Las consultas y actualizaciones son extremadamente lentas después de IndexOptimize


12

Base de datos SQL Server 2017 Enterprise CU16 14.0.3076.1

Recientemente intentamos cambiar de los trabajos de mantenimiento predeterminados de Reconstrucción de índice a Ola Hallengren IndexOptimize. Los trabajos predeterminados de reconstrucción de índice se ejecutaban durante un par de meses sin problemas, y las consultas y actualizaciones funcionaban con tiempos de ejecución aceptables. Después de ejecutar IndexOptimizeen la base de datos:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

El rendimiento fue extremadamente degradado. Una declaración de actualización que tardó 100 ms antes IndexOptimizetomó 78,000 ms después (usando un plan idéntico), y las consultas también estaban realizando varios órdenes de magnitud peor.

Como todavía es una base de datos de prueba (estamos migrando un sistema de producción de Oracle) volvimos a una copia de seguridad y la deshabilitamos IndexOptimizey todo volvió a la normalidad.

Sin embargo, nos gustaría entender qué IndexOptimizees diferente de lo "normal" Index Rebuildque podría haber causado esta degradación extrema del rendimiento para asegurarnos de evitarlo una vez que empezamos la producción. Cualquier sugerencia sobre qué buscar sería muy apreciada.

Plan de ejecución para la declaración de actualización cuando es lenta. es decir,
después de IndexOptimize
Plan de ejecución real (próximamente)

No he podido detectar una diferencia.
Planifique la misma consulta cuando sea rápida
Plan de ejecución real

Respuestas:


11

Sospecho que tiene una frecuencia de muestreo diferente definida entre sus dos enfoques de mantenimiento. Creo que los scripts de Ola usan muestreo predeterminado a menos que especifique el @StatisticsSampleparámetro , que no parece que esté haciendo actualmente.

En este punto, esto es especulación, pero puede verificar para ver qué frecuencia de muestreo se está utilizando actualmente en sus estadísticas ejecutando la siguiente consulta en su base de datos:

SELECT  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) AS TableName
    ,   col.name AS ColumnName
    ,   st.name AS StatsName
    ,   sp.last_updated
    ,   sp.rows_sampled
    ,   sp.rows
    ,   (1.0*sp.rows_sampled)/(1.0*sp.rows) AS sample_pct
FROM sys.stats st 
    INNER JOIN sys.stats_columns st_col
        ON st.object_id = st_col.object_id
        AND st.stats_id = st_col.stats_id
    INNER JOIN sys.columns col
        ON st_col.object_id = col.object_id
        AND st_col.column_id = col.column_id
    CROSS APPLY sys.dm_db_stats_properties (st.object_id, st.stats_id) sp
ORDER BY 1, 2

Si ve que esto está pasando por 1s (por ejemplo, 100%), es probable que este sea su problema. Tal vez intente los scripts de Ola nuevamente, incluido el @StatisticsSampleparámetro con el porcentaje que devuelve esta consulta y vea si eso soluciona su problema.


Como evidencia adicional de apoyo para esta teoría, el plan de ejecución XML muestra tasas de muestreo muy diferentes para la consulta lenta (2.18233%):

<StatisticsInfo LastUpdate="2019-09-01T01:07:46.04" ModificationCount="0" 
    SamplingPercent="2.18233" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

Frente a la consulta rápida (100%):

<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555" 
    SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

@JoshDarnell LOL, esta es la segunda vez que encuentras información de estadísticas de apoyo en el plan de consulta que no pude ver. Gracias por la edición!
John Eisbrener

¡Jaja, olvidé que eras tú, John! Prometo que no te estoy acosando 😅
Josh Darnell

@JoshDarnell Aprecio las ideas adicionales y es otro buen recordatorio de que hay tanta información en los planes de ejecución que simplemente no debe omitir.
John Eisbrener

¡Encantado de ayudar! Y sí, también hay cosas que extraño todo el tiempo (me han quemado las estadísticas, así que tiendo a ir rápidamente para ver qué pasa).
Josh Darnell

Gracias por esta explicación, de hecho fue el problema. La mayoría de las estadísticas tenían una frecuencia de muestreo predeterminada del 2,2%, sin embargo, algunas que se crearon después de la migración de Oracle tenían una frecuencia de muestreo del 100%. Parece que la reconstrucción predeterminada del índice mantuvo el 100%, pero cuando usamos IndexOptimize, también aplicó el valor predeterminado del 2.2%. La aplicación del parámetro @StatisticsSample y la ejecución de las consultas nuevamente verificaron que esto fue lo que causó el problema.
Martin Bergström

5

La respuesta de John es la solución correcta, esto es solo una adición en cuanto a qué partes del plan de ejecución cambiaron y, por ejemplo, cómo detectar fácilmente las diferencias con el explorador Sentry One Plan

Una declaración de actualización que tomó 100 ms antes de que IndexOptimize tomara 78,000 ms después (usando un plan idéntico)

Al mirar todos los planes de consulta cuando su rendimiento se degradó, puede detectar fácilmente las diferencias.

Rendimiento degradado

ingrese la descripción de la imagen aquí

Dos cuentas de más de 35 segundos de tiempo de CPU y tiempo transcurrido

Rendimiento esperado

ingrese la descripción de la imagen aquí

Mucho mejor

La degradación principal es dos veces en esta consulta de actualización:

UPDATE SVALA.INGÅENDEANALYS
                           SET 
                              UPPDRAGAVSLUTAT = @NEW$AVSLUTAT
                        WHERE INGÅENDEANALYS.ID IN 
                           (
                              SELECT IA.ID
                              FROM 
                                 SVALA.INGÅENDEANALYS  AS IA 
                                    JOIN SVALA.INGÅENDEANALYSX  AS IAX 
                                    ON IAX.INGÅENDEANALYS = IA.ID 
                                    JOIN SVALA.ANALYSMATERIAL  AS AM 
                                    ON AM.ID = IA.ANALYSMATERIALID 
                                    JOIN SVALA.ANALYSMATERIALX  AS AMX 
                                    ON AMX.ANALYSMATERIAL = AM.ID 
                                    JOIN SVALA.INSÄNTMATERIAL  AS IM 
                                    ON IM.ID = AM.INSÄNTMATERIALID 
                                    JOIN SVALA.INSÄNTMATERIALX  AS IMX 
                                    ON IMX.INSÄNTMATERIAL = IM.ID
                              WHERE IM.UPPDRAGSID = SVALA.PKGSVALA$STRIPVERSION(@NEW$ID)
                      )

El plan de ejecución de esta consulta con rendimiento degradado

El plan de consulta estimado de esta consulta de actualización tiene estimaciones muy altas cuando se degradó el rendimiento:

ingrese la descripción de la imagen aquí

Si bien en realidad (el plan de ejecución real) todavía tiene que funcionar, no es la cantidad loca que muestran las estimaciones.

El mayor impacto en el rendimiento son los dos escaneos y el hash match se une a continuación:

Escaneo real en rendimiento degradado # 1

ingrese la descripción de la imagen aquí

Escaneo real en rendimiento degradado # 2

ingrese la descripción de la imagen aquí


El plan de ejecución de esta consulta con el rendimiento esperado.

Cuando compara eso con las estimaciones (o datos reales) del plan de consulta con el rendimiento normal esperado, las diferencias son fáciles de detectar.

ingrese la descripción de la imagen aquí

Además, los dos accesos a la tabla anteriores ni siquiera ocurrieron:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

No ve esta eliminación en la combinación hash porque la entrada de compilación (superior) se inserta primero en la tabla hash. Luego, los valores cero se sondean en esta tabla hash, devolviendo valores cero.


1
Gracias por la descripción detallada de los planes, fue muy útil para entender por qué ocurrió el problema. Definitivamente voy a echar un vistazo a Sentry One Plan Explorer, ¡se ve muy útil!
Martin Bergström

@ MartinBergström Es genial escuchar eso, gracias por proporcionar los planes de consulta y por brindarnos toda la información relevante que solicitamos en los comentarios :). ¡Lo mejor del plan explorer es que es gratis! También puede funcionar desde ssms internos (haciendo clic con el botón derecho en el plan de ejecución y presionando "ver con sentryone plan explorer").
Randi Vertongen

1

Sin más información, solo podemos realizar puñaladas ligeramente informadas en la oscuridad, por lo que debe editar la pregunta para proporcionar un poco más. Por ejemplo, los planes de consulta para esa declaración de actualización para la que ha dado los tiempos, tanto antes como después de las operaciones de mantenimiento del índice, ya que los planes pueden diferir debido a que las estadísticas del índice se han actualizado ( https://www.brentozar.com/pastetheplan / es útil para esto, en lugar de llenar la pregunta con lo que podría ser una gran parte de XML o dar una captura de pantalla que no incluye parte de la información pertinente que contiene el texto del plan).

Sin embargo, hay dos puntos muy simples:

  1. ¿Se ha completado definitivamente la ejecución de optimización? Si sus pruebas están compitiendo con el IO de reconstrucciones de índices de larga duración que afectarán los tiempos.
  2. ¿Probaste varias veces? Si la actualización se basa en datos de una consulta que considera muchos datos (en lugar de una simple `ACTUALIZAR TheTable SET ThisColumn = 'Un valor estático'), entonces es posible que estos datos estén normalmente en la memoria pero se hayan vaciado en que las primeras ejecuciones de consultas relacionadas serán más lentas de lo habitual debido a que golpea el disco en lugar de encontrar las páginas necesarias que ya están en el grupo de búferes en la memoria.

Gracias por tomarse el tiempo de responder. He actualizado la pregunta con enlaces de pastetheplan. La optimización definitivamente se había completado, funcionó durante aproximadamente 1 hora el día antes de que ocurrieran los problemas. Probamos varias veces, y en realidad afectó a dos copias de la base de datos que se ejecutan en dos entornos de prueba diferentes de la misma manera. La declaración de actualización fue solo el ejemplo más simple que encontré, hubo muchos otros insertos y selecciones afectadas
Martin Bergström

Por "varias veces" me refería a probar las actualizaciones varias veces después de una instancia de los cambios de índice, en lugar de ejecutar el script de optimización de índice varias veces de forma independiente (aunque esa es en sí misma una forma útil de verificar que el resultado sea reproducible). Si el enjuague de memoria es (o es parte de) el problema, entonces las primeras actualizaciones desde selecciones cebarán el grupo de búferes, por lo que las posteriores serán potencialmente más rápidas debido a una E / S significativamente reducida.
David Spillett

Disculpas si mi respuesta no fue clara. Sí, probamos las actualizaciones varias veces. Las ralentizaciones ocurrieron en una base de datos utilizada por los probadores para probar la aplicación y las consultas y actualizaciones que se ejecutaron varias veces durante el día sin una mejora en el rendimiento.
Martin Bergström
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.