J'essaie de compter le nombre de commandes passées par une certaine organisation sur une certaine gamme de temps. Mais j'ai constaté que la requête ci-dessous (gamme de temps de 2 jours) est beaucoup plus lente qui fait deux requêtes séparées chaque jour.
SELECT COUNT(*) FROM ORDER_HISTORY
WHERE organization = 'BA' AND TIMESTAMP > = TO_DATE('2016-01-05', 'YYYY-MM-DD')
AND TIMESTAMP<= TO_DATE('2016-01-05', 'YYYY-MM-DD')+2;
J'ai un index sur la colonne timestamps
et un autre index sur la colonne organization
Voici le schéma de ma table. La colonne timestamp
est de type DATE
.
Le plan d'exécution de la requête sur 2 jours utilise l'index sur organization
:
Le plan d'exécution de la requête sur 1 jour utilise l'index sur timestamp
:
Avoir des statistiques:
SELECT COUNT(*) FROM ORDER_HISTORY
WHERE ORGANIZATION = 'BA' ;
donne 2359847.
SELECT COUNT(*) FROM ORDER_HISTORY
WHERE TIMESTAMP > = TO_DATE('2016-01-05', 'YYYY-MM-DD')
AND TIMESTAMP<= TO_DATE('2016-01-05', 'YYYY-MM-DD')+1;
donne 9260. Et la même requête sur 2 jours donne 16510.
Pourquoi pourrais-je obtenir le genre de comportement étrange du moteur Oracle DB?
La raison en est que l'optimiseur basé sur les coûts a un plan en mémoire à partir d'une sélection précédente, où le nombre d'enregistrements d'une organisation donnée, à savoir "lol", était beaucoup plus petit, quelque 14 000. Lorsque le plan est en mémoire, le CBO Ne se soucie pas des valeurs de paramètre plus. Utilisation:
WHERE organization || '' = 'BA'
Il me semble que les statistiques d'optimiseur sont soit obsolètes, soit une bibliothèque de données (c'est-à-dire que vous avez une colonne populaire et impopulaire dans une colonne d'organisation). Optimizer estime que le filtre ORGANIZATION = 'BA'
Retourne 14898 rangées qui sont bien différentes du résultat réel. dbms_stats.gather_table_stats
devrait résoudre le problème. ** Selon la capture d'écran, il semble que "lol" est une valeur d'organisation utilisée avec EXPLAIN
, je suggérerais d'afficher un plan d'exécution réel.
Vous pouvez également créer des statistiques étendues sur 2 colonnes (organisation, horodatage).
En outre, vérifiez toujours le plan d'exécution réel (dbms_xplan.display_cursor
), pas le résultat de explain
.
((( mise à jour
Une autre chose qui peut aider à enquêter sur le problème. Je suggère également de trouver une requête (ou des requêtes) dans v$sql
/v$sqlarea
et vérifier leurs coûts. Également, v$sql
possède is_bind_aware
et is_bind_sensitive
colonnes qui indiquent si Optimizer considère et utilise différents plans dépend de différentes valeurs de variables de liaison. Autres détails sur la raison pour laquelle plusieurs plans ont été générés V$SQL_SHARED_CURSOR
Vue du système qui montre pourquoi le curseur enfant existant n'a pas été partagé avec un nouveau.