Вопрос

Какой был бы наиболее эффективный способ выполнить запрос подкачки в SQLServer 2000?

Где "запрос подкачки" был бы эквивалентом использования оператора LIMIT в MySQL.

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

Это было полезно?

Решение

Подкачка больших наборов результатов и победитель использует RowCount.Также существует обобщенная версия для более сложных запросов.Но отдайте должное Жасмин Мухаремович :)

DECLARE @Sort /* the type of the sorting column */
SET ROWCOUNT @StartRow
SELECT @Sort = SortColumn FROM Table ORDER BY SortColumn
SET ROWCOUNT @PageSize
SELECT ... FROM Table WHERE SortColumn >= @Sort ORDER BY SortColumn

Статья содержит весь исходный код.

Пожалуйста, ознакомьтесь с информацией "Обновление 2004-05-05".!

Другие советы

Я думаю, что вложенный SELECT TOP n запрос, вероятно, является наиболее эффективным способом достижения этой цели.

SELECT TOP ThisPageRecordCount *
FROM Table
WHERE ID NOT IN (SELECT TOP BeforeThisPageRecordCount ID FROM Table ORDER BY OrderingColumn)
ORDER BY OrderingColumn

Заменить ThisPageRecordCount с элементами на странице и BeforeThisPageRecordCount с (PageNumber - 1) * items-per-page.

Конечно, лучший способ в SQL Server 2005 - это использовать ROW_NUMBER() функция в CTE.

Эффективность запроса действительно зависит от того, как структурирована базовая таблица.Если, допустим, у вас есть первичный ключ под названием ID, который является идентификатором, и это кластеризованный индекс, и вы можете предположить, что никто не выполнял IDENTITY_INSERTs для этого, вы можете выполнить запрос типа:

ВЫБЕРИТЕ TOP XXX ИЗ таблицы, ГДЕ ID > @LastPagesID;

Это позволит вам получить результаты как можно быстрее.Все остальное, что будет действительно эффективным, - это какой-то вариант этого - возможно, это не идентификатор - возможно, то, что вы используете для страницы, на самом деле является датой, которая, как вы знаете, уникальна, но вы поняли суть...Показанные здесь запросы на основе IN (), вероятно, будут работать, но они не повлияют на производительность частичного кластеризованного или охватывающего индексного сканирования.

Я думаю, что то, что у вас действительно есть здесь, - это веская причина для обновления до SQL 2005.

В SQL 2005 это можно сделать быстро и легко с помощью:

select ROW_NUMBER() over (order by [MyField]) as rowNum, *
from [MyTable]
where rowNum between @firstRow and @lastRow

Если вы действительно застряли с SQL 2000, я бы беспокоился - Microsoft не собирается полностью поддерживать его намного дольше, учитывая, что прошло уже два поколения назад.

Боюсь, что не будет ни одного лучшего способа сделать это - все решения являются своего рода взломами.

Однако ответ @Petar Petrov, вероятно, наиболее последовательный:

  • Если вы имеете дело с кластеризованным индексом в таблице меньшего размера для вашей сортировки, то метод ASC-DESC (динамическое построение двух сортировок каждым способом с использованием TOP), вероятно, быстрее.
  • Если ваши данные относительно статичны и ваша сортировка фиксирована, вы можете добавить свое собственное поле rowNum, которое вы обновляете при изменении порядка сортировки (звучит ужасно, но для больших таблиц это будет быстро).

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

Это общая хранимая процедура SQL Server 2000, которая будет выполнять разбивку на страницы в любой таблице.Хранимая процедура принимает имя таблицы, столбцы для вывода (по умолчанию используются все столбцы в таблице), необязательное условие WHERE, необязательный порядок сортировки, номер страницы для извлечения и количество строк на странице.

    CREATE PROCEDURE [dbo].[GetPage]
    @pTableName VARCHAR(30),
    @pColumns VARCHAR(200) = '*',
    @pFilter VARCHAR(200) = '',
    @pSort VARCHAR(200) = '',
    @pPage INT = 1,
    @pPageRows INT = 10
    AS

    SET NOCOUNT ON
    DECLARE @vSQL VARCHAR(4000)
    DECLARE @vTempTable VARCHAR(30)
    DECLARE @vRowStart INT
    DECLARE @vTotalRows INT

    SET @vTempTable = '##Tmp' + CAST(DATEPART(YYYY, GETDATE()) AS VARCHAR(4)) +
    CAST(DATEPART(MM, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(DD, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(HH, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(MI, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(SS, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(MS, GETDATE()) AS VARCHAR(3))

    SET @vSQL = 'SELECT ' + @pColumns + ', IDENTITY(INT, 1, 1) AS ROWID INTO ' + @vTempTable + ' FROM ' + @pTableName

    IF @pFilter != '' AND @pFilter IS NOT NULL
    SET @vSQL = @vSQL + ' WHERE ' + @pFilter

    IF @pSort != '' AND @pSort IS NOT NULL
    SET @vSQL = @vSQL + ' ORDER BY ' + @pSort

    EXECUTE (@vSQL)

    -- Get the total number of rows selected
    SET @vTotalRows = @@ROWCOUNT

    -- If page number = 0, set it to the first page
    IF @pPage = 0
    SET @pPage = 1

    -- If page number is beyond the last page, set page to the last page
    IF (@pPage * @pPageRows) > @vTotalRows
    BEGIN
    SET @pPage = @vTotalRows / @pPageRows
    IF (@vTotalRows % @pPageRows) != 0
    SET @pPage = @pPage + 1
    END

    SET @vRowStart = ((@pPage - 1) * @pPageRows) + 1
    SET @vSQL = 'SELECT * FROM ' + @vTempTable + ' WHERE ROWID BETWEEN ' + CAST(@vRowStart AS VARCHAR(10)) +
    ' AND ' + CAST((@vRowStart + @pPageRows - 1) AS VARCHAR(10)) + ' ORDER BY ROWID'
    EXECUTE (@vSQL)

    SET @vSQL = 'DROP TABLE ' + @vTempTable
    EXECUTE (@vSQL)

GO

Вот несколько примеров того, как использовать его, используя базу данных Northwing:

EXECUTE [dbo].[GetPage] 'Customers', '*', '', '', 1, 10
EXECUTE [dbo].[GetPage] 'Customers', '*', '', 'CustomerID DESC', 1, 10

Чтобы подтвердить, это не моя работа, но любезно предоставленная http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=1055

Твое здоровье, Джон

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top