Получение итогового количества строк из OFFSET/FETCH NEXT

Итак, у меня есть функция, которая возвращает несколько записей, которые я хочу реализовать подкачки на моем сайте. Мне было предложено, чтобы я использовал Offset/Fetch Next в SQL Server 2012 для выполнения этого. На нашем веб-сайте у нас есть область, в которой указано общее количество записей и какая страница вы в это время.

Раньше я получал весь набор записей и смог запрограммировать пейджинг. Но используя метод SQL с FETCH NEXT X ROWS ONLY, мне дают только X строк, поэтому я не знаю, что такое мой общий набор записей и как рассчитать мои минимальные и максимальные страницы. Единственный способ, которым я могу это сказать, - вызвать функцию дважды и сделать счет строк на первом, а затем запустить второй с FETCH NEXT. Есть ли лучший способ, который не заставит меня выполнить запрос дважды? Я пытаюсь ускорить работу, а не замедлять ее.

Ответ 1

Вы можете использовать COUNT(*) OVER()... вот краткий пример использования sys.all_objects:

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;

SELECT 
  name, object_id, 
  overall_count = COUNT(*) OVER()
FROM sys.all_objects
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;

Однако это должно быть зарезервировано для небольших наборов данных; на больших комплектах производительность может быть ужасной. Смотрите эту статью Пола Уайта, чтобы найти лучшие альтернативы, включая поддержку индексированных представлений (что работает только в том случае, если результат не отфильтрован или вы заранее знаете предложения WHERE) и использование приемов ROW_NUMBER().

Ответ 2

Я столкнулся с некоторыми проблемами производительности, используя метод COUNT() OVER(). (Я не уверен, что это был сервер, так как потребовалось 40 секунд, чтобы вернуть 10 записей, а затем не было никаких проблем.) Этот метод работал при любых условиях без использования COUNT() OVER() и выполняет то же самое:

DECLARE 
    @PageSize INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, Name
    FROM Table
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY TempResult.Name
    OFFSET (@PageNum-1)*@PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY

Ответ 3

На основе Ответ Джеймса Моберга:

Это альтернатива с использованием Row_Number(), если у вас нет SQL-сервера 2012, и вы не можете использовать OFFSET

DECLARE 
    @PageNumEnd INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, NAME
    FROM Tabla
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)

select * 
from
(
    SELECT
     ROW_NUMBER() OVER ( ORDER BY PolizaId DESC) AS 'NumeroRenglon', 
     MaxRows, 
     ID,
     Name
    FROM TempResult, TempCount

)resultados
WHERE   NumeroRenglon >= @PageNum
    AND NumeroRenglon <= @PageNumEnd
ORDER BY NumeroRenglon