2012-03-24 1 views
1

Je possède ce tabulaires (tableA):Sql Server faire une analyse complète de la table lorsque premier champ PK a quelques valeurs distinctes

(
    [FieldA] [int] NOT NULL, 
    [FieldB] [int] NOT NULL, 
    [Value] [float] NULL 
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [FieldA] ASC, 
    [FieldB] ASC 
) 

Il y a quelques valeurs FieldA distinctes, permet de dire FieldA peut être {1,2 , 3,4,5,6}.

Pourquoi cette requête provoque un scan de table:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1 

Bien que cela ne fait pas:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1 where FieldA in (1,2,3,4,5,6) 

Impossible Sql Server optimize cela? Si j'avais TableB où FieldA était un PK et que je rejoignais TableB et TableA, la requête serait exécutée de manière similaire à la deuxième requête.

+0

La deuxième version n'effectue pas un balayage de table complet vraisemblablement parce qu'il y a plus de valeurs dans la colonne A que '1,2,3,4, 5,6' - ou du moins il pourrait y avoir. La première version n'autorise pas l'optimiseur à affiner à une plage quelconque parce que vous n'avez pas inclus la colonne de clé, il doit donc vérifier chaque ligne. Si vous ajoutez un index non cluster avec FieldB comme colonne principale, vous devriez voir des performances/comportements différents. –

+2

Une bonne analogie pour un index à deux colonnes est un annuaire téléphonique. Ceci est ordonné par 'lastname, firstname'. Votre première requête est analogue à essayer et trouver tout le monde appelé "John" dans le livre. La commande par nom de famille n'aide pas. Si la seconde requête finit par faire plusieurs recherches qui finissent par renvoyer toutes les lignes, ce n'est pas plus efficace qu'une analyse complète. –

+0

Un index composé peut être utilisé chaque fois que vous interrogez les n membres les plus à gauche de celui-ci. Donc dans votre cas: votre clé primaire composée aide pour les requêtes avec 'FieldA', ou pour les requêtes avec' FieldA' et 'FieldB' - mais elle ** NE PEUT JAMAIS être utilisée pour les requêtes utilisant uniquement' FieldB'. En spécifiant deux colonnes dans la clé composée ** NE PAS ** signifier que vos recherches pour chacune de ces colonnes (séparément) seront accélérées. –

Répondre

1

Apparemment, ce que je cherchais, c'est une optimisation skip-scan qui est disponible sur Oracle mais pas sur SQL Server. L'analyse de saut peut utiliser un index si le prédicat de colonne de bord d'attaque est manquant: http://social.msdn.microsoft.com/Forums/eu/transactsql/thread/48de15ad-f8e9-4930-9f40-ca74946bc401

+0

Cette réponse est correcte. Il y a un article Microsoft Connect qui peut être voté sur: https://connect.microsoft.com/SQLServer/feedback/details/695044/implement-index-skip-scan – usr

1

L'index cluster que vous avez créé est basé sur deux colonnes. Si vous effectuez une recherche sur une seule de ces colonnes, SQL Server ne peut pas générer de valeur "clé" à utiliser dans le processus de recherche sur cet index, il revient donc à une approche d'analyse de table.

Même si FieldA a une très petite plage de valeurs qu'il peut contenir, l'optimiseur SQL ne regarde pas cette plage de valeurs pour déterminer s'il peut "fudger" une clé des informations que vous lui avez données.

Si vous souhaitez améliorer les performances de la première requête, vous devrez créer un autre index sur FieldB. Si, comme vous le dites, il n'y a pas beaucoup de valeurs distinctes dans FieldA, et que vous effectuez la plupart de vos recherches sur un FieldB exclusivement, vous pouvez envisager de déplacer votre index cluster pour construire uniquement sur FieldB et générer un index unique sur FieldA et FieldB.

+1

ou simplement changer l'ordre des colonnes de la clé primaire lors de la création de la table PRIMARY KEY CLUSTERED ( [FieldB] ASC, [FieldA] ASC ) cela permettra de garder la clé primaire 2 colonne et utilisez les PK indices si la requête utilise uniquement le champB – Kharaone

Questions connexes