【发布时间】:2021-10-23 13:54:17
【问题描述】:
我试图找到类似的问题,但没有找到。如果这是重复的,请指出正确的主题。
Oracle 版本 19 标准版 2,版本 19.3。
我有一张桌子正在预订。 部分专栏:
| COLUMN_NAME | DATA_TYPE | NULLABLE |
|---|---|---|
| ID | NUMBER(38,0) | No |
| CLASSID | NUMBER(5,0) | Yes |
| PARENTFOREIGNKEY | NUMBER(38,0) | Yes |
| BOOKINGNO | NUMBER(4,0) | Yes |
它有以下索引(对这个问题很重要):
| INDEX_NAME | UNIQUENESS | STATUS | INDEX_TYPE | COLUMNS |
|---|---|---|---|---|
| BOOKING | UNIQUE | VALID | NORMAL | ID |
| BOOKING_511_2 | NONUNIQUE | VALID | NORMAL | PARENTFOREIGNKEY, CLASSID, ID |
执行查询
SELECT * FROM BOOKING WHERE (CLASSID=511) AND PARENTFOREIGNKEY=31647961 ORDER BY BOOKINGNO;
大约需要 40-45 秒。
然而
SELECT * FROM BOOKING WHERE PARENTFOREIGNKEY=31647961 AND (CLASSID=511) ORDER BY BOOKINGNO;
只需要大约 0.013 秒。
很明显,第一个查询没有使用索引,而第二个查询是。说明计划是相同的。
| 0 | SELECT STATEMENT | | 4 | 648 | 9 (12)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 648 | 9 (12)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| BOOKING | 4 | 648 | 8 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | BOOKING_511_2 | 4 | | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("PARENTFOREIGNKEY"=31647961 AND "CLASSID"=511)
谁能告诉我这是怎么回事?为什么两个查询在执行中不等效?
谢谢你, GG
编辑:
解释计划 (SELECT * FROM TABLE(dbms_xplan.display_cursor(format => 'BASIC +PREDICATE'));):
EXPLAINED SQL STATEMENT:
------------------------
SELECT * FROM BOOKING WHERE (CLASSID=:"SYS_B_0") AND
PARENTFOREIGNKEY=:"SYS_B_1" ORDER BY BOOKINGNO
Plan hash value: 1769702959
----------------------------------------------------
| Id | Operation | Name |
----------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT ORDER BY | |
|* 2 | TABLE ACCESS FULL| BOOKING |
----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("PARENTFOREIGNKEY"=:SYS_B_1 AND "CLASSID"=:SYS_B_0))
“快速”查询:
EXPLAINED SQL STATEMENT:
------------------------
SELECT * FROM BOOKING WHERE PARENTFOREIGNKEY=:"SYS_B_0"
AND (CLASSID=:"SYS_B_1") ORDER BY BOOKINGNO
Plan hash value: 3357352015
--------------------------------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT ORDER BY | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| BOOKING |
|* 3 | INDEX RANGE SCAN | BOOKING_511_2 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("PARENTFOREIGNKEY"=:SYS_B_0 AND "CLASSID"=:SYS_B_1)
【问题讨论】:
-
请提供两个实际执行计划,并在语句执行后立即执行
dbms_xplan.display_cursor(format => 'BASIC +PREDICATE)。我无法在 db<>fiddle 中重现您的行为 -
所以第一个查询跑得慢,第二个跑得快。如果您再次运行第一个查询,它会再次变慢吗?
-
@pmdba:是的,行为是一致的。所以,反应慢又慢,快又快(又快又慢……所有的组合都试过了,重复了)
-
@GoranGerlič 再次生成执行计划,但这次使用
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);。 “BASIC”格式不会显示“Note”部分,这对于调试计划问题可能很关键。通常,谓词顺序无关紧要。最常见的例外情况是,如果 DBA 创建了仅适用于一个特定 SQL_ID 的 SQL 配置文件,将在“注意”部分进行说明。