J'ai une table, CustPassMaster
avec 16 colonnes, dont une CustNum varchar(8)
, et j'ai créé un index IX_dbo_CustPassMaster_CustNum
. Lorsque je lance ma SELECT
déclaration:
SELECT * FROM dbo.CustPassMaster WHERE CustNum = '12345678'
Il ignore complètement l'index. Cela m'embrouille car j'ai un autre tableau CustDataMaster
avec beaucoup plus de colonnes (55), dont l'une est CustNum varchar(8)
. J'ai créé un index sur cette colonne ( IX_dbo_CustDataMaster_CustNum
) dans cette table, et utilise pratiquement la même requête:
SELECT * FROM dbo.CustDataMaster WHERE CustNum = '12345678'
Et il utilise l'index que j'ai créé.
Y a-t-il un raisonnement spécifique derrière cela? Pourquoi utiliserait-il l'index de CustDataMaster
, mais pas celui de CustPassMaster
? Est-ce dû au faible nombre de colonnes?
La première requête renvoie 66 lignes. Pour le second, 1 ligne est retournée.
Remarque supplémentaire: CustPassMaster
contient 4991 enregistrements et CustDataMaster
5376 enregistrements. Serait-ce le raisonnement derrière l'ignorance de l'index? CustPassMaster
contient également des enregistrements en double qui ont également les mêmes CustNum
valeurs. Est-ce un autre facteur?
Je fonde cette revendication sur les résultats réels du plan d'exécution des deux requêtes.
Voici le DDL pour CustPassMaster
(celui avec l'index inutilisé):
CREATE TABLE dbo.CustPassMaster(
[CustNum] [varchar](8) NOT NULL,
[Username] [char](15) NOT NULL,
[Password] [char](15) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustPassMaster_CustNum] ON dbo.CustPassMaster
(
[CustNum] ASC
) WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Et le DDL pour CustDataMaster
(j'ai omis beaucoup de champs non pertinents):
CREATE TABLE dbo.CustDataMaster(
[CustNum] [varchar](8) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustDataMaster_CustNum] ON dbo.CustDataMaster
(
[CustNum] ASC
)WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Je n'ai pas d'index cluster sur aucune de ces tables, un seul index non cluster.
Ignorez le fait que les types de données ne correspondent pas entièrement au type de données stockées. Ces champs sont une sauvegarde d'une base de données IBM AS / 400 DB2, et ce sont les types de données compatibles pour celle-ci. (Je dois pouvoir interroger cette base de données de sauvegarde avec exactement les mêmes requêtes et obtenir exactement les mêmes résultats.)
Ces données ne sont utilisées que pour les SELECT
déclarations. Je ne fais aucune instruction INSERT
/ UPDATE
/ DELETE
dessus, sauf lorsque l'application de sauvegarde copie des données de l'AS / 400.
la source
Réponses:
En règle générale, les index seront utilisés par SQL Server s'il juge plus judicieux d'utiliser l'index que d'utiliser directement la table sous-jacente.
Il semblerait probable que l'optimiseur basé sur les coûts pense qu'il serait plus coûteux d'utiliser réellement l'indice en question. Vous pouvez le voir utiliser l'index si au lieu de le faire
SELECT *
, vous simplementSELECT T1Col1
.Lorsque vous
SELECT *
dites à SQL Server de renvoyer toutes les colonnes de la table. Pour renvoyer ces colonnes, SQL Server doit lire les pages des lignes qui correspondent auxWHERE
critères d'instruction de la table elle-même (index cluster ou segment de mémoire). SQL Server pense probablement que le nombre de lectures nécessaires pour obtenir le reste des colonnes de la table signifie qu'il pourrait aussi bien analyser directement la table. Il serait utile de voir la requête réelle et le plan d'exécution réel utilisé par la requête.la source
INCLUDE
clause de l'index?INCLUDE
clause obligera probablement SQL Server à utiliser l'index. Cela dit, qu'essayez-vous d'optimiser? Il me semble que si votre table a une taille de ligne moyenne de 100 octets, alors 5000 lignes ne représentent qu'environ 500 Ko de données et ne valent peut-être pas la peine d'être dépensées.Table1
et de 0,53 Ko pourTable2
. Toutes ces données sont importées d'un AS / 400 (IBM System i) et il n'y a AUCUN PK sur quoi que ce soit. J'ai créé manuellement tous les index aujourd'hui après que les gens aient mentionné que l'application est parfois assez lente.Pour utiliser l'index, comme vous le faites
select *
, SQL Server doit d'abord lire chacune des lignes de l'index qui correspondent à la valeur que vous avez dans la clause where. Sur cette base, il obtiendra les valeurs d'index cluster pour chacune des lignes, puis il devra rechercher chacune d'elles séparément de l'index cluster (= recherche de clé). Puisque vous avez dit que les valeurs ne sont pas uniques, SQL Server utilise des statistiques pour estimer le nombre de fois où il doit effectuer cette recherche de clé.Il est très probable que l'estimation des coûts pour l'analyse de l'index non clusterisé + des recherches de clés dépasse l'estimation des coûts pour l'analyse des index clusterisés, et c'est pourquoi l'index est ignoré.
Vous pouvez essayer d'utiliser
set statistics io on
puis utiliser une indication d'index pour voir si le coût d'E / S est réellement inférieur lors de l'utilisation de l'index ou non. Si la différence est importante, vous pouvez consulter les statistiques, si elles sont obsolètes.De plus, si votre SQL utilise réellement des variables et non les valeurs exactes, cela peut également être dû au reniflage des paramètres (= la valeur précédente utilisée pour créer le plan avait beaucoup de lignes dans le tableau).
la source
C'est peut-être la raison. Les optimiseurs sont basés sur le coût et décident du chemin à choisir en fonction du «coût» de chaque chemin d'exécution. Le «plus gros» coût est d'obtenir les données du disque vers la mémoire. Si l'optimiseur calcule qu'il faut plus de temps pour lire à la fois l'index et les données, il peut décider de sauter l'index. Plus les lignes sont grandes, plus elles prennent de blocs de disque.
la source