2009-02-02 9 views
9

¿Cuál sería la forma más eficiente de hacer una consulta de búsqueda en SQLServer 2000?¿Búsqueda eficiente de paginación (límite) en SQLServer 2000?

Donde una "consulta de paginación" sería el equivalente a usar la instrucción LIMIT en MySQL.

EDITAR: ¿Podría un procedimiento almacenado ser más eficiente que cualquier consulta basada en conjunto en ese caso?

Respuesta

11

Paging of Large Resultsets y el ganador usa RowCount. También hay una versión generalizada para consultas más complejas. Pero dar 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 

El artículo contiene todo el código fuente.

Lea la información "Actualización 2004-05-05". !

+3

Esto supone que val ues en la columna de clasificación son únicos. Si tiene datos que se repiten en su columna de clasificación, esta consulta podría no funcionar correctamente. Digamos que su consulta está revisando los salarios y usted tiene 35 personas que ganan $ 40K, 40 que ganan $ 50K y 20 que ganan $ 60K. Si utiliza esta solución con tamaños de página de 20, su segunda "página" aquí comenzaría en la fila 36, ​​no en la 21 como se esperaba. – OneCleverMonkey

6

Creo que una consulta anidada SELECT TOP n es probablemente la forma más eficiente de lograrlo.

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

Reemplazar ThisPageRecordCount con los objetos por página y BeforeThisPageRecordCount con (PageNumber - 1) * items-per-page.

Por supuesto, la mejor manera en SQL Server 2005 es usar la función ROW_NUMBER() en un CTE.

+0

Por cierto, * necesita * utilizar SQL dinámico ya que en 2000, las variables y expresiones no están soportadas en la cláusula 'top' –

1

La eficacia de la consulta realmente depende de cómo está estructurada la tabla subyacente. Si, digamos que tiene una clave principal llamado ID que es una identidad, y es un índice agrupado, y se puede asumir que nadie ha estado haciendo IDENTITY_INSERTs en él, se puede hacer una consulta como:

SELECT TOP XXX FROM tabla WHERE ID> @ LastPagesID;

Eso le dará resultados lo más rápido posible. Todo lo demás que va a ser realmente eficiente es una variante de esto, tal vez no sea una identificación, tal vez lo que estás usando para la página es en realidad una fecha que sabes que es única, pero entiendes el punto ... Es probable que las consultas basadas en IN() que se muestran aquí funcionen, pero no afectarán el rendimiento de un escaneo de índice agrupado o agrupado parcial.

0

Creo que lo que realmente tenemos aquí es una razón de peso para actualizar a SQL 2005.

En SQL 2005 esto se puede hacer rápida y fácilmente con:

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

Si estás realmente atascado con SQL 2000 me preocuparía: Microsoft no lo soportará por mucho más tiempo dado que ahora está a dos generaciones atrás.

No hay una mejor manera de hacerlo, me temo, todas las soluciones son un poco hacks.

respuesta de @Petar Petrov es probablemente el más consistente, sin embargo:

  • Si usted está tratando con un índice agrupado en una mesa más pequeña para su especie, entonces el método de ASC-DESC (construcción de dos clases dinámicamente cada uno manera de usar TOP) es probablemente más rápido.
  • Si sus datos son relativamente estáticos y su clasificación es fija, puede agregar su propio campo rowNum que actualice cuando cambie el orden de clasificación (suena horrible pero será rápido para tablas grandes).

creo que usted está buscando en unas pocas horas que se ajuste con el analizador de consulta cada vez. Un proceso almacenado no supondrá mucha diferencia: el almacenamiento en caché del plan de consulta probablemente no sea el cuello de botella.

0

Este es un procedimiento almacenado genérico de SQL Server 2000 que realizará la paginación en cualquier tabla. El procedimiento almacenado acepta el nombre de la tabla, las columnas a mostrar (por defecto a todas las columnas en la tabla), una condición WHERE opcional, un orden de clasificación opcional, el número de página a recuperar y el número de filas 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 

He aquí algunos ejemplos de cómo usarlo usando la base de datos Northwing:

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

Para confirmar, este no es mi trabajo, pero es cortesía de http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=1055

Cheers, John

Cuestiones relacionadas