Tuve este problema hace mucho tiempo, encontré una solución que me convenía y lo olvidé.
Pero ahora está esa pregunta sobre SO, así que estoy dispuesto a plantear este problema.
Hay una vista que une pocas tablas de una manera muy sencilla (pedidos + líneas de pedido).
Cuando se consulta sin una where
cláusula, la vista devuelve varios millones de líneas.
Sin embargo, nadie lo llama así. La consulta habitual es
select * from that_nasty_view where order_number = 123456;
Esto devuelve aproximadamente 10 registros de 5m.
Una cosa importante: la vista contiene una función de ventana rank()
, que está dividida exactamente por el campo con el que siempre se consulta la vista:
rank() over (partition by order_number order by detail_line_number)
Ahora, si esta vista se consulta con parámetros literales en la cadena de consulta, exactamente como se muestra arriba, devuelve las filas al instante. El plan de ejecución está bien:
- Búsqueda de índice en ambas tablas usando los índices en
order_number
(devuelve 10 filas). - Cálculo de ventanas sobre el pequeño resultado devuelto.
- Seleccionando.
Sin embargo, cuando la vista se llama de forma parametrizada, las cosas se ponen feas:
Index scan
en todas las tablas ignorando los índices. Devuelve 5 millones de filas.- Enorme unión.
- Cálculo de ventanas sobre todos los
partition
s (aproximadamente 500k ventanas). Filter
tomar 10 filas de 5m.- Seleccione
Esto sucede en todos los casos cuando hay parámetros involucrados. Puede ser SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Puede ser un cliente ODBC, como Excel:
select * from that_nasty_view where order_number = ?
O puede ser cualquier otro cliente que use parámetros y no concatenación SQL.
Si la función de ventana se elimina de la vista, se ejecuta perfectamente rápido, independientemente de si se consulta o no con parámetros.
Mi solución fue eliminar la función infractora y volver a aplicarla en una etapa posterior.
Pero, ¿qué da? ¿Es realmente un error en cómo SQL Server 2008 maneja las funciones de la ventana?
order_number
No es una clave primaria. Está int not null
con índice no agrupado en ambas tablas.
OPTION (RECOMPILE)
ayuda?