2010-02-06 22 views
8

Escribí el siguiente código, funciona bien, pero lleva 3 segundos completar si la tabla contiene un millón de registros. ¿Hay alguna manera de optimizar el siguiente código?T-sql: cómo realizar una paginación optimizada?

DBCC DROPCLEANBUFFERS; 
DBCC FREEPROCCACHE; 

DECLARE @Page_Size int; 
DECLARE @Page_Number int; 
DECLARE @Lower_Bound int; 
DECLARE @Upper_Bound int; 

SET @Page_Size = 30; 
SET @Page_Number = 30000; 
SET @Lower_Bound = (@Page_Number - 1) * @Page_Size; 
--SET @Upper_Bound = @Page_Number * @Page_Size; 


WITH Customers AS--(Row_Numbr, Record_Id, First_Name, 
     Middle_Name, Last_Name, Email, Telephone) AS 
(

    SELECT ROW_NUMBER() 
     OVER 
     (ORDER BY Account.Customer.Record_Id) AS Row_Numbr, * 
    FROM Account.Customer 
) 

SELECT top(@Page_Size) * 
FROM Customers 
WHERE Row_Numbr > @Lower_Bound-- 
    AND Row_Numbr <= @Upper_Bound -- This is suppose to be faster 
--SELECT * FROM Customers 
--WHERE Row_Numbr > @Lower_Bound 
-- AND Row_Numbr <= @Upper_Bound 
+0

¿qué dice el plan de ejecución? – super9

+0

¿Qué índices tienes? ¿Puedes publicar el script de crear tabla? –

+0

Relacionado: http://stackoverflow.com/questions/1897436/row-number-over-not-fast-enough-with-large-result-set-any-good-solution –

Respuesta

14

En primer lugar, ¿por qué DBCC DROPCLEANBUFFERS;? Este es un reinicio frío intenso del grupo de búferes. A menos que quiera medir y ajustar el rendimiento IO de su disco duro, a nadie le importa el rendimiento de un caché frío. Esto es no cómo funcionará su sistema. El almacenamiento en memoria caché de páginas en el grupo de búferes es el aspecto de rendimiento más crítico de en las bases de datos, y usted lo elimina. Es como aparecer en un Ferrari sin el motor y preguntar por qué es tan lento. Para mediciones de rendimiento debe hacer exactamente el opuesto a: ejecute la consulta 4-5 veces para calentar el caché, luego mida.

En segundo lugar, ¿cuál es la estructura de su mesa? ¿Es la tabla Account.Customer índice de clúster de tabla ordenar por Record_id? Si no, nunca obtendrás el rendimiento que deseas, no importa cómo expreses tu T-SQL.

Y por último pero no menos importante, ¿qué sistema tiene? ¿Tiene suficiente memoria RAM para almacenar en caché toda la base de datos en la memoria? Si no, compra más RAM. ¿Existen otros procesos que compitan por la memoria, como IIS/Asp? En caso afirmativo, expúlselos a su propio servidor, debe n ever ever run the database on the same host as the web server si el rendimiento es importante.

Para una rápida localización alternativa de considerar soluciones impulsadas conjunto de claves:

solución
/* moving up */ 
SELECT top(@Page_Size) * 
FROM Account.Customer 
WHERE Record_Id > @lastPageRecordId 
ORDER BY Record_Id; 

/* moving down */ 
SELECT top(@Page_Size) * 
FROM Account.Customer 
WHERE Record_Id < @firstPageRecordId 
ORDER BY Record_Id DESC; 

Un conjunto de claves impulsado puede solicitar directamente a la última posición y luego oscilar escanea la página siguiente/anterior, utilizando la posición clave del índice agrupado. La lógica de búsqueda (estado) debe recordar las últimas y primeras teclas de la página que se muestra para continuar desde allí, en lugar de recordar el número de página.

Las soluciones basadas en Rowcount (así como LIMIT en MySQL) son menos eficientes que las basadas en conjuntos de claves porque siempre deben contar los registros para posicionarse, en lugar de buscar directamente la posición como lo hacen los conjuntos de claves.

+0

Pero el Record_Id puede ser 1, 3, 7, 10, 11, 12, 13, 17. Las páginas no serán iguales, también la última página probablemente no cubra toda la tabla. En este caso, ¿cómo obtener la precisión @lastPageRecordId? Ahora que lo tengo quiere mejorar el rendimiento utilizando el índice Record_Id, por lo que quiere que modifique la cláusula WITH y use Record_Id en lugar de Row_Number, ¡aún no estoy seguro de cómo modificar la cláusula WITH! ¿Te estoy siguiendo? – Costa

+1

Supongamos que quiere mostrar páginas de 3. La primera vez dice TOP (3) ... ORDER BY RecordId y obtiene 1,3,7. Para la página siguiente, solicite TOP (3).DONDE RecordId> 7 ... ORDEN POR ... y obtienen 10,11,12. Para bajar pides TOP (3) ... WHERE RecordId <10 ... ORDEN POR ... DESC y vuelves a obtener 7,3,1. Para ir a continuación, solicite TOP (3) ... WHERE RecordId> 12 ... PEDIDO POR ... y obtendrá 13,17. Utiliza el primer y último RecordId en la página como * claves *, no como rangos. –

+0

@Remus Hola, ¿la solución de conjunto de claves es más rápida que la paginación? Intenté crear un procedimiento almacenado almacenado basado en el código de arriba pero no obtuve resultados. ¿Algunas ideas? Crear Proc PagingSample \t ((at) int PAGE_SIZE, \t (a) firstPageRecordId int) AS comienzan \t SELECT superior ((at) PAGE_SIZE) * \t DE dbo.data \t DONDE (a) (at) IDENTITY <(at) firstPageRecordId \t ORDER BY DateTime DESC; final –

2

que utiliza este procedimiento almacenado:

CREATE PROCEDURE sp_PagedItems 
    (
    @Page int, 
    @RecsPerPage int 
    ) 
AS 

-- We don't want to return the # of rows inserted 
-- into our temporary table, so turn NOCOUNT ON 
SET NOCOUNT ON 


--Create a temporary table 
CREATE TABLE #TempItems 
(
    ID int IDENTITY, 
    Name varchar(50), 
    Price currency 
) 


-- Insert the rows from tblItems into the temp. table 
INSERT INTO #TempItems (Name, Price) 
SELECT Name,Price FROM tblItem ORDER BY Price 

-- Find out the first and last record we want 
DECLARE @FirstRec int, @LastRec int 
SELECT @FirstRec = (@Page - 1) * @RecsPerPage 
SELECT @LastRec = (@Page * @RecsPerPage + 1) 

-- Now, return the set of paged records, plus, an indiciation of we 
-- have more records or not! 
SELECT *, 
     MoreRecords = 
    (
    SELECT COUNT(*) 
    FROM #TempItems TI 
    WHERE TI.ID >= @LastRec 
    ) 
FROM #TempItems 
WHERE ID > @FirstRec AND ID < @LastRec 


-- Turn NOCOUNT back OFF 
SET NOCOUNT OFF 
1

Si alguien está utilizando SQL Server 2012 - una nueva característica se agregó en la cláusula ORDER BY, para consultar la optimización de un conjunto de datos, lo que hace más fácil el trabajo con datos de paginación para cualquiera que escriba en T-SQL y para todo el plan de ejecución en SQL Server. Referencia here.

Cuestiones relacionadas