Base de données SQL Server 2017 Enterprise CU16 14.0.3076.1
Nous avons récemment essayé de passer des tâches de maintenance par défaut de reconstruction d'index à Ola Hallengren IndexOptimize
. Les travaux de reconstruction d'index par défaut étaient en cours d'exécution depuis quelques mois sans aucun problème, et les requêtes et les mises à jour fonctionnaient avec des délais d'exécution acceptables. Après avoir exécuté IndexOptimize
sur la base de données:
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'
les performances étaient extrêmement dégradées. Une instruction de mise à jour qui prenait 100 ms avant IndexOptimize
prenait 78 000 ms par la suite (en utilisant un plan identique), et les requêtes exécutaient également plusieurs ordres de grandeur.
Comme il s'agit toujours d'une base de données de test (nous migrons un système de production depuis Oracle), nous sommes revenus à une sauvegarde et avons désactivé IndexOptimize
et tout est revenu à la normale.
Cependant, nous aimerions comprendre ce que IndexOptimize
fait différemment du _ "normal" Index Rebuild
qui aurait pu provoquer cette dégradation extrême des performances afin de nous assurer de l'éviter une fois en production. Toute suggestion sur ce qu'il faut rechercher serait grandement appréciée.
Plan d'exécution de l'instruction de mise à jour lorsqu'elle est lente. c'est à dire.
après IndexOptimize
Plan d'exécution réel (à venir dès que possible)
Je n'ai pas pu voir de différence.
Planifiez la même requête lorsqu'elle est rapide
Plan d'exécution réel
Je suppose que vous avez un taux d'échantillonnage différent défini entre vos deux approches de maintenance. Je pense que les scripts d'Ola utilisent l'échantillonnage par défaut, sauf si vous spécifiez le @StatisticsSample
paramètre , ce qui ne semble pas être le cas actuellement.
À ce stade, il s'agit de spéculations, mais vous pouvez vérifier le taux d'échantillonnage actuellement utilisé dans vos statistiques en exécutant la requête suivante dans votre base de données:
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 vous voyez que cela passe par un 1 (par exemple 100%), c'est probablement votre problème. Essayez peut-être à nouveau les scripts d'Ola, y compris le @StatisticsSample
paramètre avec le pourcentage renvoyé par cette requête et voir si cela résout votre problème?
Comme preuve supplémentaire à l'appui de cette théorie, le plan d'exécution XML montre des taux d'échantillonnage très différents pour la requête lente (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]" />
Contre la requête rapide (100%):
<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555"
SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]"
Schema="[SVALA]" Database="[ulek-sva]" />
la réponse de John est la bonne solution, ce n'est qu'un ajout sur les parties du plan d'exécution modifiées et un exemple sur la façon de repérer facilement les différences avec Sentry One Plan Explorer
Une déclaration de mise à jour qui a pris 100 ms avant que IndexOptimize prenne 78 000 ms par la suite (en utilisant un plan identique)
Lorsque vous regardez tous les plans de requête lorsque vos performances ont été dégradées, vous pouvez facilement repérer les différences.
Performances dégradées
Deux comptes de plus de 35 secondes de temps processeur et de temps écoulé
Performances attendues
Beaucoup mieux
La dégradation principale est deux fois sur cette requête de mise à jour:
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)
)
le plan d'exécution de cette requête avec des performances dégradées
Le plan de requête estimé de cette requête de mise à jour a des estimations très élevées lorsque les performances ont été dégradées:
Alors qu'en réalité (le plan d'exécution réel), il doit encore faire du travail, mais pas le montant fou que les estimations montrent.
Le plus grand impact sur les performances est les deux scans et correspondances de hachage ci-dessous:
Analyse réelle des performances dégradées # 1
Analyse réelle des performances dégradées # 2
Le plan d'exécution de cette requête avec les performances attendues
Lorsque vous comparez cela aux estimations (ou chiffres réels) du plan de requête avec des performances attendues normales, les différences sont faciles à repérer.
De plus, les deux accès précédents aux tables ne se sont même pas produits:
Vous ne voyez pas cette élimination sur la jointure de hachage car l'entrée de construction (en haut) est insérée en premier dans la table de hachage. Ensuite, des valeurs nulles sont sondées dans cette table de hachage, retournant des valeurs nulles.
Sans plus d'informations, nous ne pouvons que prendre des coups de couteau légèrement informés dans l'obscurité, vous devez donc modifier la question pour en fournir un peu plus. Par exemple, les plans de requête pour cette instruction de mise à jour pour laquelle vous avez donné les délais, à la fois avant et après les opérations de maintenance d'index, car les plans peuvent différer en raison de la mise à jour des statistiques d'index ( https: //www.brentozar .com/pastetheplan / est utile pour cela, plutôt que de remplir la question avec ce qui pourrait être un énorme morceau de XML ou de donner une capture d'écran qui n'inclut pas certaines des informations pertinentes contenues dans le texte du plan) .
Cependant, deux points très simples: