2011-07-11 6 views
14

Digamos que usted tiene una visión:¿Por qué poner una cláusula WHERE vista exterior tiene desempeño terrible

CREATE VIEW dbo.v_SomeJoinedTables AS 
SELECT 
    a.date, 
    a.Col1, 
    b.Col2, 
    DENSE_RANK() 
     OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something 
FROM a JOIN b on a.date = b.date 

He encontrado que el rendimiento de:

SELECT * 
FROM v_SomeJoinedTables 
WHERE date > '2011-01-01' 

es mucho peor que

SELECT *, 
    DENSE_RANK() 
    OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something 
FROM a JOIN b ON a.date = b.date 
WHERE a.date > '2011-01-01' 

Estoy muy sorprendido de que el plan de consulta para estas dos declaraciones no sea el mismo.

También he intentado utilizar una función de tabla en línea, pero la consulta todavía tarda 100-1000 veces más que el código donde copio y pego la lógica de vista.

¿Alguna idea?

+2

Bueno, ¿cómo se ven los planes de consulta? ¿Te estás perdiendo un índice? ¿La vista está devolviendo demasiadas filas? Si la cláusula where se aplica en el lugar equivocado? –

+1

¿Su vista está llamando a una vista? – HLGEM

+0

¿Qué sucede si su vista no contiene una función de ventana? ¿Cuál es el resultado semántico esperado de una VISTA que calcula el rango en todo el conjunto, pero una consulta a la vista agrega una nueva condición - ¿debe aplicarse el insde RANK antes o después de la condición afuera? – ErikE

Respuesta

15

Se llama "Predicate pushing" alias filtrado diferido.

SQL Server no siempre se da cuenta de que DONDE se puede aplicar "antes", dentro de la vista de manera efectiva.

Se ha mitigado en SQL Server 2008 para que funcione más de lo esperado

+0

Buena referencia. Eso es realmente aterrador. Confirma mi sospecha de que SQL Server nunca se ha sentido cómodo con el concepto de una palabra clave TOP en SQL. Uno realmente no debería necesitar saber esto para escribir consultas optimizadas. – dkretz

+0

Estaba completamente sorprendido de descubrir cuán mal SQL Server 2005 maneja las funciones de RANK. Realmente debería haber una revisión para eso y no requerir una actualización a SQL 2008. – bpeikes

+0

@bpeikes: sí, ver http://stackoverflow.com/q/4230838/27535 y comentar aquí también: http://stackoverflow.com/q/2798094/27535 – gbn

2

No soy un experto en SQL, por lo que puede ser rechazado por mi tontería, pero supongo que en el primer caso SQL obtiene los resultados de la vista completa antes de aplicar el predicado en la cláusula WHERE . Por lo tanto, cuando consulta la vista, selecciona todos los registros, los pone en la memoria y luego aplica el filtro de fecha después de que finaliza.

Esto parece similar a la búsqueda de todo el conjunto de datos especificado en sus uniones antes de aplicar el filtro en el WHERE (la lección aquí es que debe aplicar predicados en su cláusula ON cuando sea posible).

A menos que las vistas se traten de manera diferente de alguna manera.

+0

+1 Creo que tienes toda la razón. Quizás las estadísticas estén desactivadas, y tendría que verificar comparando los planes estimados/reales para cada consulta, pero es bastante probable que la consulta de la vista materialice la unión completa antes de aplicar el filtro, mientras que la consulta externa puede usar el filtro para elija un tipo de combinación más eficiente si puede eliminar las filas de un lado de la unión anteriormente. –

+0

Las vistas son solo abreviaciones de la expresión completa. No serían de mucha utilidad si no fueran igualmente optimizables. – dkretz

+0

+1 está en lo cierto, mi respuesta muestra * por qué * – gbn

-1

Como solución alternativa, sugeriría usar una función en lugar de una vista para poder pasar el parámetro de datos.

1

Técnicamente, no está comparando entre las mismas sentencias de SQL. Su vista indica que devuelve a.date, a.Col1, b.Col2, más su función DENSE_RANK(). En su consulta sin la vista, devuelve todas las columnas.

Al principio, puede pensar que devolver todas las columnas sería peor. Pero es difícil determinar cuál sería mejor sin saber cómo se ve la estructura de la tabla, incluidos los índices.

¿Ha comparado los planes de consulta para cada declaración?

+0

Casi válido ... la vista es más lenta, este es el punto de la pregunta. Incluso si la consulta en línea es "perjudicada" por SELECT * – gbn

2

la sintaxis OVER() era nueva en SS2005 y aparentemente no está bien integrada en el optimizador. Te sugiero que pruebes una expresión más tradicional? Probablemente NO sea una expresión si te preocupa la optimización.

http://www.sqlteam.com/article/sql-sever-2005-using-over-with-aggregate-functions

O, mejor, ser un poco más familiarizados con el perfilador - la vista debe ser corregible.

+0

FYI, mi enlace demuestra que esto se ha resuelto. Ver esto también (comentarios también) http://stackoverflow.com/q/2798094/27535 – gbn

+0

Tal vez, pero tal vez no con su sitio/versión. No es genial cuando la implementación es tan poco fiable que necesitas saber todo lo que tú o yo sabemos que funciona de manera confiable. – dkretz

+0

De hecho. Y la gente como tú o yo no solemos utilizar las vistas para no verlas día a día ... – gbn

Cuestiones relacionadas