El plan de ejecución de consultas de SQL Server muestra un error & # 8220; conteo real de filas & # 8221; en un índice usado y el rendimiento es terrible lento

StackOverflow https://stackoverflow.com/questions/225309

Pregunta

Hoy me topé con un problema de rendimiento interesante con un procedimiento almacenado que se ejecuta en Sql Server 2005 SP2 en una base de datos que se ejecuta en un nivel compatible de 80 (SQL2000).

El proceso se ejecuta en aproximadamente 8 minutos y el plan de ejecución muestra el uso de un índice con un recuento real de filas de 1.339.241.423, que es aproximadamente un factor 1000 más alto que el " real " el número real de filas de la propia tabla, que es 1.144.640, como se muestra correctamente según el recuento estimado de filas. ¡Así que el recuento real de filas dado por el optimizador de planes de consulta es definitivamente incorrecto!

alt text

Curiosamente, cuando copio los valores del parámetro procs dentro de proc a las variables locales y luego utilizo las variables locales en la consulta real, todo funciona bien: el proc se ejecuta durante 18 segundos y el plan de ejecución muestra el número correcto de filas reales.

EDITAR: según lo sugerido por TrickyNixon, esto parece ser una señal del problema de detección de parámetros. Pero en realidad, en ambos casos obtengo el mismo plan de ejecución. Se están utilizando los mismos índices en el mismo orden. La única diferencia que veo es la forma de contar con un alto número de filas reales en el índice PK_ED_Transitions cuando se usan directamente los parametervalues.

Ya hice dbcc dbreindex y UPDATE STATISTICS sin ningún éxito. dbcc show_statistics también muestra buenos datos para el índice.

El proceso se crea CON RECOMPILE por lo que cada vez que se ejecuta un nuevo plan de ejecución se compila.

Para ser más específico, este se ejecuta rápido:

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

declare @local datetime
set @local = @Param

select 
some columns
from 
table1
where
column = @local
group by
some other columns

Y esta versión se ejecuta terriblemente lenta, pero produce exactamente el mismo plan de ejecución (además del conteo real de filas demasiado alto en un índice usado):

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

select 
some columns
from 
table1
where
column = @Param
group by
some other columns

¿Alguna idea? ¿Alguien por ahí que sabe de dónde obtiene el Sql Server el valor real del recuento de filas cuando calcula los planes de consulta?

Actualizar : probé la consulta en otro servidor con el modo copat establecido en 90 (Sql2005). Es el mismo comportamiento. Creo que abriré una llamada de soporte de ms, porque me parece un error.

¿Fue útil?

Solución

Ok, finalmente lo logré yo mismo.

Los dos planes de consulta son diferentes en un pequeño detalle que falté al principio. el lento utiliza un operador de bucles anidados para unir dos subconsultas. Y eso resulta en el número alto en el recuento de filas actual en el operador de exploración de índice, que es simplemente el resultado de multiplicar el número de filas de la entrada a con el número de filas de la entrada b.

Todavía no sé por qué el optimizador decide usar los bucles anidados en lugar de una coincidencia hash que ejecuta 1000 temporizadores más rápido en este caso, pero podría manejar mi problema creando un nuevo índice, de modo que el motor haga una index search statt en lugar de una exploración de índice bajo los bucles anidados.

Otros consejos

Cuando está comparando los planes de ejecución del proceso almacenado con la consulta de copiar / pegar, ¿está utilizando los planes estimados o los planes reales? Asegúrese de hacer clic en Consulta, Incluir plan de ejecución y luego ejecute cada consulta. Compare esos planes y vea cuáles son las diferencias.

Suena como un caso de Detección de Parámetros. Aquí hay una excelente explicación junto con posibles soluciones: ¡Huelo un parámetro!

Aquí hay otro hilo de StackOverflow que lo trata: Sniffing de parámetros (o Spoofing) en SQL Server

Para mí todavía suena como si las estadísticas fueran incorrectas. La reconstrucción de los índices no necesariamente los actualiza.

¿Ya probaste un UPDATE STATISTICS explícito para las tablas afectadas?

¿Ha ejecutado sp_spaceused para verificar si SQL Server tiene el resumen correcto para esa tabla? Creo que en SQL 2000, el motor solía usar ese tipo de metadatos al crear planes de ejecución. Solíamos tener que ejecutar DBCC UPDATEUSAGE semanalmente para actualizar los metadatos en algunas de las tablas que cambian rápidamente, ya que SQL Server estaba eligiendo los índices incorrectos debido a los datos de conteo de filas incorrectos.

Está ejecutando SQL 2005, y BOL dice que en 2005 ya no debería tener que ejecutar UpdateUsage, pero dado que está en modo compatible con 2000, es posible que siga siendo necesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top