Question

J'ai ce tableau:

create table demo (
    key number(10) not null,
    type varchar2(3) not null,
    state varchar2(16) not null,
    ... lots more columns ...
)

Et cet index:

create index demo_x04 on demo(key, type, state);

Quand j'exécute cette requête

select * from demo where key = 1 and type = '003' and state = 'NEW'

EXPLAIN PLAN montre qu'il fait une analyse de table complète. J'ai donc laissé tomber l'index et l'ai à nouveau créé. EXPLAIN PLAN Dit toujours la numérisation complète de la table. Comment cela peut-il être?

Quelques antécédents: ce sont des données historiques, donc ce qui se passe, c'est que je regarde une rangée avec l'état CLEARED et insérer une nouvelle ligne avec l'état NEW (plus je copie quelques valeurs de l'ancienne ligne). L'ancienne rangée est ensuite mise à jour pour USED. Donc, la table grandit toujours. Ce que j'ai remarqué, c'est que la cardinalité de l'indice est 0 (malgré le fait que j'ai des milliers de valeurs différentes). Après avoir recréé, la cardinalité a augmenté, mais le CBO n'a pas aimé l'index.

Le lendemain matin, Oracle a soudainement aimé l'index (probablement dormi dessus) et a commencé à l'utiliser mais pas longtemps. Après un certain temps, le traitement est passé de 50 lignes / s à 3 lignes / s et j'ai revu "Scan de table complète". Que se passe-t-il?

Dans mon cas, je dois traiter environ un million de lignes. Je commette les changements dans les lots de ca. 50. Y a-t-il une commande que je devrais exécuter après un engagement à mettre à jour / réorg l'index ou quelque chose comme ça?

Je suis sur Oracle 10G.

Modifier] J'ai 969'491 clés distinctes dans ce tableau, 3 types et 3 états.

Était-ce utile?

La solution

Que se passe-t-il si vous spécifiez un indice d'index? Essaye ça:

SELECT /*+ INDEX (demo demo_x04) */ * 
  FROM demo 
 WHERE key = 1 
   AND type = '003' 
   AND state = 'NEW';

Il semble que ce qui s'est passé du jour au lendemain, c'est que la table a été analysée. Ensuite, au fur et à mesure que vous exécutez votre traitement par rapport à la table, suffisamment de l'index a été mis à jour pour provoquer à nouveau les statistiques du tableau d'Oracle et l'optimiseur a cessé d'utiliser l'index.

Ajoutez l'indice et voyez si Explication Plan vous donne un plan différent et la requête fonctionne mieux.

Oh, et la réponse de Tony concernant l'analyse du tableau est une bonne pratique générale, bien qu'avec 10g, la base de données est assez bonne à faire l'auto-maintenance à cet égard. Si votre processus fait de nombreuses mises à jour, l'index peut être périmé rapidement. Si l'exécution d'analyse lorsque votre processus commence à aller dans le fossé améliore la situation pendant un certain temps, vous saurez alors que c'est le problème.

Pour mettre à jour les statistiques pour le tableau, utilisez le dmbs_stats.gather_table_stats forfait.

Par exemple:

exec dbms_stats.gather_table_stats ('le propriétaire', 'démo');

Autres conseils

Le tableau a-t-il été analysé récemment? Si Oracle pense qu'il est très petit, il peut même ne pas envisager d'utiliser l'index.

Essaye ça:

select last_analyzed, num_rows 
from user_tables
where table_name = 'DEMO';

NUM_ROWS vous dit combien de lignes Oracle pense que le tableau contient.

"Le lendemain matin, Oracle a soudainement aimé l'index (probablement dormi dessus)" probablement un DBMS_STATS fonctionne pendant la nuit.

Généralement, je verrais l'une des trois raisons pour une numérisation complète sur un index. La première est que l'optimiseur pense que la table est vide, ou du moins très petite. Je soupçonne que c'était le problème initial. Dans ce cas, il serait plus rapide de scanner complet un tableau composé d'une poignée de blocs plutôt que d'utiliser un index.

La seconde est lorsque la requête est telle qu'un index ne peut pas être pratiquement utilisé.

"select * from demo where key = 1 and type = '003' and state = 'NEW'"

Utilisez-vous réellement des littéraux codés en dure dans la requête. Sinon, vos données variables peuvent être incorrectes (par exemple, le caractère de la clé de la clé). Cela nécessiterait que la clé numérique soit convertie en caractère pour comparaison, ce qui rendrait l'indice presque inutile.

La troisième raison est où il pense que la requête traitera une grande proportion des lignes du tableau. Le type et l'état semblent assez faibles. Avez-vous peut-être un grand nombre d'une valeur de «clé» spécifique?

Un commentaire sur le traitement que vous décrivez: il semble que vous effectuiez un traitement en ligne par rangée avec des engins intermittents, et je vous exhorte à repenser cela si vous le pouvez. Le mécanisme de mise à jour / insertion peut bien être converti en une instruction Merge et l'ensemble de données peut ensuite être traité dans une seule déclaration avec un engagement à la fin. Ce serait presque certainement plus rapide et utiliserait moins de ressources que votre méthode actuelle.

La valeur de la clé de colonne est-elle toujours 1? Si c'est le cas, je ne suis pas sûr que la consultation de l'index optimiserait la requête, car chaque ligne devrait être examinée de toute façon. Si c'est le cas, déclarez l'index sans la colonne de clé. Vous pouvez également essayer:

select key, type, state from demo where key = 1 and type = '003' and state = 'NEW'

Ce qui (si ma supposition est juste) devrait toujours regarder chaque ligne, mais qui pourrait aller à l'index car toutes les colonnes du jeu de résultats sont désormais couvertes.

Je devine en fonction de votre déclaration que l'index montre la cardinalité 0.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top