Следует ли мне использовать LINQ Skip()
иTake()
метод для разбиения на страницы или реализовать собственное разбиение на страницы с помощью SQL-запроса?
Что наиболее эффективно? Почему я должен предпочесть одно другому?
Я использую SQL Server 2008, ASP.NET MVC и LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Каменное сердце
источник
источник
Ответы:
Пытаясь дать вам краткий ответ на ваши сомнения, если вы выполните
skip(n).take(m)
методы на linq (с SQL 2005/2008 в качестве сервера базы данных), ваш запрос будет использоватьSelect ROW_NUMBER() Over ...
оператор с каким-то прямым разбиением на страницы в механизме SQL.Приведу пример: у меня есть таблица db с именем,
mtcity
и я написал следующий запрос (работает также с linq to entity):В результате будет получен следующий запрос:
Это оконный доступ к данным (довольно круто, кстати, cuz будет возвращать данные с самого начала и будет обращаться к таблице, пока выполняются условия). Это будет очень похоже на:
За исключением того, что этот второй запрос будет выполняться быстрее, чем результат linq, потому что он будет использовать исключительно индекс для создания окна доступа к данным; это означает, что если вам нужна какая-то фильтрация, фильтрация должна быть (или должна быть) в списке сущностей (где создается строка), а также должны быть созданы некоторые индексы для поддержания хорошей производительности.
Что лучше?
Если в вашей логике есть достаточно надежный рабочий процесс, реализация правильного способа SQL будет сложной. В этом случае решением будет LINQ.
Если вы можете понизить эту часть логики непосредственно до SQL (в хранимой процедуре), это будет еще лучше, потому что вы сможете реализовать второй запрос, который я вам показал (с использованием индексов), и позволить SQL генерировать и сохранять план выполнения для запрос (повышение производительности).
источник
Попробуйте использовать
чтобы получить строки от 501 до 600 на сервере SQL, не загружая их в память. Обратите внимание , что этот синтаксис стал доступен с SQL Server 2012 только
источник
Хотя LINQ-to-SQL будет генерировать
OFFSET
предложение (возможно, эмулируемое с использованием,ROW_NUMBER() OVER()
как упоминалось другими ), существует совершенно другой, гораздо более быстрый способ выполнить разбиение на страницы в SQL. Это часто называют «методом поиска», как описано в этом сообщении в блоге здесь .Значения
@previousScore
и@previousPlayerId
являются соответствующими значениями последней записи с предыдущей страницы. Это позволяет вам перейти на «следующую» страницу. ЕслиORDER BY
направление естьASC
, просто используйте>
вместо него.С помощью описанного выше метода вы не можете сразу перейти к странице 4, не загрузив сначала предыдущие 40 записей. Но часто вы все равно не хотите прыгать так далеко. Вместо этого вы получаете гораздо более быстрый запрос, который может извлекать данные за постоянное время, в зависимости от вашей индексации. Кроме того, ваши страницы остаются «стабильными» независимо от того, изменяются ли базовые данные (например, на странице 1, пока вы находитесь на странице 4).
Это лучший способ реализовать разбиение на страницы, например, при отложенной загрузке большего количества данных в веб-приложения.
Обратите внимание, что «метод поиска» также называется пейджингом набора клавиш .
источник
LinqToSql автоматически конвертирует .Skip (N1) .Take (N2) в синтаксис TSQL за вас. Фактически, каждый «запрос», который вы делаете в Linq, на самом деле просто создает для вас SQL-запрос в фоновом режиме. Чтобы проверить это, просто запустите SQL Profiler во время работы вашего приложения.
Из того, что я читал, методика пропуска / приема очень хорошо сработала для меня и других.
Из любопытства, какой у вас тип запроса на самостоятельную подкачку, который, по вашему мнению, более эффективен, чем пропуск / дубль Linq?
источник
Мы используем CTE, завернутый в Dynamic SQL (поскольку наше приложение требует динамической сортировки на стороне сервера данных) внутри хранимой процедуры. Если хотите, я могу привести простой пример.
У меня не было возможности взглянуть на T / SQL, который производит LINQ. Может кто-нибудь выложить образец?
Мы не используем LINQ или прямой доступ к таблицам, поскольку нам требуется дополнительный уровень безопасности (при условии, что динамический SQL несколько нарушает это).
Что-то вроде этого должно помочь. Вы можете добавить параметризованные значения для параметров и т. Д.
источник
sp_executesql
Вас есть возможность передавать параметры в безопасном режиме, например:EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Безопасность в этом контексте означает, что она устойчива к SQL-инъекциям - вы можете передать все возможные значения внутри переменной@ValueForCol4
- даже'--'
, и запрос все равно будет работать!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
эмуляция смещения. См. Также: 4guysfromrolla.com/webtech/042606-1.shtmlВ SQL Server 2008:
В t0 находятся все записи, в t1 - только те, которые соответствуют этой странице
источник
Подход, который я предлагаю, - это самая быстрая разбивка на страницы, которую может достичь SQL-сервер. Я проверил это на 5 миллионах записей. Этот подход намного лучше, чем "СМЕЩЕНИЕ 10 СТРОК ВЫБРАТЬ СЛЕДУЮЩИЕ 10 СТРОК ТОЛЬКО", предоставляемый SQL Server.
источник
вы можете еще больше улучшить производительность, проверьте это
если вы будете использовать from таким образом, это даст лучший результат:
причина: потому что вы используете класс where в таблице CityEntities, который удалит многие записи перед присоединением к MtCity, поэтому на 100% уверен, что это многократно увеличит производительность ...
В любом случае ответ Родригоэлпа действительно полезен.
Спасибо
источник
@p0
и конкретнее@p1
взялсяВы можете реализовать разбиение на страницы таким простым способом, передав PageIndex
источник
В 2008 году мы не можем использовать Skip (). Take ()
Путь такой:
источник