Получение подмножества записей вместе с общим количеством записей - PullRequest
6 голосов
/ 06 января 2010

Я работаю над возвращением набора записей из SQL Server 2008, чтобы выполнить нумерацию страниц. Я возвращаю только 15 записей за раз, но мне нужно иметь общее количество совпадений и подмножество записей. Я использовал два разных запроса со смешанными результатами в зависимости от того, где в большей группе мне нужно вытащить подмножество. Вот образец:

SET NOCOUNT ON;
WITH tempTable AS (
  SELECT
     FirstName
     , LastName
     , ROW_NUMBER() OVER(ORDER BY FirstName ASC) AS RowNumber 
   FROM People
   WHERE 
      Active = 1
)

SELECT 
   tempTable.*     
   , (SELECT Max(RowNumber) FROM tempTable) AS Records    
FROM tempTable     
WHERE
   RowNumber >= 1
   AND RowNumber <= 15
ORDER BY
   FirstName

Этот запрос работает действительно быстро, когда я возвращаю элементы в нижнем конце совпадений, например записи с 1 по 15. Однако, когда я начинаю возвращать записи 1000 - 1015, обработка будет идти из-под от секунды до более 15 секунд.

Поэтому я изменил запрос на следующий:

SET NOCOUNT ON;
WITH tempTable AS (
  SELECT * FROM (
     SELECT
        FirstName
        , LastName
        , ROW_NUMBER() OVER(ORDER BY FirstName ASC) AS RowNumber 
        , COUNT(*) OVER(PARTITION BY NULL) AS Records
      FROM People
      WHERE 
         Active = 1
   ) derived
   WHERE RowNumber >= 1 AND RowNumber <= 15
)

SELECT 
   tempTable.*     
FROM tempTable     
ORDER BY
   FirstName

Этот запрос запускает возврат большого числа за 2-3 секунды, но также выполняет запросы с меньшим числом через 2-3 секунды. Поскольку он выполняет подсчет для каждой из 70 000 строк, он делает каждый запрос более длинным, чем просто большие номера строк.

Так что мне нужно выяснить, как получить хороший счетчик строк, а также вернуть только подмножество элементов в любой точке набора результатов, не подвергаясь такому огромному штрафу. Я мог бы справиться с 2-3-секундным штрафом за высокие числа строк, но 15 - это слишком много, и я не желаю терпеть медленные нагрузки на первых нескольких страницах, которые просматривает человек.

ПРИМЕЧАНИЕ : я знаю, что мне не нужен CTE во втором примере, но это всего лишь простой пример. В процессе работы я делаю дальнейшие соединения с tempTable после того, как отфильтровал его до 15 нужных мне строк.

Ответы [ 2 ]

8 голосов
/ 06 января 2010

Вот что я сделал (и так же быстро, независимо от того, какие записи я возвращаю):

--Parameters include:
@pageNum int = 1,
@pageSize int = 0,



DECLARE 
    @pageStart int,
    @pageEnd int

SELECT
    @pageStart = @pageSize * @pageNum - (@pageSize - 1),
    @pageEnd = @pageSize * @pageNum;


SET NOCOUNT ON;
WITH tempTable AS (
    SELECT
        ROW_NUMBER() OVER (ORDER BY FirstName ASC) AS RowNumber,
        FirstName
        , LastName
    FROM People
    WHERE Active = 1
)

SELECT
    (SELECT COUNT(*) FROM tempTable) AS TotalRows,
    *
FROM tempTable
WHERE @pageEnd = 0
OR RowNumber BETWEEN @pageStart AND @pageEnd
ORDER BY RowNumber
0 голосов
/ 06 января 2010

Я обрабатывал ситуацию, немного похожую на эту, в прошлом, не пытаясь определить определенное количество строк, а используя план запроса, чтобы получить приблизительное количество строк, как в первом описании этой ссылки :

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=108658

Затем предполагалось доставить все запрашиваемые строки в пределах диапазона (скажем, от 900 до 915), а затем вернуть расчетное количество строк, например,

rows 900-915 of approx. 990

, что позволило избежать подсчета всех строк. Когда пользователь выходит за пределы этой точки, я просто показал

rows 1000-1015 of approx. 1015

т.е. просто взять последнюю запрошенную строку в качестве моей новой оценки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...