J'ai une base de données SQL Server où les requêtes sont assez lentes, et il y a beaucoup de verrouillage et de blocage.
Quand je regarde les DMV d'index manquants et les plans de requête, il n'y a aucune suggestion.
Pourquoi donc?
Nous examinerons quelques-unes des raisons plus en détail et parlerons également de certaines des limites générales de la fonctionnalité.
Tout d'abord, à partir de: Limitations de la fonction d'index manquants :
- Il ne spécifie pas d'ordre d'utilisation des colonnes dans un index.
Comme indiqué dans cette Q&R: Comment SQL Server détermine-t-il l'ordre des colonnes clés dans les demandes d'index manquantes? , l'ordre des colonnes dans la définition d'index est dicté par le prédicat Equality vs Inequality, puis la position ordinale des colonnes dans le table.
Il n'y a aucune supposition quant à la sélectivité, et il peut y avoir un meilleur ordre disponible. C'est votre travail de comprendre cela.
Index spéciaux
Les demandes d'index manquantes ne couvrent pas non plus les index "spéciaux", comme:
Les colonnes de clé d'index manquantes sont générées à partir des colonnes utilisées pour filtrer les résultats, comme celles de:
Les colonnes manquantes de l'index inclus sont générées à partir des colonnes requises par la requête, comme celles de:
Même si assez souvent, les colonnes que vous triez ou regroupez peuvent être utiles en tant que colonnes clés. Cela remonte à l'une des limitations:
- Il n'est pas destiné à affiner une configuration d'indexation.
Par exemple, cette requête n'enregistrera pas une demande d'index manquante, même si l'ajout d'un index sur LastAccessDate éviterait d'avoir à trier (et à renverser sur le disque).
SELECT TOP (1000) u.DisplayName
FROM dbo.Users AS u
ORDER BY u.LastAccessDate DESC;
Ce regroupement ne fait pas non plus de requête sur l'emplacement.
SELECT TOP (20000) u.Location
FROM dbo.Users AS u
GROUP BY u.Location
Eh bien, oui, mais c'est mieux que rien. Pensez aux demandes d'index manquantes comme un bébé qui pleure. Vous savez qu'il y a un problème, mais c'est à vous, en tant qu'adulte, de déterminer ce qu'est ce problème.
Détendez-vous, bucko. Nous y arrivons.
Si vous activez TF 23 , les demandes d'index manquantes ne seront pas enregistrées. Pour savoir si vous l'avez activé, exécutez ceci:
DBCC TRACESTATUS;
Reconstruction des index effacera les requêtes d'index manquantes. Donc, avant de partir Hi-Ho-Silver-Away reconstruire chaque index à la seconde où un iota de fragmentation se glisse, pensez aux informations que vous effacez chaque fois que vous faites cela.
Vous pouvez également penser à Pourquoi la défragmentation de vos index n'aide pas , de toute façon. Sauf si vous utilisez Columnstore .
L'ajout, la suppression ou la désactivation d'un index effacera toutes les demandes d'index manquantes pour cette table. Si vous travaillez sur plusieurs modifications d'index sur la même table, assurez-vous de les écrire toutes avant de les effectuer.
Si un plan est assez simple et que le choix d'accès à l'index est assez évident et que le coût est suffisamment bas, vous obtiendrez un plan trivial.
Cela signifie que l'optimiseur n'a pris aucune décision basée sur les coûts.
Via Paul White :
Les détails des types de requête pouvant bénéficier du plan trivial changent fréquemment, mais des éléments tels que les jointures, les sous-requêtes et les prédicats d'inégalité empêchent généralement cette optimisation.
Lorsqu'un plan est trivial, les phases d'optimisation supplémentaires ne sont pas explorées et les index manquants ne sont pas demandés .
Voir la différence entre ces requêtes et leurs plans :
SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2;
SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2
AND 1 = (SELECT 1);
Le premier plan est trivial et aucune demande n'est affichée. Il peut y avoir des cas où des bogues empêchent les index manquants d'apparaître dans les plans de requête; cependant, ils sont généralement enregistrés de manière plus fiable dans les DMV d'index manquants.
Les prédicats où l'optimiseur ne pourrait pas utiliser un index efficacement même avec un index peuvent les empêcher d'être enregistrés.
Les choses qui ne sont généralement pas SARGable sont:
SELECT *
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 1000) > 1000;
SELECT *
FROM dbo.Users AS u
WHERE DATEDIFF(DAY, u.CreationDate, u.LastAccessDate) > 5000
SELECT *
FROM dbo.Users AS u
WHERE u.UpVotes + u.DownVotes > 10000000
DECLARE @ThisWillHappenWithStoredProcedureParametersToo NVARCHAR(40) = N'Eggs McLaren'
SELECT *
FROM dbo.Users AS u
WHERE u.DisplayName LIKE @ThisWillHappenWithStoredProcedureParametersToo
OR @ThisWillHappenWithStoredProcedureParametersToo IS NULL;
Aucune de ces requêtes n'enregistrera les demandes d'index manquantes. Pour plus d'informations à ce sujet, consultez les liens suivants:
Prenez cet indice:
CREATE INDEX ix_whatever ON dbo.Posts(CreationDate, Score) INCLUDE(OwnerUserId);
Il semble correct pour cette requête:
SELECT p.OwnerUserId, p.Score
FROM dbo.Posts AS p
WHERE p.CreationDate >= '20070101'
AND p.CreationDate < '20181231'
AND p.Score >= 25000
AND 1 = (SELECT 1)
ORDER BY p.Score DESC;
Le plan est une simple recherche ...
Mais parce que la colonne clé principale est pour le prédicat moins sélectif, nous finissons par faire plus de travail que nous ne le devrions:
Tableau "Messages". Nombre de balayages 13, lectures logiques 136890
Si nous changeons l'ordre des colonnes de clé d'index, nous faisons beaucoup moins de travail:
CREATE INDEX ix_whatever ON dbo.Posts(Score, CreationDate) INCLUDE(OwnerUserId);
Et beaucoup moins de lectures:
Tableau "Messages". Nombre de numérisations 1, lectures logiques 5
Dans certains cas, SQL Server choisira de créer un index à la volée via une bobine d'index. Quand un spool d'index est présent, une requête d'index manquante ne le sera pas. L'ajout de l'index vous-même pourrait certainement être une bonne idée, mais ne comptez pas sur SQL Server pour vous aider à le comprendre.