2009-09-25 5 views
5

J'essaie de déboguer une procédure stockée assez complexe qui se joint à de nombreuses tabls (10-11). Je vois que pour une partie de l'arbre, le nombre estimé de lignes diffère radicalement du nombre réel de lignes - dans le pire des cas, le serveur SQL estime qu'une ligne sera retournée, alors qu'en réalité, 55 000 lignes sont retournées! Je cherche à comprendre pourquoi - toutes mes statistiques sont à jour, et j'ai mis à jour les statistiques avec un FULLSCAN sur plusieurs tables. Je n'utilise aucune fonction définie par l'utilisateur ou aucune variable de table. Autant que je puisse voir SQL Server devrait être capable d'estimer exactement combien de lignes vont être retournées, mais il continue à choisir un plan qui le cas pour effectuer des dizaines de milliers de recherches RDI (quand il s'attend à effectuer seulement 1 ou 2).Comment le serveur SQL calcule-t-il le nombre estimé de lignes?

Que puis-je faire pour essayer de comprendre pourquoi le nombre estimé de lignes est si important?

MISE À JOUR: Ainsi, la recherche au plan que j'ai trouvé un nœud en particulier qui semble suspicous - sa table scan sur une table à l'aide predecate suivante:

status <> 5 
AND [type] = 1 
OR [type] = 2 

Ce prédicat renvoie le tableau entier (630 lignes - la table se scanne elle-même PAS la source de la mauvaise performance) Cependant le serveur SQL a le nombre estimé de lignes à seulement 37. SQL Server continue ensuite à faire plusieurs boucles imbriquées avec ceci sur les recherches RDI, index scans et index cherche. Cela pourrait-il être la source de mon erreur de calcul massive? Comment l'obtenir pour estimer un nombre plus raisonnable de lignes?

+0

Pourriez-vous publier votre définition de table et la requête complète? – Quassnoi

+0

Désolé, mais pas vraiment - c'est trop grand (250 lignes sp + 10 tables). – Justin

+3

Si votre prédicat est exactement comme cela (pas de parenthèses) alors vous pouvez avoir un problème de logique. ET a la priorité sur OU. Devrait être [état] <> 5 ET (type = 1 OU type = 2) – GilaMonster

Répondre

8

SQL Server divise chaque index dans les plages allant jusqu'à 200 avec les données suivantes (de): here

  • RANGE_HI_KEY

    Une valeur de clé montrant la limite supérieure d'un pas d'histogramme.

  • RANGE_ROWS

    Indique le nombre de lignes sont à l'intérieur de la plage (ils sont plus petits que ce RANGE_HI_KEY, mais plus grand que le plus petit RANGE_HI_KEY précédent).

  • EQ_ROWS

    Indique le nombre de lignes sont exactement égales à RANGE_HI_KEY.

  • AVG_RANGE_ROWS

    Nombre moyen de lignes par valeur distincte à l'intérieur de la gamme.

  • DISTINCT_RANGE_ROWS

    Indique le nombre de valeurs clés distinctes sont à l'intérieur de cette plage (non compris la clé précédente avant RANGE_HI_KEY et RANGE_HI_KEY lui-même);

Habituellement, les valeurs les plus peuplées vont dans RANGE_HI_KEY. Cependant, ils peuvent entrer dans la plage, ce qui peut conduire à la distribution asymétrique.

Imaginez ces données (entre autres):

valeur clé Nombre de lignes

1   1 
2   1 
3   10000 
4   1 

SQL Server construit habituellement deux gammes: 1 à 3 et 4 à la valeur suivante peuplée, ce qui rend ces statistiques :

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
3    2   10000 1    2 

, ce qui signifie que lors de la recherche, par exemple, 2, il n'y a plus 1 et il est préférable d'utiliser l'accès à l'index.

Mais si 3 va à l'intérieur de la gamme, les statistiques sont les suivantes:

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
4    10002  1  3334   3 

L'optimiseur pense qu'il ya 3334 lignes pour la 2 clé et accès à l'index est trop cher.

+0

Comment pouvons-nous résoudre ce problème même si la mise à jour des statistiques avec analyse complète ne pouvait pas le résoudre? – Meysam

+0

@Maysam: vous pouvez utiliser 'CREATE STATISTICS' pour les prédicats que vous utilisez souvent. – Quassnoi

3

Il utilise des statistiques, qu'il conserve pour chaque indice.

(Vous pouvez également créer des statistiques sur des colonnes non indexées)

Pour mettre à jour toutes vos statistiques sur toutes les tables dans une base de données (AVERTISSEMENT:. Prendra un certain temps sur les bases de données très importantes Ne pas faire sur les serveurs de production sans vérifier avec votre DBA ...):

exec sp_msforeachtable 'UPDATE STATISTICS ?' 

Si vous n'avez pas régulièrement tâche planifiée pour reconstruire vos index les plus actifs (c.-à beaucoup d'insérer ou de supprimer), vous devriez envisager la reconstruction de votre indices (même mise en garde que ci-dessus):

exec sp_msforeachtable "DBCC DBREINDEX('?')" 
0

La reconstruction de vos index peut résoudre le problème de la valeur estimée des lignes incorrectes

Questions connexes