一、表关联时执行计划filter代表什么?
http://www.oracleplus.net/arch/1026.html 实验数据准备 SQL> create table scott.htz1 as select * from dba_objects; SQL> create table scott.htz2 as select * from dba_objects; SQL> create table scott.htz3 as select * from dba_objects; SQL> create index scott.ind_htz3_object_owner on scott.htz3(object_id,owner); set linesize 500 set termout off alter session set statistics_level=all; SQL> host cat plan.sql set linesize 200 pagesize 999 测试一、驱动表无重复值 SQL> select * from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.object_id in (select object_id from scott.htz3 c where c.owner = 'SCOTT' and a.owner = 'SYS') ; select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); Plan hash value: 1177288075 ---------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ---------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 772 (100)| | 0 |00:00:00.06 | 1519 | |* 1 | HASH JOIN | | 1 | 14 | 772 (1)| 00:00:10 | 0 |00:00:00.06 | 1519 | |* 2 | HASH JOIN RIGHT SEMI | | 1 | 14 | 424 (1)| 00:00:06 | 0 |00:00:00.06 | 1519 | |* 3 | INDEX FAST FULL SCAN| IND_HTZ3_OBJECT_OWNER | 1 | 14 | 77 (0)| 00:00:01 | 64 |00:00:00.02 | 270 | |* 4 | TABLE ACCESS FULL | HTZ1 | 1 | 37820 | 347 (1)| 00:00:05 | 37820 |00:00:00.02 | 1249 | | 5 | TABLE ACCESS FULL | HTZ2 | 0 | 97015 | 347 (1)| 00:00:05 | 0 |00:00:00.01 | 0 | ---------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("A"."OBJECT_ID"="B"."OBJECT_ID") 2 - access("A"."OBJECT_ID"="OBJECT_ID") 3 - filter("C"."OWNER"='SCOTT') 4 - filter("A"."OWNER"='SYS') --想整一个 filter执行计划! 不出来,说明Oracle 版本升级后优化器确实存在内部提升! select * from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.object_id in (select /*+ NO_USE_HASH(c) */ object_id from scott.htz3 c where c.owner = 'SCOTT' and a.owner = 'SYS') ; select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); 参考 https://www.cndba.cn/cndba/dave/article/4352 select /*+ optimizer_features_enable('10.2.0.5') */ * from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.object_id in (select object_id from scott.htz3 c where c.owner = 'SCOTT' and a.owner = 'SYS') ; select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); Plan hash value: 286543034 ---------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads | ---------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 80894 (100)| | 0 |00:00:00.78 | 41608 | 926 | |* 1 | FILTER | | 1 | | | | 0 |00:00:00.78 | 41608 | 926 | |* 2 | HASH JOIN | | 1 | 80459 | 2533 (1)| 00:00:31 | 87117 |00:00:00.52 | 2498 | 926 | | 3 | TABLE ACCESS FULL| HTZ1 | 1 | 80459 | 347 (1)| 00:00:05 | 87119 |00:00:00.05 | 1249 | 0 | | 4 | TABLE ACCESS FULL| HTZ2 | 1 | 97015 | 347 (1)| 00:00:05 | 87120 |00:00:00.08 | 1249 | 926 | |* 5 | FILTER | | 87117 | | | | 0 |00:00:00.14 | 39110 | 0 | |* 6 | INDEX RANGE SCAN | IND_HTZ3_OBJECT_OWNER | 37819 | 1 | 1 (0)| 00:00:01 | 0 |00:00:00.10 | 39110 | 0 | ---------------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter( IS NOT NULL) 2 - access("A"."OBJECT_ID"="B"."OBJECT_ID") 5 - filter(:B1='SYS') 6 - access("OBJECT_ID"=:B1 AND "C"."OWNER"='SCOTT') select count(*) from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id; COUNT(*) ---------- 87117 select count(*) from ( select distinct a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id); COUNT(*) ---------- 87117 select count(*) from ( select distinct a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.owner='SYS'); COUNT(*) ---------- 37819 !!!Filter 驱动表的需要循环执行的次数,是驱动结果集的数量! --index scott.ind_htz3_object_owner [object_id,owner] select count(*) from ( select object_id,owner from scott.htz3 group by object_id,owner); COUNT(*) ---------- 87121 测试二、驱动表存在重复值 SQL> insert into scott.htz1 select * from scott.htz1; commit; select /*+ optimizer_features_enable('10.2.0.5') */ * from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.object_id in (select object_id from scott.htz3 c where c.owner = 'SCOTT' and a.owner = 'SYS') ; select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); ------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 291K(100)| | 0 |00:00:01.13 | 86565 | |* 1 | FILTER | | 1 | | | | 0 |00:00:01.13 | 86565 | |* 2 | HASH JOIN | | 1 | 288K| 5409 (1)| 00:01:05 | 174K|00:00:00.69 | 3767 | | 3 | TABLE ACCESS FULL| HTZ2 | 1 | 97015 | 347 (1)| 00:00:05 | 87120 |00:00:00.03 | 1249 | | 4 | TABLE ACCESS FULL| HTZ1 | 1 | 324K| 694 (1)| 00:00:09 | 174K|00:00:00.06 | 2518 | |* 5 | FILTER | | 173K| | | | 0 |00:00:00.26 | 82798 | |* 6 | INDEX RANGE SCAN | IND_HTZ3_OBJECT_OWNER | 74784 | 1 | 1 (0)| 00:00:01 | 0 |00:00:00.17 | 82798 | ------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter( IS NOT NULL) 2 - access("A"."OBJECT_ID"="B"."OBJECT_ID") 5 - filter(:B1='SYS') 6 - access("OBJECT_ID"=:B1 AND "C"."OWNER"='SCOTT') select count(*) from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id; COUNT(*) ---------- 174234 select count(*) from ( select distinct a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id); COUNT(*) ---------- 87117 select count(*) from ( select distinct a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.owner='SYS'); COUNT(*) ---------- 37819 select count(*) from ( select a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.owner='SYS'); COUNT(*) ---------- 75638 select count(*) from scott.htz3; 87121 select count(*) from scott.htz3 where owner='SCOTT'; 64 select count(*) from ( select tmp_b.object_id from ( select a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id) tmp_a,scott.htz1 tmp_b where tmp_a.object_id=tmp_b.object_id and tmp_b.owner='SYS'); COUNT(*) ---------- 151276 select count(*) from ( select distinct tmp_b.object_id from ( select a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id) tmp_a,scott.htz1 tmp_b where tmp_a.object_id=tmp_b.object_id and tmp_b.owner='SYS'); COUNT(*) ---------- 37819 select count(*) from ( select tmp_b.object_id from ( select a.object_id from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.owner='SYS') tmp_a,scott.htz1 tmp_b where tmp_a.object_id=tmp_b.object_id ); select * from scott.htz1 a, scott.htz2 b where a.object_id = b.object_id and a.object_id in (select /*+ no_unnest */ object_id from scott.htz3 c where c.owner = 'SCOTT' and a.owner = 'SYS') ; select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); ------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2663 (100)| | 0 |00:00:00.53 | 42877 | |* 1 | FILTER | | 1 | | | | 0 |00:00:00.53 | 42877 | |* 2 | HASH JOIN | | 1 | 3246 | 1040 (1)| 00:00:13 | 75638 |00:00:00.33 | 3767 | |* 3 | TABLE ACCESS FULL| HTZ1 | 1 | 3246 | 692 (1)| 00:00:09 | 75640 |00:00:00.04 | 2518 | | 4 | TABLE ACCESS FULL| HTZ2 | 1 | 97015 | 347 (1)| 00:00:05 | 87120 |00:00:00.04 | 1249 | |* 5 | INDEX RANGE SCAN | IND_HTZ3_OBJECT_OWNER | 37819 | 1 | 1 (0)| 00:00:01 | 0 |00:00:00.12 | 39110 | -------------------------------------------------------------------------------------------------------------------------------
小结:
测试了一下filter 在表关联的情况下,类似nest loop, 驱动的结果集有多少,被驱动结果集需要重复执行多少次。
但是filter优化了nest loop, 就是假设驱动结果集记录500,distinct 之后是60,那么被驱动的结果集只需要执行60次。 具体可以测试以及学习基于Oracle SQL优化。
本次测试11.2.0.4 DB版本,使用Hint sql 10.2.0.5优化器参数后, 驱动表无重复值,start次数符合预期,但是驱动表存在重复值后,start与预期不符合。 sql重新使用11.2.0.4 优化器参数后,start 次数符合预期!!!
也就是说当出现filter时,可以类似用nest loop的方式考虑! 但是驱动次数=去重后的驱动结果集数量!
二、相关优化器参数
https://blog.csdn.net/cuiqu77884/article/details/100338813 11g 默认参数为true
create table t1 as select * from dba_objects; create table t2 as select * from dba_tables; select count(*) from t1 where object_name not in (select table_name from t2); COUNT(*) ---------- 83859 select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); ----------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads | ----------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 379 (100)| | 1 |00:00:00.21 | 1355 | 879 | | 1 | SORT AGGREGATE | | 1 | 1 | | | 1 |00:00:00.21 | 1355 | 879 | |* 2 | HASH JOIN RIGHT ANTI SNA| | 1 | 90231 | 379 (1)| 00:00:05 | 83859 |00:00:00.20 | 1355 | 879 | | 3 | TABLE ACCESS FULL | T2 | 1 | 2771 | 32 (0)| 00:00:01 | 2927 |00:00:00.01 | 106 | 0 | | 4 | TABLE ACCESS FULL | T1 | 1 | 90231 | 347 (1)| 00:00:05 | 87121 |00:00:00.13 | 1249 | 879 | ----------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_NAME"="TABLE_NAME") SQL> alter session set "_optimizer_null_aware_antijoin"=false; select count(*) from t1 where object_name not in (select table_name from t2); select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last')); --等待16s还是没有执行完毕,手工取消执行 -------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | -------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 120K(100)| | 0 |00:00:00.01 | 0 | | 1 | SORT AGGREGATE | | 1 | 1 | | | 0 |00:00:00.01 | 0 | |* 2 | FILTER | | 1 | | | | 63977 |00:00:16.00 | 3963K| | 3 | TABLE ACCESS FULL| T1 | 1 | 90231 | 347 (1)| 00:00:05 | 65341 |00:00:00.03 | 939 | |* 4 | TABLE ACCESS FULL| T2 | 38236 | 2633 | 2 (0)| 00:00:01 | 1249 |00:00:15.75 | 3962K| -------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter( IS NULL) 4 - filter(LNNVL("TABLE_NAME"<>:B1))
_optimizer_null_aware_antijoin参数能优化查询效率,但是查看mos,开启该隐含参数会有很多的bug。可能存在不稳定,因此通常会建议把该参数关闭。
这个参数默认true开启状态,会自动将filter执行计划调整为hash,如果关闭之后就出现filter了!
! 如果执行计划发行存在filter之后,并且参数false,可以尝试SQL语句Hint 参数=true观察,hash是否有所提升!