Pergunta

Qual seria a maneira mais eficiente de fazer uma consulta de paginação no SQLSERVER 2000?

Onde uma "consulta de paginação" seria o equivalente a usar a instrução LIMIT no MySQL.

EDIT: Um procedimento armazenado poderia ser mais eficiente do que qualquer consulta baseada em conjunto nesse caso?

Foi útil?

Solução

Pagamento de grandes resultados E o vencedor está usando o RowCount. Também há uma versão generalizada para consultas mais complexas. Mas dê crédito a Jasmin Muharemovic :)

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

O artigo contém todo o código -fonte.

Leia as informações "Update 2004-05-05". !

Outras dicas

Eu acho um aninhado SELECT TOP n A consulta é provavelmente a maneira mais eficiente de realizá -la.

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

Substituir ThisPageRecordCount com itens por página e BeforeThisPageRecordCount com (PageNumber - 1) * items-per-page.

É claro que a melhor maneira no SQL Server 2005 é usar o ROW_NUMBER() função em um CTE.

A eficiência da consulta realmente depende de como a tabela subjacente está estruturada. Se, digamos, você tem uma chave primária chamada ID, que é uma identidade, e É um índice agrupado, e Você pode assumir que ninguém está fazendo Identity_inserts, você pode fazer uma consulta como:

Selecione XXX superior da tabela onde id> @lastPagesId;

Isso obterá os resultados o mais rápido possível. Todo o resto que será realmente eficiente é uma variante sobre isso - talvez não seja um ID - talvez o que você esteja usando na página seja realmente uma data que você sabe ser única, mas você entendeu ... o As consultas baseadas em () mostradas aqui provavelmente funcionarão, mas elas não tocarão no desempenho de uma varredura parcial de índice em cluster ou cobertura.

Eu acho que o que você realmente tem aqui é um motivo convincente para atualizar para o SQL 2005.

No SQL 2005, isso pode ser feito de maneira rápida e fácil com:

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

Se você está realmente preso ao SQL 2000, eu me preocuparia - a Microsoft não vai suportar totalmente por muito mais tempo, uma vez que agora está duas gerações atrás.

Não haverá uma melhor maneira de fazer isso, receio - todas as soluções são meio que hacks.

A resposta de @Peter Petrov é provavelmente a mais consistente, no entanto:

  • Se você estiver lidando com um índice em cluster em uma tabela menor para o seu tipo, o método ASC-DESC (construindo dinamicamente dois tipos em cada sentido usando o topo) provavelmente é mais rápido.
  • Se seus dados forem relativamente estáticos e seu tipo for corrigido, você poderá adicionar seu próprio campo rownum que você atualiza quando alterar o pedido de classificação (parece horrível, mas será rápido para tabelas grandes).

Eu acho que você está olhando para algumas horas aprimorando o analisador de consulta a cada vez. Um PROC armazenado não fará muita diferença de qualquer maneira - o cache do plano de consulta provavelmente não será o gargalo.

Este é um procedimento armazenado genérico do SQL Server 2000 que executará a paginação em qualquer tabela. O procedimento armazenado aceita o nome da tabela, as colunas para saída (padrão para todas as colunas da tabela), uma condição opcional, uma condição, uma ordem de classificação opcional, o número da página a recuperar e o número de linhas por página.

    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

Aqui estão alguns exemplos sobre como usá -lo usando o banco de dados de Northwing:

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

Para confirmar, este não é o meu trabalho, mas é cortesia dehttp://www.eggheadcafe.com/printsearchcontent.asp?linkid=1055

Saúde, John

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top