2011-05-14 12 views
16

que acaba de comenzar buscando en la optimización de mis consultas a través de índices, porque los datos de SQL está creciendo grande y rápido. Miré cómo el optimizador está procesando mi consulta a través del plan de ejecución en SSMS y noté que se está utilizando un operador de clasificación. He oído que un operador de Sort indica un diseño incorrecto en la consulta, ya que el ordenamiento se puede realizar prematuramente a través de un índice. Así que aquí es una tabla de ejemplo y datos similares a lo que estoy haciendo:Optimización de consultas SQL mediante la eliminación de operador Clasificar en el plan de ejecución

IF OBJECT_ID('dbo.Store') IS NOT NULL DROP TABLE dbo.[Store] 
GO 

CREATE TABLE dbo.[Store] 
(
    [StoreId] int NOT NULL IDENTITY (1, 1), 
    [ParentStoreId] int NULL, 
    [Type] int NULL, 
    [Phone] char(10) NULL, 
    PRIMARY KEY ([StoreId]) 
) 

INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 0, '2223334444') 
INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 0, '3334445555') 
INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 1, '0001112222') 
INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 1, '1112223333') 
GO 

Aquí es una consulta de ejemplo:

SELECT [Phone] 
FROM [dbo].[Store] 
WHERE [ParentStoreId] = 10 
AND ([Type] = 0 OR [Type] = 1) 
ORDER BY [Phone] 

creo un índice no agrupado para ayudar a acelerar la consulta:

CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Type], [Phone]) 

Para construir el índice IX_Store, comienzo con los predicados simples

[ParentStoreId] = 10 
AND ([Type] = 0 OR [Type] = 1) 

Luego añadir la columna de la [Phone] para el ORDER BY y para cubrir la salida SELECT

lo tanto, incluso cuando el índice se construye, el optimizador todavía utiliza el operador Ordenar (y no el índice de clasificación) porque [Phone] está ordenada según [ParentStoreId] Y [Type]. Si quito la columna de la [Type] del índice y funciono con la pregunta:

SELECT [Phone] 
FROM [dbo].[Store] 
WHERE [ParentStoreId] = 10 
--AND ([Type] = 0 OR [Type] = 1) 
ORDER BY [Phone] 

Entonces, por supuesto, el operador Ordenar no es utilizado por el optimizador porque [Phone] está ordenada por [ParentStoreId].

Entonces, la pregunta es ¿cómo puedo crear un índice que cubra la consulta (incluido el predicado [Type]) y que el optimizador no utilice Sort?

EDIT:

La tabla Estoy trabajando con más de 20 millones de filas

+0

que realmente debería hacer '' una tecla [StoreID] primaria (que también a los valores predeterminados en clúster por cierto), no sólo tiene que añadir un índice único. – Lucero

+0

Es posible que pueda solucionar este problema creando un * segundo * índice en la columna del Teléfono. –

+0

@Lucero, que modificó mi post para marcar '[StoreID]' como la clave principal, aunque no creo que esto va a resolver el problema Ordenar – jodev

Respuesta

10

En primer lugar, debe verificar que el tipo es en realidad un cuello de botella. La duración de la clasificación dependerá de la cantidad de elementos que se ordenarán, y es probable que el número de tiendas para una tienda principal particular sea pequeño. (Eso es suponiendo que se aplica el operador sort después de aplicar la cláusula where).

He oído que un operador Ordenar indica un mal diseño en la consulta ya que la especie se puede hacer antes de tiempo a través de un índice

Esa es una generalización más. A menudo, un operador de clasificación puede trasladarse trivialmente al índice y, si solo se captan las primeras dos filas del conjunto de resultados, puede reducir sustancialmente el costo de la consulta, porque la base de datos ya no tiene que buscar todas las filas coincidentes (y ordenarlas). todo) para encontrar los primeros, pero puede leer los registros en orden de conjunto de resultados, y detener una vez que se encuentran suficientes registros.

En su caso, usted parece ser ir a buscar todo el conjunto de resultados, por lo que es poco probable ordenación que para hacer las cosas mucho peores (a menos que el conjunto de resultados es enorme). Además, en su caso podría no ser trivial construir un índice ordenado útil, porque la cláusula where contiene un o.

Ahora, si todavía quiere deshacerse de ese tipo-operador, que puede probar:

SELECT [Phone] 
FROM [dbo].[Store] 
WHERE [ParentStoreId] = 10 
AND [Type] in (0, 1) 
ORDER BY [Phone]  

Alternativamente, puede intentar el siguiente índice:

CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Phone], [Type]) 

para tratar de conseguir el optimizador de consultas para hacer una exploración del rango de índices de ParentStoreId solamente, a continuación, analizar todas las filas coincidentes en el índice, la salida de ellos si Type partidos. Sin embargo, es probable que esto genere más E/S de disco y, por lo tanto, ralentice la consulta en lugar de acelerarla.

Editar: Como último recurso, puede utilizar

SELECT [Phone] 
FROM [dbo].[Store] 
WHERE [ParentStoreId] = 10 
AND [Type] = 0 
ORDER BY [Phone] 

UNION ALL 

SELECT [Phone] 
FROM [dbo].[Store] 
WHERE [ParentStoreId] = 10 
AND [Type] = 1 
ORDER BY [Phone] 

con

CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Type], [Phone]) 

y ordenar las dos listas en el servidor de aplicaciones, donde se puede combinar (como en la combinación de una especie) las listas preclasificadas, evitando así un tipo completo. Pero eso es realmente una microoptimización que, si bien acelera la clasificación en un orden de magnitud, es poco probable que afecte al tiempo de ejecución total de la consulta, ya que supongo que el cuello de botella será de red y de E/S de disco, especialmente a la luz del hecho de que el disco tendrá mucho acceso aleatorio ya que el índice no está agrupado.

+0

la tabla que estoy usando tiene más de 20 millones de filas. Hay aproximadamente 50 valores diferentes "[ParentStoreId]" y 8 valores diferentes "[Type]". Al final, me queda ordenar alrededor de 200.000 filas, lo que parece ralentizar la consulta. Su información es útil, lo intentaré – jodev

+0

+1 Por sugerir una unión para eludir el operador Ordenar –

Cuestiones relacionadas