2009-09-08 4 views
10

Estoy seleccionando algunas filas de una función con valores de tabla pero he encontrado una inexplicable diferencia de rendimiento masivo al colocar SELECCIONAR SUPERIOR en la consulta.Diferencia de rendimiento masivo SQL usando SELECCIONAR SUPERIOR x incluso cuando x es mucho más alto que las filas seleccionadas

SELECT col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

tarda más de 5 o 6 minutos en completarse.

Sin embargo

SELECT TOP 6000 col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

completa en aproximadamente 4 o 5 segundos.

Esto no me sorprendería si el conjunto de datos devueltos fuera enorme, pero la consulta en particular implicó devuelve ~ 5000 filas de 200,000.

Por lo tanto, en ambos casos, toda la tabla se procesa, ya que SQL Server continúa hasta el final en busca de 6000 filas que nunca alcanzará. ¿Por qué la diferencia masiva entonces? ¿Esto tiene algo que ver con la forma en que SQL Server asigna espacio en anticipación del tamaño del conjunto de resultados (el TOP 6000 por lo tanto le da un requisito bajo que se asigna más fácilmente en la memoria)? ¿Alguien más ha sido testigo de algo como esto?

Gracias

+0

¿Has mirado los planes de consulta? ¿Hay una diferencia? –

+2

Simplemente curioso, ¿qué pasa con el rendimiento si dices SELECCIONAR EL 100 POR CIENTO ...? –

+0

Supongo que tiene algunas estadísticas que arrojan el optimizador de consultas fuera de kelter. El optimizador puede, por ejemplo, decidir utilizar un escaneo de tabla en lugar de una búsqueda de índice si cree que hay muy pocas filas en una tabla. Por qué esto no afecta la consulta SUPERIOR que no sé, pero examine los planes de ejecución. Estos le muestran lo que hace el servidor, y eso explicará por qué uno es lento. También le mostrará el número estimado y real de filas. Si algunas estimaciones están lejos, actualice las estadísticas y vuelva a intentarlo. :) –

Respuesta

6

Las funciones con valores de tabla pueden tener un tiempo de ejecución no lineal.

Consideremos función equivalente para esta consulta:

SELECT (
     SELECT SUM(mi.value) 
     FROM mytable mi 
     WHERE mi.id <= mo.id 
     ) 
FROM mytable mo 
ORDER BY 
     mo.value 

Esta consulta (que calcula el funcionamiento SUM) es rápido al principio y lenta al final, ya que en cada fila de mo se deben sumar todas las valores anteriores que requieren rebobinar la fuente.

El tiempo necesario para calcular SUM para cada fila aumenta a medida que aumenta el número de filas.

Si hace mytable lo suficientemente grande (por ejemplo, 100,000 filas, como en el ejemplo) y ejecuta esta consulta, verá que lleva un tiempo considerable.

Sin embargo, si aplica TOP 5000 a esta consulta, verá que completa mucho más rápido que 1/20 del tiempo requerido para la tabla completa.

Lo más probable es que ocurra algo similar en su caso también.

Para decir algo más definitivamente, necesito ver la definición de la función.

Actualización:

SQL Server puede empujar predicados en la función.

Por ejemplo, acabo de crear este TVF:

CREATE FUNCTION fn_test() 
RETURNS TABLE 
AS 
RETURN (
     SELECT * 
     FROM master 
     ); 

Estas consultas: exploración

SELECT * 
FROM fn_test() 
WHERE name = @name 

SELECT TOP 1000 * 
FROM fn_test() 
WHERE name = @name 

de rendimiento diferentes planes de ejecución (el primero utiliza agrupado, el segundo utiliza un índice buscan con a TOP)

+0

'Fraudó no en este caso. El objetivo de mi consulta es que se devuelvan _same_ las filas independientemente de si la cláusula TOP se usó o no (TOP 6000 es más grande que el conjunto de resultados). Por lo tanto, no puede ser con el cálculo de esas filas. – Ray

+0

'@ Arj': ¿podría publicar la definición de su función? – Quassnoi

+0

@Quassnoi: el TVF en línea es simplemente un macro. – gbn

1

No es necesariamente cierto que toda la tabla se procesa si col1 tiene un índice.

La optimización de SQL elegirá si se usa o no un índice. Tal vez su "TOP" lo obligue a usar el índice.

Si está utilizando el MSSQL Query Analyzer (El nombre se me escapa) pulse Ctrl-K. Esto mostrará el plan de ejecución para la consulta en lugar de ejecutarlo. El desplazamiento sobre los iconos mostrará el uso de I/CPU, creo.

Apuesto a que uno está utilizando una búsqueda de índice, mientras que el otro no lo es.

Si tiene un cliente genérico: SET SHOWPLAN_ALL ON; GO seleccionar ...; ir

ver http://msdn.microsoft.com/en-us/library/ms187735.aspx para más detalles.

+0

Sí, estoy viendo el plan en este momento. Aunque he alterado la consulta para publicar. En realidad, está haciendo SELECT *. No veo cómo usar TOP provocaría el uso de un índice. – Ray

+0

SQL Optimizer decidirá si se usa o no un índice. He realizado consultas en las que la cláusula where provoca un "punto de inflexión" en el que el optimizador decide realizar una exploración de tabla completa en lugar de usar un índice. – ericp

1

Puede que te encuentres con algo tan simple como el almacenamiento en caché aquí - ¿quizás (por alguna razón) la consulta "TOP" está en caché? ¿Usa un índice que el otro no es?

En cualquier caso, la mejor manera de saciar su curiosidad es examinar el plan de ejecución completo para ambas consultas. Puede hacerlo bien en SQL Management Console y le informará EXACTAMENTE qué operaciones se están completando y cuánto tiempo se prevé que tomarán.

Todas las implementaciones de SQL son peculiares a su manera: SQL Server no es una excepción. Este tipo de "whaaaaaa ?!" los momentos son bastante comunes. ; ^)

3

Su TOP no tiene ORDER BY, por lo que es simplemente lo mismo que SET ROWCOUNT 6000 primero. Un ORDER BY requeriría que todas las filas se evalúen primero, y tomaría mucho más tiempo.

Si dbo.some_table_function es una tabla en línea valorada como udf, entonces simplemente se trata de una macro que se expande, por lo que devuelve las primeras 6000 filas como se menciona en un orden particular.

Si el udf tiene múltiples valores, se trata de una caja negra y siempre extraerá el conjunto de datos completo antes de filtrar. No creo que esto esté sucediendo.

no directamente relacionados, pero another SO question on TVFs

1

creo sugerencia Quassnois' parece muy plausible. Al agregar TOP 6000 está implícitamente dando al optimizador una pista de que se devolverá un subconjunto bastante pequeño de las 200,000 filas. Luego, el optimizador utiliza una búsqueda de índice en lugar de una exploración de índice agrupado o una exploración de tabla.

Otra posible explicación podría ser el almacenamiento en caché, como sugiere Jim Davis. Esto es bastante fácil de descartar al ejecutar las consultas nuevamente. Intenta ejecutar primero el primero con TOP 6000.

2

Tuve el mismo problema, una consulta simple que une cinco tablas y devuelve 1000 filas tardó dos minutos en completarse. Cuando agregué "TOP 10000" a él, se completó en menos de un segundo. Resultó que el índice agrupado en una de las tablas estaba muy fragmentado.

Después de reconstruir el índice, la consulta se completa en menos de un segundo.

Cuestiones relacionadas