[20250619]21c使用or_expand提示.txt
[20250619]21c使用or_expand提示.txt
--//生产系统遇到的问题,我以为以前在21c下测试通过的方法在19c上可以通过,结果不行,有必要重复在21c重复测试看看。
1.环境:
SCOTT@book01p> @ ver2
==============================
PORT_STRING : x86_64/Linux 2.4.xx
VERSION : 21.0.0.0.0
BANNER : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID : 0
PL/SQL procedure successfully completed.
2.测试环境建立:
--//drop table t1 purge ;
--//drop table t2 purge ;
create table t1 as select * from all_objects;
create table t2 as select * from all_objects;
create index i_t1_object_id on t1(object_id);
create index i_t2_object_id on t2(object_id);
create index i_t1_object_name on t1(object_name);
create index i_t2_object_name on t2(object_name);
create index i_t1_CREATED on t1(CREATED );
create index i_t2_CREATED on t2(CREATED );
--//分析表略。
$ cat f4.txt
set term off
variable v_id number ;
variable v_id1 number ;
variable v_name varchar2(20) ;
variable startdate varchar2(32) ;
variable enddate varchar2(32) ;
exec :v_id := 76191;
--exec :v_name := NULL;
exec :startdate := '2024-08-16 00:00:00'
exec :enddate := '2024-08-17 00:00:00'
set term on
SELECT /*+ &&1 */
t1.object_id
,t1.object_name
,t1.object_type
,t2.object_id
,t2.object_name
,t2.object_type
FROM t1 LEFT JOIN t2 ON t1.object_id = t2.object_id
WHERE t1.created >= SYSDATE - 360
AND ( ( :v_id = '' OR :v_id IS NULL) OR t2.object_id = :v_id)
AND ( ( :StartDate = '' OR :StartDate IS NULL) OR t2.CREATED >= :StartDate)
AND ( ( :EndDate = '' OR :EndDate IS NULL) OR t2.CREATED <= :EndDate);
--//做一个接近生产系统的例子,真实的生产系统语句基本类似(只不过查询SYSDATE - 7),注意出现LEFT JOIN,谓词条件在表T2上,使用
--//use_concat提示根本不行。
--//另外实际上开发有可能写错,如果:v_id,:StartDate,:EndDate任何一个非空,LEFT JOIN消失,换一句话将开发可能写错sql语句。
--//实际的情况如果:v_id,:StartDate,:EndDate都是null,在实际生产系统查询没有任何意义,返回一大堆记录。
--//当然还是1个可能开发( ( :v_id = '' OR :v_id IS NULL) OR t2.object_id = :v_id)应该写成
--//( ( :v_id = '' OR :v_id IS NULL) OR t1.object_id = :v_id).
3.测试:
SCOTT@book01p> @ sl all
alter session set statistics_level = all;
Session altered.
--//如果没有提示:
SCOTT@book01p> @ f4.txt ''
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
--//执行计划如下:
Plan hash value: 1764467842
---------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1121 (100)| | 1 |00:00:00.06 | 2959 | | | |
|* 1 | FILTER | | 1 | | | | | | 1 |00:00:00.06 | 2959 | | | |
|* 2 | HASH JOIN OUTER | | 1 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 566 |00:00:00.06 | 2959 | 1123K| 1123K| 2736K (0)|
|* 3 | TABLE ACCESS FULL| T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 4 | TABLE ACCESS FULL| T2 | 1 | 69913 | 4028K| | 412 (1)| 00:00:01 | 69913 |00:00:00.02 | 1480 | | | |
---------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$2BFA4EE4
3 - SEL$2BFA4EE4 / "T1"@"SEL$1"
4 - SEL$2BFA4EE4 / "T2"@"SEL$1"
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('21.1.0')
DB_VERSION('21.1.0')
ALL_ROWS
OUTLINE_LEAF(@"SEL$2BFA4EE4")
MERGE(@"SEL$8812AA4E" >"SEL$948754D7")
OUTLINE(@"SEL$948754D7")
ANSI_REARCH(@"SEL$2")
OUTLINE(@"SEL$8812AA4E")
ANSI_REARCH(@"SEL$1")
OUTLINE(@"SEL$2")
OUTLINE(@"SEL$1")
FULL(@"SEL$2BFA4EE4" "T1"@"SEL$1")
FULL(@"SEL$2BFA4EE4" "T2"@"SEL$1")
LEADING(@"SEL$2BFA4EE4" "T1"@"SEL$1" "T2"@"SEL$1")
USE_HASH(@"SEL$2BFA4EE4" "T2"@"SEL$1")
END_OUTLINE_DATA
*/
Peeked Binds (identified by position):
--------------------------------------
3 - (NUMBER, Primary=1)
6 - (VARCHAR2(30), CSID=852, Primary=4)
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(((:V_ID IS NULL OR "T2"."OBJECT_ID"=:V_ID) AND (:STARTDATE IS NULL OR "T2"."CREATED">=:STARTDATE) AND (:ENDDATE IS NULL OR
"T2"."CREATED"<=:ENDDATE)))
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T1"."CREATED">=SYSDATE@!-360)
67 rows selected.
--//正常没有提示的情况,根本不会使用索引,建立开发真心不要再写这类似的sql语句,我们开发真心感谢exadata或者现在的硬件性能。
--//提交问题,开发仅仅加入类似条件t1.created >= SYSDATE - 7,认为问题解决了,实际上开发自己到一定时间就发现写的语句执行
--//缓慢,加入一个条件t1.created >= SYSDATE - 7使执行计划走日期索引,7天的数据量实际上逻辑读依旧很高,根本不是解决该问题
--//的根本方法。
SCOTT@book01p> @ f4.txt ' or_expand(@"SEL$2BFA4EE4")'
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
--//注:提示里面的信息是Query Block Name,可以从前面的Query Block Name / Object Alias (identified by operation id)。
--//查看执行计划确实可以使用or_expand,不知道19c为什么不行,不过21c下执行计划还是存在1个全表扫描。
Plan hash value: 1850264297
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 3117 (100)| | 1 |00:00:00.01 | 1486 | | | |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 40214 | 7225K| | 3117 (1)| 00:00:01 | 1 |00:00:00.01 | 1486 | | | |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 1486 | | | |
|* 3 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 | | | |
| 4 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 | | | |
|* 5 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | | |
|* 6 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
| 7 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 | 73728 | 73728 | |
|* 8 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 | | | |
|* 9 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | | |
|* 10 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 11 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 12 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 13 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 14 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 15 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 16 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 17 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 18 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 19 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 20 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 21 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 22 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 23 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 24 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 25 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 26 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 27 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 28 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
| 29 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 30 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 31 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 32 | NESTED LOOPS | | 0 | 166 | 19588 | | 338 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 33 | NESTED LOOPS | | 0 | 166 | 19588 | | 338 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 34 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 166 | 9794 | | 6 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 35 | INDEX RANGE SCAN | I_T2_CREATED | 0 | 166 | | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 36 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 37 | TABLE ACCESS BY INDEX ROWID | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 38 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
|* 39 | HASH JOIN OUTER | | 0 | 17591 | 1889K| 1224K| 1095 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | 3574K| 1122K| |
|* 40 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 41 | TABLE ACCESS FULL | T2 | 0 | 69913 | 3481K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 42 | HASH JOIN | | 1 | 22453 | 3595K| 1224K| 1668 (1)| 00:00:01 | 0 |00:00:00.01 | 1479 | 1123K| 1123K| 2147K (0)|
| 43 | JOIN FILTER CREATE | :BF0000 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
|* 44 | TABLE ACCESS FULL | T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 45 | VIEW | VW_JF_SET$4BFF19FA | 1 | 70079 | 7185K| | 805 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 46 | UNION-ALL | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
|* 47 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 48 | JOIN FILTER USE | :BF0000 | 0 | 15175 | 874K| | 393 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 49 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 0 | 15175 | 874K| | 393 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 50 | INDEX RANGE SCAN | I_T2_CREATED | 0 | 15175 | | | 42 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 51 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 52 | JOIN FILTER USE | :BF0000 | 0 | 54904 | 3163K| | 413 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 53 | TABLE ACCESS FULL | T2 | 0 | 54904 | 3163K| | 413 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) (3) (4) (5) (6) (7) (8))
...
*/
SCOTT@book01p> alter index i_t2_created invisible;
Index altered.
--//再次测试,还是有1次全表扫描,尝试关闭布隆过滤,还是存在1个全表扫描,结果不再贴出。有一点点奇怪的是如果我删除i_t2_created索引。
SCOTT@book01p> drop index i_t2_created;
Index dropped.
Plan hash value: 1351258686
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 1 |00:00:00.01 | 7 |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 1 |00:00:00.01 | 7 |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 7 |
|* 3 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 |
|* 4 | FILTER | | 0 | | | | | | 0 |00:00:00.01 | 0 |
|* 5 | HASH JOIN OUTER | | 0 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 6 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 |
| 7 | TABLE ACCESS FULL | T2 | 0 | 69913 | 4028K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 8 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 |
| 9 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
| 12 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) )
...
*/
--//似乎只要不过度展开,就可以获得比较理想的执行计划。
--//注意Outline Data里面记录的是OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) )
SCOTT@book01p> create index i_t2_CREATED on t2(CREATED );
Index created.
--//再次测试,使用提示or_expand(@"SEL$2BFA4EE4" (1) (2) )。
SCOTT@book01p> @ f4.txt 'or_expand(@"SEL$2BFA4EE4" (1) (2) )'
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
Plan hash value: 1351258686
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 1 |00:00:00.01 | 7 |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 1 |00:00:00.01 | 7 |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 7 |
|* 3 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 |
|* 4 | FILTER | | 0 | | | | | | 0 |00:00:00.01 | 0 |
|* 5 | HASH JOIN OUTER | | 0 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 6 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 |
| 7 | TABLE ACCESS FULL | T2 | 0 | 69913 | 4028K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 8 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 |
| 9 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
| 12 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
--//虽然存在一个全表扫描,但是只要:v_id 非空,这条执行路径不会执行,可以发现starts=0.(id =6,7)。
--//当然如果exec :v_id := null;执行计划如下:
Plan hash value: 1351258686
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 8 |00:00:00.06 | 2959 | | | |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 8 |00:00:00.06 | 2959 | | | |
| 2 | UNION-ALL | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 3 | FILTER | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 4 | FILTER | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 5 | HASH JOIN OUTER | | 1 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 566 |00:00:00.06 | 2959 | 1123K| 1123K| 2513K (0)|
|* 6 | TABLE ACCESS FULL | T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 7 | TABLE ACCESS FULL | T2 | 1 | 69913 | 4028K| | 412 (1)| 00:00:01 | 69913 |00:00:00.02 | 1480 | | | |
|* 8 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 9 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 12 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//执行计划选择全表扫描。
$ cat f5.txt
column SESSION_ID format 9999
column VALUE format 9999
column EVENT format 9999
column DESCRIPTION format a70
column SQL_FEATURE format a24
define 1=expand
SELECT *
FROM v$session_fix_control
WHERE session_id = SYS_CONTEXT ('userenv', 'sid')
and OPTIMIZER_FEATURE_ENABLE like '2%'
AND ( LOWER (description) LIKE LOWER ('%&1%')
OR LOWER (sql_feature) LIKE LOWER ('%&&1%')
OR TO_CHAR (bugno) LIKE LOWER ('%&&1%')
OR optimizer_feature_enable LIKE LOWER ('%&&1%'))
order by 6
/
SCOTT@book01p> @ f5.txt
SESSION_ID BUGNO VALUE SQL_FEATURE DESCRIPTION OPTIMIZER_FEATURE_ENABLE EVENT IS_DEFAULT CON_ID
---------- ---------- ----- ------------------------ ---------------------------------------------------------------------- ------------------------- ----- ---------- ----------
282 27541468 1 QKSFM_OR_EXPAND_27541468 avoid disjunct chain if same index chosen by other disjunct chai 20.1.0 0 1 3
282 28498976 1 QKSFM_OR_EXPAND_28498976 Allow legacy OR expansion for DML top query block 20.1.0 0 1 3
282 29450812 1 QKSFM_OR_EXPAND_29450812 Allow legacy ORE for exotic query constructs 20.1.0 0 1 3
282 28414968 3 QKSFM_OR_EXPAND_28414968 expansion with some constant branches;fkr1 in (NOT)EXISTS subque 20.1.0 0 1 3
282 29304314 1 QKSFM_OR_EXPAND_29304314 Allow legacy OR expansion when number of sub QB exceeds threshol 20.1.0 0 1 3
282 30374470 1 QKSFM_OR_EXPAND_30374470 Obey OR expansion hint with arguments 20.1.0 0 1 3
282 30358390 1 QKSFM_OR_EXPAND_30358390 Avoid FKR during ORE if query has group/order by 20.1.0 0 1 3
282 31191224 1 QKSFM_OR_EXPAND_31191224 ORE - Fix opposite range predicate check 20.1.0 0 1 3
282 30347410 1 QKSFM_OR_EXPAND_30347410 Check for sub QB is present in given QB by traversing the operan 20.1.0 0 1 3
282 29385774 1 QKSFM_OR_EXPAND_29385774 Allow LORE when cbqt ore rejected due to sub qb is parametrised 20.1.0 0 1 3
282 31162457 1 QKSFM_OR_EXPAND_31162457 Obey ORE hint with arguments even when no index driver found 21.1.0 0 1 3
282 30617002 1 QKSFM_OR_EXPAND_30617002 Allow ORE in coalesced query block 21.1.0 0 1 3
282 28234255 3 QKSFM_OR_EXPAND_28234255 allow more cases for interleaving ORE with SU 21.1.0 0 1 3
13 rows selected.
--//20c,21c版本增加许多OR_EXPAND的fix,也许19c还不支持,能力有限放弃。
--//顺便提一下这类方式只能使用sql patch打补丁来控制执行计划。
--//有点麻烦是如果建立created索引,执行计划会变差。顺便测试一下,可以这样打补丁就没有问题了
SYS@book01p> @ sqlpatch 71vbkguj3482r 'or_expand(@"SEL$2BFA4EE4" (1) (2))'
input @sqlpatch sqlid 'hint_text' oracle_version(11 or 12)
drop sql patch ,run exec sys.dbms_sqldiag.drop_sql_patch('sqlpatch_71vbkguj3482r');
display sql path message , run @spext 71vbkguj3482r
P
--//生产系统遇到的问题,我以为以前在21c下测试通过的方法在19c上可以通过,结果不行,有必要重复在21c重复测试看看。
1.环境:
SCOTT@book01p> @ ver2
==============================
PORT_STRING : x86_64/Linux 2.4.xx
VERSION : 21.0.0.0.0
BANNER : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID : 0
PL/SQL procedure successfully completed.
2.测试环境建立:
--//drop table t1 purge ;
--//drop table t2 purge ;
create table t1 as select * from all_objects;
create table t2 as select * from all_objects;
create index i_t1_object_id on t1(object_id);
create index i_t2_object_id on t2(object_id);
create index i_t1_object_name on t1(object_name);
create index i_t2_object_name on t2(object_name);
create index i_t1_CREATED on t1(CREATED );
create index i_t2_CREATED on t2(CREATED );
--//分析表略。
$ cat f4.txt
set term off
variable v_id number ;
variable v_id1 number ;
variable v_name varchar2(20) ;
variable startdate varchar2(32) ;
variable enddate varchar2(32) ;
exec :v_id := 76191;
--exec :v_name := NULL;
exec :startdate := '2024-08-16 00:00:00'
exec :enddate := '2024-08-17 00:00:00'
set term on
SELECT /*+ &&1 */
t1.object_id
,t1.object_name
,t1.object_type
,t2.object_id
,t2.object_name
,t2.object_type
FROM t1 LEFT JOIN t2 ON t1.object_id = t2.object_id
WHERE t1.created >= SYSDATE - 360
AND ( ( :v_id = '' OR :v_id IS NULL) OR t2.object_id = :v_id)
AND ( ( :StartDate = '' OR :StartDate IS NULL) OR t2.CREATED >= :StartDate)
AND ( ( :EndDate = '' OR :EndDate IS NULL) OR t2.CREATED <= :EndDate);
--//做一个接近生产系统的例子,真实的生产系统语句基本类似(只不过查询SYSDATE - 7),注意出现LEFT JOIN,谓词条件在表T2上,使用
--//use_concat提示根本不行。
--//另外实际上开发有可能写错,如果:v_id,:StartDate,:EndDate任何一个非空,LEFT JOIN消失,换一句话将开发可能写错sql语句。
--//实际的情况如果:v_id,:StartDate,:EndDate都是null,在实际生产系统查询没有任何意义,返回一大堆记录。
--//当然还是1个可能开发( ( :v_id = '' OR :v_id IS NULL) OR t2.object_id = :v_id)应该写成
--//( ( :v_id = '' OR :v_id IS NULL) OR t1.object_id = :v_id).
3.测试:
SCOTT@book01p> @ sl all
alter session set statistics_level = all;
Session altered.
--//如果没有提示:
SCOTT@book01p> @ f4.txt ''
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
--//执行计划如下:
Plan hash value: 1764467842
---------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1121 (100)| | 1 |00:00:00.06 | 2959 | | | |
|* 1 | FILTER | | 1 | | | | | | 1 |00:00:00.06 | 2959 | | | |
|* 2 | HASH JOIN OUTER | | 1 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 566 |00:00:00.06 | 2959 | 1123K| 1123K| 2736K (0)|
|* 3 | TABLE ACCESS FULL| T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 4 | TABLE ACCESS FULL| T2 | 1 | 69913 | 4028K| | 412 (1)| 00:00:01 | 69913 |00:00:00.02 | 1480 | | | |
---------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$2BFA4EE4
3 - SEL$2BFA4EE4 / "T1"@"SEL$1"
4 - SEL$2BFA4EE4 / "T2"@"SEL$1"
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('21.1.0')
DB_VERSION('21.1.0')
ALL_ROWS
OUTLINE_LEAF(@"SEL$2BFA4EE4")
MERGE(@"SEL$8812AA4E" >"SEL$948754D7")
OUTLINE(@"SEL$948754D7")
ANSI_REARCH(@"SEL$2")
OUTLINE(@"SEL$8812AA4E")
ANSI_REARCH(@"SEL$1")
OUTLINE(@"SEL$2")
OUTLINE(@"SEL$1")
FULL(@"SEL$2BFA4EE4" "T1"@"SEL$1")
FULL(@"SEL$2BFA4EE4" "T2"@"SEL$1")
LEADING(@"SEL$2BFA4EE4" "T1"@"SEL$1" "T2"@"SEL$1")
USE_HASH(@"SEL$2BFA4EE4" "T2"@"SEL$1")
END_OUTLINE_DATA
*/
Peeked Binds (identified by position):
--------------------------------------
3 - (NUMBER, Primary=1)
6 - (VARCHAR2(30), CSID=852, Primary=4)
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(((:V_ID IS NULL OR "T2"."OBJECT_ID"=:V_ID) AND (:STARTDATE IS NULL OR "T2"."CREATED">=:STARTDATE) AND (:ENDDATE IS NULL OR
"T2"."CREATED"<=:ENDDATE)))
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T1"."CREATED">=SYSDATE@!-360)
67 rows selected.
--//正常没有提示的情况,根本不会使用索引,建立开发真心不要再写这类似的sql语句,我们开发真心感谢exadata或者现在的硬件性能。
--//提交问题,开发仅仅加入类似条件t1.created >= SYSDATE - 7,认为问题解决了,实际上开发自己到一定时间就发现写的语句执行
--//缓慢,加入一个条件t1.created >= SYSDATE - 7使执行计划走日期索引,7天的数据量实际上逻辑读依旧很高,根本不是解决该问题
--//的根本方法。
SCOTT@book01p> @ f4.txt ' or_expand(@"SEL$2BFA4EE4")'
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
--//注:提示里面的信息是Query Block Name,可以从前面的Query Block Name / Object Alias (identified by operation id)。
--//查看执行计划确实可以使用or_expand,不知道19c为什么不行,不过21c下执行计划还是存在1个全表扫描。
Plan hash value: 1850264297
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 3117 (100)| | 1 |00:00:00.01 | 1486 | | | |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 40214 | 7225K| | 3117 (1)| 00:00:01 | 1 |00:00:00.01 | 1486 | | | |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 1486 | | | |
|* 3 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 | | | |
| 4 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 | | | |
|* 5 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | | |
|* 6 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
| 7 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 | 73728 | 73728 | |
|* 8 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 | | | |
|* 9 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | | |
|* 10 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 11 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 12 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 13 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 14 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 15 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 16 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 17 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 18 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 19 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 20 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 21 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 22 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 23 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 24 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 25 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 26 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 27 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 28 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
| 29 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 30 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 31 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 32 | NESTED LOOPS | | 0 | 166 | 19588 | | 338 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 33 | NESTED LOOPS | | 0 | 166 | 19588 | | 338 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 34 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 166 | 9794 | | 6 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 35 | INDEX RANGE SCAN | I_T2_CREATED | 0 | 166 | | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 36 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 37 | TABLE ACCESS BY INDEX ROWID | T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 38 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
|* 39 | HASH JOIN OUTER | | 0 | 17591 | 1889K| 1224K| 1095 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | 3574K| 1122K| |
|* 40 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 41 | TABLE ACCESS FULL | T2 | 0 | 69913 | 3481K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 42 | HASH JOIN | | 1 | 22453 | 3595K| 1224K| 1668 (1)| 00:00:01 | 0 |00:00:00.01 | 1479 | 1123K| 1123K| 2147K (0)|
| 43 | JOIN FILTER CREATE | :BF0000 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
|* 44 | TABLE ACCESS FULL | T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 45 | VIEW | VW_JF_SET$4BFF19FA | 1 | 70079 | 7185K| | 805 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 46 | UNION-ALL | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
|* 47 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 48 | JOIN FILTER USE | :BF0000 | 0 | 15175 | 874K| | 393 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 49 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 0 | 15175 | 874K| | 393 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 50 | INDEX RANGE SCAN | I_T2_CREATED | 0 | 15175 | | | 42 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 51 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 52 | JOIN FILTER USE | :BF0000 | 0 | 54904 | 3163K| | 413 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 53 | TABLE ACCESS FULL | T2 | 0 | 54904 | 3163K| | 413 (1)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) (3) (4) (5) (6) (7) (8))
...
*/
SCOTT@book01p> alter index i_t2_created invisible;
Index altered.
--//再次测试,还是有1次全表扫描,尝试关闭布隆过滤,还是存在1个全表扫描,结果不再贴出。有一点点奇怪的是如果我删除i_t2_created索引。
SCOTT@book01p> drop index i_t2_created;
Index dropped.
Plan hash value: 1351258686
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 1 |00:00:00.01 | 7 |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 1 |00:00:00.01 | 7 |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 7 |
|* 3 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 |
|* 4 | FILTER | | 0 | | | | | | 0 |00:00:00.01 | 0 |
|* 5 | HASH JOIN OUTER | | 0 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 6 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 |
| 7 | TABLE ACCESS FULL | T2 | 0 | 69913 | 4028K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 8 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 |
| 9 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
| 12 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) )
...
*/
--//似乎只要不过度展开,就可以获得比较理想的执行计划。
--//注意Outline Data里面记录的是OR_EXPAND(@"SEL$2BFA4EE4" (1) (2) )
SCOTT@book01p> create index i_t2_CREATED on t2(CREATED );
Index created.
--//再次测试,使用提示or_expand(@"SEL$2BFA4EE4" (1) (2) )。
SCOTT@book01p> @ f4.txt 'or_expand(@"SEL$2BFA4EE4" (1) (2) )'
OBJECT_ID OBJECT_NAME OBJECT_TYPE OBJECT_ID OBJECT_NAME OBJECT_TYPE
--------- ----------- ----------- ---------- ----------- -----------
76191 DEPT TABLE 76191 DEPT TABLE
Plan hash value: 1351258686
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 1 |00:00:00.01 | 7 |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 1 |00:00:00.01 | 7 |
| 2 | UNION-ALL | | 1 | | | | | | 1 |00:00:00.01 | 7 |
|* 3 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 |
|* 4 | FILTER | | 0 | | | | | | 0 |00:00:00.01 | 0 |
|* 5 | HASH JOIN OUTER | | 0 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 6 | TABLE ACCESS FULL | T1 | 0 | 17591 | 1013K| | 415 (2)| 00:00:01 | 0 |00:00:00.01 | 0 |
| 7 | TABLE ACCESS FULL | T2 | 0 | 69913 | 4028K| | 412 (1)| 00:00:01 | 0 |00:00:00.01 | 0 |
|* 8 | FILTER | | 1 | | | | | | 1 |00:00:00.01 | 7 |
| 9 | MERGE JOIN CARTESIAN | | 1 | 1 | 118 | | 4 (0)| 00:00:01 | 1 |00:00:00.01 | 7 |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
| 12 | BUFFER SORT | | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 59 | | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 1 | 1 | | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
--//虽然存在一个全表扫描,但是只要:v_id 非空,这条执行路径不会执行,可以发现starts=0.(id =6,7)。
--//当然如果exec :v_id := null;执行计划如下:
Plan hash value: 1351258686
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | | 1125 (100)| | 8 |00:00:00.06 | 2959 | | | |
| 1 | VIEW | VW_ORE_4392E357 | 1 | 17592 | 3161K| | 1125 (1)| 00:00:01 | 8 |00:00:00.06 | 2959 | | | |
| 2 | UNION-ALL | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 3 | FILTER | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 4 | FILTER | | 1 | | | | | | 8 |00:00:00.06 | 2959 | | | |
|* 5 | HASH JOIN OUTER | | 1 | 17591 | 2027K| 1224K| 1121 (1)| 00:00:01 | 566 |00:00:00.06 | 2959 | 1123K| 1123K| 2513K (0)|
|* 6 | TABLE ACCESS FULL | T1 | 1 | 17591 | 1013K| | 415 (2)| 00:00:01 | 566 |00:00:00.01 | 1479 | | | |
| 7 | TABLE ACCESS FULL | T2 | 1 | 69913 | 4028K| | 412 (1)| 00:00:01 | 69913 |00:00:00.02 | 1480 | | | |
|* 8 | FILTER | | 1 | | | | | | 0 |00:00:00.01 | 0 | | | |
| 9 | MERGE JOIN CARTESIAN | | 0 | 1 | 118 | | 4 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | T2 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 11 | INDEX RANGE SCAN | I_T2_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
| 12 | BUFFER SORT | | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 73728 | 73728 | |
|* 13 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 0 | 1 | 59 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
|* 14 | INDEX RANGE SCAN | I_T1_OBJECT_ID | 0 | 1 | | | 1 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | | | |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//执行计划选择全表扫描。
$ cat f5.txt
column SESSION_ID format 9999
column VALUE format 9999
column EVENT format 9999
column DESCRIPTION format a70
column SQL_FEATURE format a24
define 1=expand
SELECT *
FROM v$session_fix_control
WHERE session_id = SYS_CONTEXT ('userenv', 'sid')
and OPTIMIZER_FEATURE_ENABLE like '2%'
AND ( LOWER (description) LIKE LOWER ('%&1%')
OR LOWER (sql_feature) LIKE LOWER ('%&&1%')
OR TO_CHAR (bugno) LIKE LOWER ('%&&1%')
OR optimizer_feature_enable LIKE LOWER ('%&&1%'))
order by 6
/
SCOTT@book01p> @ f5.txt
SESSION_ID BUGNO VALUE SQL_FEATURE DESCRIPTION OPTIMIZER_FEATURE_ENABLE EVENT IS_DEFAULT CON_ID
---------- ---------- ----- ------------------------ ---------------------------------------------------------------------- ------------------------- ----- ---------- ----------
282 27541468 1 QKSFM_OR_EXPAND_27541468 avoid disjunct chain if same index chosen by other disjunct chai 20.1.0 0 1 3
282 28498976 1 QKSFM_OR_EXPAND_28498976 Allow legacy OR expansion for DML top query block 20.1.0 0 1 3
282 29450812 1 QKSFM_OR_EXPAND_29450812 Allow legacy ORE for exotic query constructs 20.1.0 0 1 3
282 28414968 3 QKSFM_OR_EXPAND_28414968 expansion with some constant branches;fkr1 in (NOT)EXISTS subque 20.1.0 0 1 3
282 29304314 1 QKSFM_OR_EXPAND_29304314 Allow legacy OR expansion when number of sub QB exceeds threshol 20.1.0 0 1 3
282 30374470 1 QKSFM_OR_EXPAND_30374470 Obey OR expansion hint with arguments 20.1.0 0 1 3
282 30358390 1 QKSFM_OR_EXPAND_30358390 Avoid FKR during ORE if query has group/order by 20.1.0 0 1 3
282 31191224 1 QKSFM_OR_EXPAND_31191224 ORE - Fix opposite range predicate check 20.1.0 0 1 3
282 30347410 1 QKSFM_OR_EXPAND_30347410 Check for sub QB is present in given QB by traversing the operan 20.1.0 0 1 3
282 29385774 1 QKSFM_OR_EXPAND_29385774 Allow LORE when cbqt ore rejected due to sub qb is parametrised 20.1.0 0 1 3
282 31162457 1 QKSFM_OR_EXPAND_31162457 Obey ORE hint with arguments even when no index driver found 21.1.0 0 1 3
282 30617002 1 QKSFM_OR_EXPAND_30617002 Allow ORE in coalesced query block 21.1.0 0 1 3
282 28234255 3 QKSFM_OR_EXPAND_28234255 allow more cases for interleaving ORE with SU 21.1.0 0 1 3
13 rows selected.
--//20c,21c版本增加许多OR_EXPAND的fix,也许19c还不支持,能力有限放弃。
--//顺便提一下这类方式只能使用sql patch打补丁来控制执行计划。
--//有点麻烦是如果建立created索引,执行计划会变差。顺便测试一下,可以这样打补丁就没有问题了
SYS@book01p> @ sqlpatch 71vbkguj3482r 'or_expand(@"SEL$2BFA4EE4" (1) (2))'
input @sqlpatch sqlid 'hint_text' oracle_version(11 or 12)
drop sql patch ,run exec sys.dbms_sqldiag.drop_sql_patch('sqlpatch_71vbkguj3482r');
display sql path message , run @spext 71vbkguj3482r
P