J'ai fait face à une situation embarrassante. Une requête avait un bon plan d'exécution. Mais lorsque cette requête a été utilisée comme une requête interne dans une requête plus importante, ce plan a changé. J'essaie de comprendre pourquoi cela pourrait être ainsi.Le plan d'exécution de la requête interne est différent lorsqu'il est exécuté dans le cadre d'une requête plus importante.
C'était sur Oracle 11g. Ma requête était:
SELECT * FROM YFS_SHIPMENT_H
WHERE SHIPMENT_KEY IN
(
SELECT DISTINCT SHIPMENT_KEY
FROM YFS_SHIPMENT_LINE_H
WHERE ORDER_HEADER_KEY = '20150113083918815889858'
OR (ORDER_LINE_KEY IN ( '20150113084438815896336'))
);
Comme vous pouvez le voir, il y a une requête intérieure ici, qui est la suivante:
SELECT DISTINCT SHIPMENT_KEY
FROM YFS_SHIPMENT_LINE_H
WHERE ORDER_HEADER_KEY = '20150113083918815889858'
OR (ORDER_LINE_KEY IN ( '20150113084438815896336'))
Quand je lance juste la requête interne, je reçois le plan d'exécution comme:
PLAN_TABLE_OUTPUT
========================================================================================================
SQL_ID 3v82m4j5tv1k3, child number 0
=====================================
SELECT DISTINCT SHIPMENT_KEY FROM YFS_SHIPMENT_LINE_H WHERE
ORDER_HEADER_KEY = '20150113083918815889858' OR (ORDER_LINE_KEY IN (
'20150113084438815896336'))
Plan hash value: 3691773903
========================================================================================================
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
========================================================================================================
| 0 | SELECT STATEMENT | | | | 10 (100)| |
| 1 | HASH UNIQUE | | 7 | 525 | 10 (10)| 00:00:01 |
| 2 | CONCATENATION | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_LINE_H | 1 | 75 | 4 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | YFS_SHIPMENT_LINE_H_I4 | 1 | | 3 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_LINE_H | 6 | 450 | 5 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | YFS_SHIPMENT_LINE_H_I6 | 6 | | 3 (0)| 00:00:01 |
========================================================================================================
Predicate Information (identified by operation id):
===================================================
4 = access("ORDER_LINE_KEY"='20150113084438815896336')
5 = filter(LNNVL("ORDER_LINE_KEY"='20150113084438815896336'))
6 = access("ORDER_HEADER_KEY"='20150113083918815889858')
le plan d'exécution montre que le tableau est accessible YFS_SHIPMENT_LINE_H avec deux index YFS_SHIPMENT_LINE _H_I4 et YFS_SHIPMENT_LINE_H_I6; puis les résultats sont concaténés. Ce plan semble bien et le temps de réponse de la requête est génial.
Mais quand je lance la requête complète, le chemin d'accès des modifications de la requête interne comme donné ci-dessous:
PLAN_TABLE_OUTPUT
=======================================================================================================
SQL_ID dk1bp8p9g3vzx, child number 0
=====================================
SELECT * FROM YFS_SHIPMENT_H WHERE SHIPMENT_KEY IN (SELECT DISTINCT
SHIPMENT_KEY FROM YFS_SHIPMENT_LINE_H WHERE ORDER_HEADER_KEY =
'20150113083918815889858' OR (ORDER_LINE_KEY IN (
'20150113084438815896336')))
Plan hash value: 3651083773
=======================================================================================================
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
=======================================================================================================
| 0 | SELECT STATEMENT | | | | 12593 (100)| |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 7 | 6384 | 12593 (1)| 00:02:32 |
| 3 | SORT UNIQUE | | 7 | 525 | 12587 (1)| 00:02:32 |
|* 4 | INDEX FAST FULL SCAN | YFS_SHIPMENT_LINE_H_I2 | 7 | 525 | 12587 (1)| 00:02:32 |
|* 5 | INDEX UNIQUE SCAN | YFS_SHIPMENT_H_PK | 1 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_H | 1 | 837 | 2 (0)| 00:00:01 |
=======================================================================================================
Predicate Information (identified by operation id):
===================================================
4 = filter(("ORDER_HEADER_KEY"='20150113083918815889858' OR
"ORDER_LINE_KEY"='20150113084438815896336'))
5 = access("SHIPMENT_KEY"="SHIPMENT_KEY")
S'il vous plaît noter que le YFS_SHIPMENT_LINE_H est maintenant accessible avec un indice différent (YFS_SHIPMENT_LINE_H_I2). Comme il s'avère, ce n'est pas un très bon index et le temps de réponse de la requête souffre.
Ma question est: Pourquoi le plan d'exécution de requête interne changerait-il lorsqu'il est exécuté dans le cadre de la requête plus grande? Une fois que l'optimiseur a trouvé le meilleur moyen d'accéder à YFS_SHIPMENT_LINE_H, pourquoi ne continuerait-il pas à utiliser le même plan d'exécution même s'il fait partie de la requête plus grande?
Remarque: Je ne suis pas trop préoccupé par ce qui serait le bon chemin d'accès ou l'index à utiliser; et par conséquent ne pas donner tous les index sur la table ici; et la cardinalité des données. Ma préoccupation concerne le changement lorsqu'il est exécuté séparément par rapport à une autre requête.
Merci.
- Parag
Vous avez raison, la requête peut en effet se faire d'une manière différente. Celui-ci se trouve être dans un code que je ne peux pas changer. ...... Aussi, vous faites un bon point sur ne pas avoir à utiliser 'distinct' dans le cadre de la clause' in'. –