SQL Server 2008 методы подкачки? - PullRequest
       4

SQL Server 2008 методы подкачки?

10 голосов
/ 05 декабря 2010

Мне приходится работать с потенциально большим списком записей, и я гуглю в поисках способов избежать выбора всего списка, вместо этого я хочу позволить пользователям выбирать страницу (например, от 1 до 10) и отображать записи соответствующим образом..

Скажем, для 1000 записей у меня будет 100 страниц по 10 записей каждая, и сначала будут отображаться 10 последних записей, а затем, если пользователь нажмет на страницу 5, будут показаны записи от 41 до 50.

Это хорошая идея, чтобы добавить номер строки к каждой записи, а затем запросить на основе номера строки?Есть ли лучший способ достичь результата подкачки без лишних затрат?Пока что описанные здесь методы выглядят наиболее перспективными:

http://developer.berlios.de/docman/display_doc.php?docid=739&group_id=2899

http://www.codeproject.com/KB/aspnet/PagingLarge.aspx

Ответы [ 7 ]

15 голосов
/ 05 декабря 2010

Следующая хранимая процедура T-SQL представляет собой очень эффективную реализацию подкачки.Оптимизатор SQL может быстро найти первый идентификатор.Комбинируйте это с использованием ROWCOUNT, и у вас есть подход, который эффективен с точки зрения использования процессора и чтения.Для таблицы с большим количеством строк она, безусловно, превосходит любой подход, который я видел, используя временную таблицу или переменную таблицы.

Примечание: в этом примере я использую столбец последовательной идентификации, ноКод работает на любом столбце, подходящем для сортировки страниц.Кроме того, разрывы последовательности в используемом столбце не влияют на результат, так как код выбирает количество строк, а не значение столбца.

РЕДАКТИРОВАТЬ: если вы сортируете столбец с потенциально не уникальнымзначений (например, LastName), затем добавьте второй столбец в предложение Order By, чтобы снова сделать значения сортировки уникальными.

CREATE  PROCEDURE dbo.PagingTest
(
    @PageNumber int,
    @PageSize int
)
AS

DECLARE @FirstId int, @FirstRow int

SET @FirstRow = ( (@PageNumber - 1) * @PageSize ) + 1
SET ROWCOUNT @FirstRow

-- Add check here to ensure that @FirstRow is not
-- greater than the number of rows in the table.

SELECT   @FirstId = [Id]
FROM     dbo.TestTable
ORDER BY [Id]

SET ROWCOUNT @PageSize

SELECT   *
FROM     dbo.TestTable
WHERE    [Id] >= @FirstId
ORDER BY [Id]

SET ROWCOUNT 0
GO 
7 голосов
/ 05 декабря 2010

Если вы используете CTE с двумя столбцами row_number () - один отсортированный asc, один desc, вы получите номера строк для подкачки, а также итоговые записи, добавив два столбца row_number.

create procedure get_pages(@page_number int, @page_length int)
as
    set nocount on;

    with cte as
    (
        select 
            Row_Number() over (order by sort_column desc) as row_num
            ,Row_Number() over (order by sort_column) as inverse_row_num
            ,id as cte_id
        From my_table
    )
    Select 
        row_num+inverse_row_num as total_rows
        ,*  
    from CTE inner join my_table
        on cte_id=df_messages.id
    where row_num between 
        (@page_number)*@page_length 
        and (@page_number+1)*@page_length
    order by rownumber
5 голосов
/ 26 октября 2013

Использование OFFSET

Другие объясняли, как можно использовать функцию ранжирования ROW_NUMBER() OVER() для просмотра страниц.Стоит отметить, что SQL Server 2012 наконец-то включил поддержку стандарта SQL OFFSET .. FETCH предложение:

SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY

Если вы используете SQL Server 2012 и обратная совместимость не является проблемойвам, вероятно, следует предпочесть это предложение, поскольку оно будет более оптимально выполняться SQL Server в угловых случаях.

Использование метода SEEK

Существует совершенно другой, гораздо более быстрый способ выполнения подкачки в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 DESC

Значения @previousScore и @previousPlayerId являются соответствующими значениями последней записи изпредыдущая страницаЭто позволяет вам получить «следующую» страницу.Если направление ORDER BY равно ASC, просто используйте вместо него >.

С помощью описанного выше метода вы не можете сразу перейти к странице 4, предварительно не получив 40 предыдущих записей.Но часто, вы все равно не хотите прыгать так далеко.Вместо этого вы получаете гораздо более быстрый запрос, который может извлекать данные в постоянное время, в зависимости от вашей индексации.Кроме того, ваши страницы остаются «стабильными», независимо от того, изменяются ли базовые данные (например, на странице 1, пока вы находитесь на странице 4).

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

Обратите внимание, что "метод поиска" также называется подкачки с клавиатуры .

4 голосов
/ 05 декабря 2010

Попробуйте что-то вроде этого:

declare @page int = 2
declare @size int = 10

declare @lower int =  (@page - 1) * @size
declare @upper int =  (@page    ) * @size

select * from (
select 
    ROW_NUMBER() over (order by some_column) lfd,
* from your_table
) as t
 where lfd between @lower and @upper
 order by some_column
3 голосов
/ 04 августа 2013

Вот обновленная версия кода @ RoadWarrior с использованием TOP. Производительность идентична, и очень быстро. Убедитесь, что у вас есть индекс TestTable.ID

CREATE PROC dbo.PagingTest
    @SkipRows int,
    @GetRows int
AS
DECLARE @FirstId int

SELECT   TOP (@SkipRows) 
         @FirstId = [Id]
FROM     dbo.TestTable
ORDER BY [Id]

SELECT   TOP (@GetRows) *
FROM     dbo.TestTable
WHERE    [Id] >= @FirstId
ORDER BY [Id]

GO 
0 голосов
/ 23 августа 2015

Почему бы не использовать рекомендуемое решение :

ВЫБРАТЬ ЗНАЧЕНИЕ продукта ИЗ AdventureWorksEntities.Products AS продукт упорядочить по продукту.ListPrice SKIP @skip LIMIT @ limit

0 голосов
/ 25 марта 2013

Попробуйте это

Declare @RowStart int, @RowEnd int;


SET @RowStart = 4;
SET @RowEnd = 7; 

With MessageEntities As 
(
    Select ROW_NUMBER() Over (Order By [MESSAGE_ID]) As Row, [MESSAGE_ID]
    From [TBL_NAFETHAH_MESSAGES]
)
Select  m0.MESSAGE_ID, m0.MESSAGE_SENDER_NAME,
        m0.MESSAGE_SUBJECT, m0.MESSAGE_TEXT
From MessageEntities M
    Inner Join [TBL_NAFETHAH_MESSAGES] m0 on M.MESSAGE_ID = m0.MESSAGE_ID
Where M.Row Between @RowStart AND @RowEnd
Order By M.Row Asc
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...