Comment puis-je éliminer un opérateur de recherche de clé (en cluster) dans mon plan d'exécution?
Le tableau tblQuotes
a déjà un index ordonné en clusters (sur QuoteID
) et 27 index non - cluster, donc je suis en train de ne pas créer plus.
J'ai mis la colonne d'index cluster QuoteID
dans ma requête, en espérant que cela aiderait - mais malheureusement toujours la même.
Ou regardez-le:
Voici ce que dit l'opérateur de recherche de clé:
Requete:
declare
@EffDateFrom datetime ='2017-02-01',
@EffDateTo datetime ='2017-08-28'
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data
(
QuoteID int NOT NULL, --clustered index
[EffectiveDate] [datetime] NULL, --not indexed
[Submitted] [int] NULL,
[Quoted] [int] NULL,
[Bound] [int] NULL,
[Exonerated] [int] NULL,
[ProducerLocationId] [int] NULL,
[ProducerName] [varchar](300) NULL,
[BusinessType] [varchar](50) NULL,
[DisplayStatus] [varchar](50) NULL,
[Agent] [varchar] (50) NULL,
[ProducerContactGuid] uniqueidentifier NULL
)
INSERT INTO #Data
SELECT
tblQuotes.QuoteID,
tblQuotes.EffectiveDate,
CASE WHEN lstQuoteStatus.QuoteStatusID >= 1 THEN 1 ELSE 0 END AS Submitted,
CASE WHEN lstQuoteStatus.QuoteStatusID = 2 or lstQuoteStatus.QuoteStatusID = 3 or lstQuoteStatus.QuoteStatusID = 202 THEN 1 ELSE 0 END AS Quoted,
CASE WHEN lstQuoteStatus.Bound = 1 THEN 1 ELSE 0 END AS Bound,
CASE WHEN lstQuoteStatus.QuoteStatusID = 3 THEN 1 ELSE 0 END AS Exonareted,
tblQuotes.ProducerLocationID,
P.Name + ' / '+ P.City as [ProducerName],
CASE WHEN tblQuotes.PolicyTypeID = 1 THEN 'New Business'
WHEN tblQuotes.PolicyTypeID = 3 THEN 'Rewrite'
END AS BusinessType,
tblQuotes.DisplayStatus,
tblProducerContacts.FName +' '+ tblProducerContacts.LName as Agent,
tblProducerContacts.ProducerContactGUID
FROM tblQuotes
INNER JOIN lstQuoteStatus
on tblQuotes.QuoteStatusID=lstQuoteStatus.QuoteStatusID
INNER JOIN tblProducerLocations P
On P.ProducerLocationID=tblQuotes.ProducerLocationID
INNER JOIN tblProducerContacts
ON dbo.tblQuotes.ProducerContactGuid = tblProducerContacts.ProducerContactGUID
WHERE DATEDIFF(D,@EffDateFrom,tblQuotes.EffectiveDate)>=0 AND DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <=0
AND dbo.tblQuotes.LineGUID = '6E00868B-FFC3-4CA0-876F-CC258F1ED22D'--Surety
AND tblQuotes.OriginalQuoteGUID is null
select * from #Data
Plan d'exécution:
Réponses:
Des recherches de clés de différentes saveurs se produisent lorsque le processeur de requêtes doit obtenir des valeurs à partir de colonnes qui ne sont pas stockées dans l'index utilisé pour localiser les lignes requises pour que la requête renvoie des résultats.
Prenons par exemple le code suivant, où nous créons une table avec un seul index:
Nous allons insérer 1 000 000 lignes dans le tableau afin que nous ayons quelques données à utiliser:
Maintenant, nous allons interroger les données avec l'option pour afficher le plan d'exécution "réel":
Le plan de requête montre:
La requête examine l'
IX_Table1
index pour trouver la ligne,Table1ID = 5000000
car la consultation de cet index est beaucoup plus rapide que l'analyse de la table entière à la recherche de cette valeur. Cependant, pour satisfaire les résultats de la requête, le processeur de requêtes doit également trouver la valeur des autres colonnes de la table; c'est là que la "RID Lookup" entre en jeu. Il recherche dans le tableau l'ID de ligne (le RID dans RID Lookup) associé à la ligne contenant laTable1ID
valeur de 500000, obtenant les valeurs de laTable1Data
colonne. Si vous passez la souris sur le nœud "RID Lookup" dans le plan, vous voyez ceci:La "Liste de sortie" contient les colonnes renvoyées par la recherche RID.
Une table avec un index cluster et un index non cluster constitue un exemple intéressant. Le tableau ci-dessous comporte trois colonnes; ID qui est la clé de cluster,
Dat
qui est indexé par un index non-clusterIX_Table
, et une troisième colonne,Oth
.Prenez cet exemple de requête:
Nous demandons à SQL Server de renvoyer chaque colonne de la table où la
Dat
colonne contient le motTest
. Nous avons quelques choix ici; nous pouvons regarder la table (c.-à-d. l'index clusterisé) - mais cela impliquerait de scanner la chose entière puisque la table est ordonnée par laID
colonne, qui ne nous dit rien sur la ou les lignes qui contiennentTest
dans laDat
colonne. L'autre option (et celle choisie par SQL Server) consiste à rechercher dans l'IX_Table1
index non cluster pour trouver la ligne oùDat = 'Test'
, cependant, puisque nous avons également besoin de laOth
colonne, SQL Server doit effectuer une recherche dans l'index cluster à l'aide d'une clé " Rechercher ". Voici le plan pour cela:Si nous modifions l'index non clusterisé pour qu'il inclue la
Oth
colonne:Réexécutez ensuite la requête:
Nous voyons maintenant une seule recherche d'index non cluster, car SQL Server a simplement besoin de localiser la ligne où
Dat = 'Test'
dans l'IX_Table1
index, qui inclut la valeur deOth
, et la valeur de laID
colonne (la clé primaire), qui est automatiquement présente dans chaque non index clusterisé. Le plan:la source
La recherche de clé est due au fait que le moteur a choisi d'utiliser un index qui ne contient pas toutes les colonnes que vous essayez de récupérer. Ainsi, l'index ne couvre pas les colonnes de l'instruction select and where.
Pour éliminer la recherche de clé, vous devez inclure les colonnes manquantes (les colonnes de la liste de sortie de la recherche de clé) = ProducerContactGuid, QuoteStatusID, PolicyTypeID et ProducerLocationID ou une autre méthode consiste à forcer la requête à utiliser l'index clusterisé à la place.
Notez que 27 index non cluster sur une table peuvent être mauvais pour les performances. Lors de l'exécution d'une mise à jour, d'une insertion ou d'une suppression, SQL Server doit mettre à jour tous les index. Ce travail supplémentaire peut affecter négativement les performances.
la source
Vous avez oublié de mentionner le volume de données impliqué dans cette requête. Aussi pourquoi insérez-vous dans une table temporaire? Si seulement vous devez afficher, n'exécutez pas d'instruction d'insertion.
Pour les besoins de cette requête,
tblQuotes
n'a pas besoin de 27 index non clusterisés. Il a besoin d'un index cluster et de 5 index non cluster ou, peut-être de 6 indexex non cluster.Cette requête voudrait des index sur ces colonnes:
J'ai également remarqué le code suivant:
c'est
NON Sargable
-à - dire qu'il ne peut pas utiliser d'index.Pour que ce code le
SARgable
change en ceci:Pour répondre à votre question principale, "pourquoi vous obtenez une clé Rechercher":
Vous obtenez
KEY Look up
parce que certaines des colonnes mentionnées dans la requête ne sont pas présentes dans un index de couverture.Vous pouvez google et étudier
Covering Index
ouInclude index
.Dans mon exemple, supposons que tblQuotes.QuoteStatusID est un index non clusterisé, alors je peux également couvrir DisplayStatus. Puisque vous voulez DisplayStatus dans Resultset. Toute colonne qui n'est pas présente dans un index et qui est présente dans l'ensemble de résultats peut être couverte pour éviter
KEY Look Up or Bookmark lookup
. Voici un exemple d'index couvrant:** Avis de non-responsabilité: ** N'oubliez pas que ci-dessus est seulement mon exemple DisplayStatus peut être couvert avec d'autres non CI après analyse.
De même, vous devrez créer un index et un index de couverture sur les autres tables impliquées dans la requête.
Vous obtenez
Index SCAN
également dans votre plan.Cela peut se produire car il n'y a pas d'index sur la table ou lorsqu'il y a un grand volume de données, l'optimiseur peut décider d'analyser plutôt que d'effectuer une recherche d'index.
Cela peut également se produire en raison de
High cardinality
. Obtention d'un plus grand nombre de lignes que nécessaire en raison d'une jointure défectueuse. Cela peut également être corrigé.la source