Consulta de paginação eficiente (limite) no SQLSERVER 2000?
-
20-08-2019 - |
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?
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