Как пейджинг работает с ROW_NUMBER в SQL Server?

13

У меня есть Employeeтаблица с одним миллионом записей. У меня есть следующий SQL для подкачки данных в веб-приложении. Работает нормально. Однако, что я вижу как проблему - производная таблица tblEmployeeвыбирает все записи в Employeeтаблице (для создания MyRowNumberзначений).

Я думаю, что это вызывает выбор всех записей в Employeeтаблице.

Это действительно так работает? Или SQL Server оптимизирован для выбора только 5 записей из исходной Employeeтаблицы?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 
LCJ
источник
3
См. Sqlservercentral.com/articles/T-SQL/66030 и, что более важно, последующее обсуждение .
Аарон Бертран

Ответы:

17

Альтернативой тестированию может быть:

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

Да, вы дважды попали в таблицу, но в CTE, где вы сканируете всю таблицу, вы берете только ключ, а не ВСЕ данные. Но вы действительно должны посмотреть на эту статью:

http://www.sqlservercentral.com/articles/T-SQL/66030/

И последующее обсуждение:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

В SQL Server 2012, конечно , вы можете использовать новый OFFSET/ FETCH NEXTсинтаксис:

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 
Аарон Бертран
источник
Следует отметить, что OFFSET / FETCH NEXT не дают никаких преимуществ в производительности по сравнению с методом CTE
Akash
2
@ Акаш, ты тщательно проверил это? Я наблюдал некоторые различия в плане, но ничего не упомянул о производительности, потому что я не проводил всестороннего тестирования. Даже если производительность одинакова, синтаксис немного менее громоздок. Я сделал блог об этом здесь: sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/…
Аарон Бертран
1
Ах, вы правы, разница в производительности. Я читал это: blogs.technet.com/b/dataplatforminsider/archive/2011/11/01/… где он не упоминает никакой разницы, но только что увидел channel9.msdn.com/posts/SQL11UPD03-REC-02, где он показывает theres большая разница .. (хотя в аудио недооценивают разницу в производительности)
Akash
2

Хотя вы можете не знать механизм, стоящий за ним, вы можете проверить это самостоятельно, сравнив производительность вашего запроса с: select * from Employee.

Более поздние версии SQL Server довольно хорошо оптимизируют работу, но это может зависеть от нескольких факторов.

Работа вашей функции ROW_NUMBER будет зависеть от предложения Order By. В вашем примере большинство предположит, что EmpID является первичным ключом.

В некоторых случаях такие предложения, которые являются настолько сложными и / или плохо закодированными или проиндексированными, вам может быть лучше просто вернуть весь набор данных (это редко и может быть исправлено). Использование МЕЖДУ имеет проблемы.

Прежде чем предполагать, что было бы лучше вернуть все строки в ваше приложение и дать ему понять, вам следует поработать над оптимизацией запроса. Проверьте оценки. Спросите анализатор запросов. Проверьте некоторые альтернативы.

JeffO
источник
2

Я знаю, что вопрос касается row_number (), но я хочу добавить одну новую функцию sql server 2012. В sql server 2012 появилась новая функция OFFSET Fetch, и она очень быстрая, чем row_number (). Я использовал это, и это дает мне хороший результат, надеюсь, что вы, ребята, тоже воспользуетесь этим.

Я нашел один пример на http://blogfornet.com/2013/06/sql-server-2012-offset-use/

что полезно. Надеюсь, это поможет вам и для реализации новых функций ....

Сэм Радж
источник
-2

Я не думаю, что он возвращает все строки в исходной таблице. SQL сервер оптимизирует. В противном случае для выбора миллиона записей потребуется огромное количество времени. В настоящее время я использую это, и это намного быстрее, чем выбор всех строк. Так что, конечно, не получить все строки. Однако это медленнее, чем просто выборка первых пяти строк, вероятно, из-за времени, затраченного на упорядочение

user3688672
источник
-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId
Агнель Амодия
источник
4
Не могли бы вы расширить свой ответ? Вопрос касался того, как подкачка работает внутри SQL Server - то есть, что делает ядро ​​базы данных для выполнения запроса. К сожалению, на данный момент ваш ответ не решает актуальную проблему.
Мистер Браунстоун