Я работаю над возвратом recordset от 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 во втором примере, но это - просто простой пример. В производстве я делаю дальнейшие соединения на поддающемся соблазну после того, как я отфильтровал его к этим 15 строкам, в которых я нуждаюсь.
Вот что я сделал (и это так же быстро, независимо от того, какие записи я вернул):
--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
В прошлом я справлялся с ситуацией, немного похожей на эту, не утруждая себя определённым количеством строк, а используя план запроса, чтобы дать мне примерное количество строк, немного похожее на то, что описывает первый элемент в этой ссылке:
http://www. sqlteam.com/forums/topic.asp?TOPIC_ID=108658
Затем было намерение доставить все строки, которые были запрошены в пределах диапазона (от, скажем, 900 до 915), а затем вернуть оценочное количество строк, например,
rows 900-915 of approx. 990
, что позволило избежать необходимости считать все строки. Как только пользователь выходит за пределы этой точки, я просто показываю
rows 1000-1015 of approx. 1015
, т.е. просто принимаю последний запрошенный ряд как мою новую оценку.