Tengo una consulta SQL Server 2008 algo compleja (alrededor de 200 líneas de SQL bastante denso) que no funcionaba como la necesitaba. Con el tiempo, el rendimiento bajó de aproximadamente .5 segundos a aproximadamente 2 segundos.
Echando un vistazo al plan de ejecución, era bastante obvio que al reordenar las uniones, el rendimiento podría mejorarse. Lo hice, y lo hizo ... hasta unos 0,3 segundos. Ahora la consulta tiene la sugerencia "ORDEN DE FUERZA DE OPCIÓN" , y la vida es buena.
Hoy viene conmigo, limpiando la base de datos. Archivo alrededor del 20% de las filas, sin realizar ninguna acción en la base de datos relevante, excepto eliminar filas ... el plan de ejecución se MANTIENE TOTALMENTE . Evalúa completamente erróneamente cuántas filas devolverán ciertos subárboles y (por ejemplo) reemplaza a:
<Hash>
con
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Ahora el tiempo de consulta aumenta de aproximadamente .3s a aproximadamente 18s. (!) Solo porque eliminé filas. Si elimino la sugerencia de consulta, vuelvo al tiempo de consulta de aproximadamente 2 segundos. Mejor pero peor.
He reproducido el problema después de restaurar la base de datos en múltiples ubicaciones y servidores. Simplemente eliminar aproximadamente el 20% de las filas de cada tabla siempre causa este problema.
- ¿Es normal que una orden de unión forzada haga que las estimaciones de la consulta sean completamente inexactas (y, por lo tanto, los tiempos de consulta sean impredecibles)?
- ¿Debo esperar que tendré que aceptar un rendimiento de consulta subóptimo o mirarlo como un halcón y con frecuencia editar manualmente las sugerencias de consulta? ¿O tal vez insinúa cada unión también? .3s a 2s es un gran éxito.
- ¿Es obvio por qué el optimizador explotó después de eliminar filas? Por ejemplo, "sí, tomó un escaneo de muestra, y debido a que archivé la mayoría de las filas anteriormente en el historial de datos, la muestra arrojó resultados escasos, por lo que subestimó la necesidad de una operación de hash ordenada"?
Si desea ver los planes de ejecución, sugiera una ubicación donde pueda publicarlos. De lo contrario, he probado la parte más impresionante. Aquí está la estimación errónea fundamental, los números en parens son filas (estimadas: reales).
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Tenga en cuenta que se espera que el bucle interno escanee 908 filas, pero en su lugar escanea 52,258,441. Si hubiera sido preciso, esta rama habría corrido unos 2 ms, en lugar de 12 segundos. Antes de eliminar las filas, esta estimación de unión interna solo estaba desactivada por un factor total de 2, y se realizó como una coincidencia hash en dos índices agrupados.