Pourquoi SQL Server n'a-t-il pas de demandes d'index manquantes dans les DMV ou les plans de requête?

14

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?

Erik Darling
la source

Réponses:

17

Il y a de nombreuses raisons pour lesquelles vous ne manquez pas de demandes d'index!

Nous examinerons quelques-unes des raisons plus en détail et parlerons également de certaines des limites générales de la fonctionnalité.

Limitations générales

Tout d'abord, à partir de: Limitations de la fonction d'index manquants :

  • Il ne spécifie pas d'ordre pour les colonnes à utiliser dans un index.

Comme indiqué dans ce 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 Égalité vs Inégalité, puis par la position ordinale des colonnes dans le tableau.

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:

  • Clustered
  • Filtré
  • Partitionné
  • Comprimé
  • XML-ed
  • Spatial-ed
  • Columnstore-d
  • Affichage indexé

Quelles colonnes sont prises en compte?

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:

  • JOINS
  • Clause WHERE

Les colonnes incluses dans l'index manquant sont générées à partir des colonnes requises par la requête, comme celles de:

  • SÉLECTIONNER
  • PAR GROUPE
  • COMMANDÉ PAR

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;

DES NOISETTES

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

DES NOISETTES

Cela ne semble pas très utile!

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.

Vous ne m'avez toujours pas dit pourquoi je ne les ai pas, cependant ...

Détendez-vous, bucko. Nous y arrivons.

Trace Flags

Si vous activez TF 2330 , les demandes d'index manquantes ne seront pas enregistrées. Pour savoir si vous l'avez activé, exécutez ceci:

DBCC TRACESTATUS;

Reconstructions d'index

La reconstruction des index effacera les demandes 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 voudrez peut-être également réfléchir à la raison pour laquelle la défragmentation de vos index n'aide pas , de toute façon. Sauf si vous utilisez Columnstore .

Ajout, suppression ou désactivation d'index

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.

Plans triviaux

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 effectivement que l'optimiseur n'a pas pris de décisions basées 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 .

Voyez 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);

DES NOISETTES

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.

SARGabilité

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 SARGables sont:

  • Colonnes enveloppées dans des fonctions
  • Colonne + SomeValue = SomePredicate
  • Column + AnotherColumn = SomePredicate
  • Colonne = @Variable OU @Variable IS NULL

Exemples:

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:

Vous avez déjà un index correct

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 ...

DES NOISETTES

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 la clé d'index, nous faisons beaucoup moins de travail:

CREATE INDEX ix_whatever ON dbo.Posts(Score, CreationDate) INCLUDE(OwnerUserId);

DES NOISETTES

Et beaucoup moins de lectures:

Tableau «Messages». Nombre de scans 1, lectures logiques 5

SQL Server crée des index pour vous

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.

DES NOISETTES

Erik Darling
la source