2009-10-15 7 views
4

J'ai une requête qui fait partie d'un SP qui est exécuté assez régulièrement, et la requête a pris un certain temps à s'exécuter, j'ai donc décidé d'y jeter un coup d'œil. J'ai fait un autotrace sur la requête, et this was the execution plan retourné [collé dans pastebin en raison de la taille excessive]Dégradation des performances d'une requête après l'ajout de l'index

J'ai ajouté des index sur les tables qui subissaient l'accès à la table complète, et a couru la requête. La performance de la requête était pire qu'avant, malgré le cost being significantly lower.

Pourquoi est-ce ainsi, quelqu'un peut-il jeter la lumière sur le même?

La base de données est une Oracle 10gR2 (version 10.2.0.1.0).

C'est la requête en cours d'exécution

SELECT DISTINCT CAC_FLEX_03, CAC_FLEX_04 
     FROM PCOM_CUST_PRACTICE_INFO A, 
      PGIM_ZIP_CODES   C, 
      PGIM_PROD_TARIFF_DATA B, 
      PCOM_CODES_APPL_CODES D 
     WHERE A.PCPI_CUST_CODE IN ('002023', '002025') 
     AND C.ZC_ZIP_CODE = A.PCPI_PIN_CODE 
     AND C.ZC_CITY_CODE = A.PCPI_CITY 
     AND C.ZC_COUNTY_CODE = A.PCPI_COUNTY 
     AND C.ZC_STATE_CODE = A.PCPI_STATE 
     AND B.PTD_CVR_CODE = 'TF-001' 
     AND B.PTD_VALUE_SET2 = A.PCPI_STATE 
     AND B.PTD_VALUE_SET4 = A.PCPI_COUNTY 
     AND B.PTD_VALUE_SET5 = D.CAC_FLEX_03 
     AND D.CAC_FLEX_04 IS NOT NULL 
     AND ZC_STATE_CODE = 
      (SELECT POL_FLEX_04 
       FROM PGIT_POLICY 
       WHERE POL_SYS_ID = 541332) 
     AND B.PTD_VALUE_SET3 = 
      (SELECT POL_FLEX_01 
       FROM PGIT_POLICY 
       WHERE POL_SYS_ID = 541332) 
     AND CAC_TYPE = 'TERR-CODE' 
     AND CAC_FLEX_03 = 0; 
+0

les stats de votre schéma sont-elles à jour? – SeriousCallersOnly

+0

SeriousCallersOnly - Comment puis-je trouver cela? – Sathya

+0

regardez dans user_tables/user_indexes pour les tables/indexes dans votre requête, il y a une colonne "last_analyzed" – SeriousCallersOnly

Répondre

4

Quelques choses:

D'abord, si vous accédez à plus de la moitié des blocs de données, analyse complète sera plus rapide car la lecture du bloc d'index est un autre appel IO, de sorte que la lecture d'une ligne indexée est généralement deux fois aussi coûteux que la lecture d'une ligne séquentielle. Deuxièmement, vous devez regarder vos plans avec et sans l'index. Il y aura des informations ici qui vous permettront de savoir ce qui a changé. Si vous voyez un "Fusionner joindre cartésien", le planificateur a fait une erreur. Ce plan n'est JAMAIS bon. Les boucles internes des analyses complètes ont le même coût d'E/S, mais prennent moins de mémoire et d'espace temporaire. Troisièmement, vous avez construit des statistiques avec ANALYZE TABLE. Ne pas. Même Oracle dit que c'est mauvais et cassé. Utilisez le paquet dbms_stats pour construire vos statistiques, et vous obtiendrez des statistiques plus précises. Si c'est toujours bizarre, changez la taille de votre échantillon, ou faites des statistiques complètes au lieu d'estimer.

0

Nous avons eu un problème similaire et il est avéré être la fragmentation de l'indice. Demandez à votre administrateur de base de données de vérifier toutes les statistiques sur les indices que vous utilisez et de voir s'il est nécessaire de les reconstruire. Rappelez-vous, une reconstruction en ligne vous permettra de continuer pendant un certain temps, mais une reconstruction hors ligne devra probablement être effectuée à un moment donné.

0

Pas de requête "devrait" jamais être affecté par l'ajout d'un nouvel index. Seules les opérations d'écriture (qui ont besoin de modifier l'index) devraient jamais être ralenties par la présence d'un index) Même un index qui a une fragmentation devrait être plus rapide qu'aucun index du tout. Et si vous venez d'ajouter l'index, il est flambant neuf (plus ou moins) et ne devrait pas être fragmenté dans une mesure appréciable. Si l'on ajoute à cela que vous dites que les coûts sont plus bas, je suppose que vous avez quelque chose d'autre qui n'est pas lié à l'indice. Est-il possible que d'autres transactions aient temporairement placé des verrous de lecture sur certaines lignes de données nécessaires à la requête et les aient bloquées pendant une période importante?

+0

Son peu probable, mais je va vérifier et mettre à jour le même. – Sathya

+0

Juste confirmé qu'il n'y a pas de verrous sur l'une des tables – Sathya

+0

@Sathya, les verrous n'existeraient que (et être détectable) tandis que l'autre requête de blocage est active. Une fois terminé, les verrous sont libérés (détruits) et votre requête peut continuer. Après cela, il n'y a aucun moyen (que je sache) de voir quels verrous ont pu exister pendant l'exécution de la requête. La seule façon est d'exécuter une trace ou un moniteur pendant que la requête exécute cette activité de verrouillage d'enregistrements. Je ne suis pas sûr de savoir comment faire cela dans Oracle. –

0

Semblable à ce que Charles Brentana a déclaré, l'ajout d'un index ne devrait pas dégrader les performances d'une requête.

Cela serait vrai si toutes les statistiques étaient à jour, de sorte que l'optimiseur basé sur les coûts choisisse un bon plan d'exécution. Encore une fois, s'il vous plaît vérifiez les statistiques, à la fois sur les tables et les index.

Si tout est kascher là, je ne peux que supposer qu'il y a un autre facteur qui affecte les performances de la requête. Existe-t-il un autre chargement (travail par lots long, sauvegarde, etc.) sur le serveur de base de données afin que la requête s'exécute plus longtemps? Y a-t-il une activité majeure de mise à jour sur l'une des tables que vous utilisez dans la requête? Les données ont-elles été dans le cache db la première fois mais pas la deuxième fois? Je n'ai aucune idée de comment vous pouvez tester les deux déclarations côte à côte, mais il doit y avoir une raison pour ce comportement étrange ...

+0

Il n'y a pas d'autre charge, pas de travail de sauvegarde, de travail planifié, pas de mise à jour. J'ai vérifié deux fois, comme mentionné les stats étaient obsolètes et ont été reconstruit – Sathya

2

J'ai vu les requêtes devenir plus lentes de cette façon où la table indexée était petit. Le plan de requête est passé de la construction d'une table de hachage temporaire à l'utilisation de l'index (basé sur l'arbre), qui était plus lent (mais qui serait plus évolutif). Les optimiseurs basés sur les coûts ne sont pas toujours corrects avec les statistiques disponibles, en effet ils ne le peuvent pas si vous y réfléchissez. Pour un plan de requête suffisamment complexe, il ne sera pas possible de prédire parfaitement les performances sans faire la requête.

+0

> il ne sera pas possible de prédire parfaitement la performance > sans faire la requête. J'ai exécuté la requête, prend environ 112 secondes en moyenne, avec l'index. Publiera bientôt des statistiques exactes – Sathya

0

Vous devez être conscient que l'optimiseur basé sur les coûts, tout en étant assez sophistiqué et la plupart du temps correct, peut parfois être erroné.

Il existe de nombreuses publications spécifiques à Oracle (voir par exemple le blog de Tom Kyte) qui prouvent clairement que l'ajout d'un index peut en fait réduire les performances des instructions SELECT. Entre autres raisons, l'accès à un ensemble de données par index peut être plus coûteux que de le faire par un balayage complet si la densité des données est suffisamment élevée. Parfois, vous pouvez faire prendre conscience à l'optimiseur basé sur les coûts de la distribution des données en générant des histogrammes pour les colonnes impliquées, mais même cela peut parfois échouer. Je vais d'abord essayer de générer les histogrammes pour les colonnes indexées. Si cela échoue, nous devrons revoir votre instruction et votre plan d'accès.

1

Juste pour l'intérêt, la table PGIM_ZIP_CODES est-elle vraiment requise dans la requête? Il me semble que changer "AND ZC_STATE_CODE =" [ligne 16 du sql] à "et A.PCPI_STATE =" vous permet de supprimer PGIM_ZIP_CODES du corps de la requête. Deuxièmement, il semble que l'index créé sur PGIM_PROD_TARIFF_DATA a échoué à faire le travail correctement - dans mon expérience limitée, une table avec seulement 78k lignes est normalement plus rapide à scanner sauf si l'index ajouté est unique ou réduit le plan pour cette table à une recherche index seulement (le deuxième plan ressemble à 2 index ont été créés sur la table, et ils n'étaient pas uniques). Troisièmement, maintenant que j'ai regardé un peu plus difficile. il ressemble à votre requête pourrait résoudre à:

sélectionner CAC_FLEX_03 distincts, CAC_FLEX_04

de PCOM_CODES_APPL_CODES

où CAC_FLEX_03 = 0

et CAC_TYPE = 'TERR CODE'

où existe (bla bla bla)

  • toujours assum ing que le où existe est nécessaire - parce que l'existence d'une ligne de résultat de la table A, B et C sera en effet retourner toutes les lignes du tableau D avec CAC_FLEX_03 = 0 et TYPE = « TERR CODE »

PS Je n'ai pas mal compris la question!

Questions connexes