9 ответов:
пытается дать вам краткий ответ на ваши сомнения, если вы выполните
skip(n).take(m)методы на linq (с SQL 2005 / 2008 в качестве сервера базы данных) ваш запрос будет использоватьSelect ROW_NUMBER() Over ...заявление, с каким-то прямым подкачкой в SQL-движке.приведу вам пример, у меня есть таблица БД под названием
mtcityи я написал следующий запрос (работайте также с linq to entities):using (DataClasses1DataContext c = new DataClasses1DataContext()) { var query = (from MtCity2 c1 in c.MtCity2s select c1).Skip(3).Take(3); //Doing something with the query. }результирующий запрос будет:
SELECT [t1].[CodCity], [t1].[CodCountry], [t1].[CodRegion], [t1].[Name], [t1].[Code] FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY [t0].[CodCity], [t0].[CodCountry], [t0].[CodRegion], [t0].[Name], [t0].[Code]) AS [ROW_NUMBER], [t0].[CodCity], [t0].[CodCountry], [t0].[CodRegion], [t0].[Name], [t0].[Code] FROM [dbo].[MtCity] AS [t0] ) AS [t1] WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1 ORDER BY [t1].[ROW_NUMBER]который является оконные данные доступ (довольно круто, кстати, потому что будет возвращать данные с самого начала и будет получать доступ к таблице, пока выполняются условия). Это будет очень похоже на:
With CityEntities As ( Select ROW_NUMBER() Over (Order By CodCity) As Row, CodCity //here is only accessed by the Index as CodCity is the primary From dbo.mtcity ) Select [t0].[CodCity], [t0].[CodCountry], [t0].[CodRegion], [t0].[Name], [t0].[Code] From CityEntities c Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity Where c.Row Between @p0 + 1 AND @p0 + @p1 Order By c.Row Ascза исключением того, что этот второй запрос будет выполняться быстрее, чем результат linq, потому что он будет использовать исключительно индекс для создания окна доступа к данным; это означает, что если вам нужна некоторая фильтрация, фильтрация должна быть (или должна быть) в списке сущностей (где создается строка) и некоторые другие индексы также должны быть созданы, чтобы поддерживать хорошую производительность.
теперь, что лучше?
если у вас есть довольно солидный рабочий процесс в вашей логике, реализация правильного способа SQL будет сложной. В этом случае LINQ будет решением.
если вы можете опустить эту часть логики непосредственно в SQL (в хранимой процедуре), это будет еще лучше, потому что вы можете реализовать второй запрос, который я показал вам (используя индексы), и разрешить SQL генерировать и хранить план выполнения запроса (повышение производительности).
попробуйте использовать
FROM [TableX] ORDER BY [FieldX] OFFSET 500 ROWS FETCH NEXT 100 ROWS ONLYчтобы получить строки от 501 до 600 В SQL server, не загружая их в память. Обратите внимание, что этот синтаксис стал доступен с помощью SQL Server 2012 только
в то время как LINQ-to-SQL будет генерировать
OFFSETпредложение (возможно, эмулируется с помощьюROW_NUMBER() OVER()как уже говорили другие), есть совершенно другой, гораздо более быстрый способ выполнения подкачки в SQL. Это часто называют "методом поиска", как описано в это сообщение в блоге здесь.SELECT TOP 10 first_name, last_name, score FROM players WHERE (score < @previousScore) OR (score = @previousScore AND player_id < @previousPlayerId) ORDER BY score DESC, player_id DESCThe
@previousScoreи@previousPlayerIdзначения-это соответствующие значения последней записи с предыдущей страницы. Это позволяет получить" следующую " страницу. ЕслиORDER BYнаправление - этоASC, просто использовать>вместо.С помощью вышеуказанного метода вы не можете сразу перейти на страницу 4, не получив предварительно предыдущие 40 записей. Но часто, вы не хотите прыгать так далеко в любом случае. Вместо этого вы получаете гораздо более быстрый запрос, который может быть способен извлекать данные в постоянное время, в зависимости от вашего индексирования. Кроме того, ваши страницы остаются "стабильными", независимо от того, изменяются ли базовые данные (например, на странице 1, пока вы находитесь на странице 4).
это лучший способ реализовать подкачку при ленивой загрузке большего количества данных в веб-приложениях, например.
обратите внимание, что "метод поиска" также называется набор ключей подкачки.
LinqToSql автоматически преобразует a .Пропустить(Н1).Возьмите (N2) в синтаксис TSQL для вас. Фактически, каждый "запрос", который вы делаете в Linq, на самом деле просто создает SQL-запрос для вас в фоновом режиме. Чтобы проверить это, просто запустите SQL Profiler во время работы приложения.
методология skip / take работала очень хорошо для меня и других из того, что я читал.
из любопытства, какой тип самостоятельной подкачки запроса у вас есть, что вы считаете более эффективным, чем В LINQ пропустить/забрать?
мы используем CTE, завернутый в динамический SQL (потому что наше приложение требует динамической сортировки данных на стороне сервера) в хранимой процедуре. Я могу привести простой пример, если вы хотите.
У меня не было возможности посмотреть на T/SQL, который производит LINQ. Может кто-то образец?
мы не используем LINQ или прямой доступ к таблицам, поскольку нам требуется дополнительный уровень безопасности (при условии, что динамический SQL несколько нарушает это).
что-то вроде этого следует сделать трюк. Вы можете добавить параметризованные значения для параметров и т. д.
exec sp_executesql 'WITH MyCTE AS ( SELECT TOP (10) ROW_NUMBER () OVER ' + @SortingColumn + ' as RowID, Col1, Col2 FROM MyTable WHERE Col4 = ''Something'' ) SELECT * FROM MyCTE WHERE RowID BETWEEN 10 and 20'
в SQL Server 2008:
DECLARE @PAGE INTEGER = 2 DECLARE @TAKE INTEGER = 50 SELECT [t1].* FROM ( SELECT ROW_NUMBER() OVER (ORDER BY [t0].[COLUMNORDER] DESC) AS [ROW_NUMBER], [t0].* FROM [dbo].[TABLA] AS [t0] WHERE ([t0].[COLUMNS_CONDITIONS] = 1) ) AS [t1] WHERE [t1].[ROW_NUMBER] BETWEEN ((@PAGE*@TAKE) - (@TAKE-1)) AND (@PAGE*@TAKE) ORDER BY [t1].[ROW_NUMBER]в t0 находятся все записи В t1 находятся только те, которые соответствуют этой странице
вы можете дополнительно улучшить производительность, чех это
From CityEntities c Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity Where c.Row Between @p0 + 1 AND @p0 + @p1 Order By c.Row AscЕсли вы будете использовать от Таким образом, это даст лучший результат:
From dbo.MtCity t0 Inner Join CityEntities c on c.CodCity = t0.CodCityпричина: потому что вы используете класс where в таблице CityEntities, который устранит многие записи перед присоединением к MtCity, поэтому 100% уверен, что это увеличит производительность во много раз...
в любом случае ответ родригоэлпа действительно полезен.
спасибо
вы можете реализовать подкачку таким простым способом, передав PageIndex
Declare @PageIndex INT = 1 Declare @PageSize INT = 20 Select ROW_NUMBER() OVER ( ORDER BY Products.Name ASC ) AS RowNumber, Products.ID, Products.Name into #Result From Products SELECT @RecordCount = COUNT(*) FROM #Results SELECT * FROM #Results WHERE RowNumber BETWEEN (@PageIndex -1) * @PageSize + 1 AND (((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1
в 2008 году мы не можем использовать Skip ().Возьмите ()
путь:
var MinPageRank = (PageNumber - 1) * NumInPage + 1 var MaxPageRank = PageNumber * NumInPage var visit = Visita.FromSql($"SELECT * FROM (SELECT [RANK] = ROW_NUMBER() OVER (ORDER BY Hora DESC),* FROM Visita WHERE ) A WHERE A.[RANK] BETWEEN {MinPageRank} AND {MaxPageRank}").ToList();
Comments