select count(distinct b.object_id)from t1 aleft join t99 bon a.object_id=b.object_idAND (a.owner='SYS' or b.owner='SYS');说明:执行计划如下所示,有两个问题:1.不能使用hash join2.没有识别出这是个inner join这个SQL如果要提高执行效率,必须改写.有些国产数据库可以识别这是一个inner join,不需要改写,可以使用hash join---------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time |---------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 232K (1)| 00:00:10 || 1 | HASH GROUP BY | | 1 | | || 2 | MERGE JOIN OUTER | | 77275 | 232K (1)| 00:00:10 || 3 | TABLE ACCESS FULL | T1 | 77275 | 447 (1)| 00:00:01 || 4 | BUFFER SORT | | 1 | 231K (1)| 00:00:10 || 5 | VIEW | VW_LAT_2E38C6CE | 1 | 3 (0)| 00:00:01 ||* 6 | TABLE ACCESS FULL| T99 | 1 | 3 (0)| 00:00:01 |---------------------------------------------------------------------------------注: 这个SQL的原型,本来效率更差,就是and后面的or缺少了括号.
--其中v_t1t2是一个view, 是t1表和t2表的union all,--两表的object_id字段上都有索引select a.owner,a.object_id,b.object_type,c.createdfrom v_t1t2 a, t3 b,t4 cwhere b.object_id=a.object_idand b.object_type='WINDOW'and a.object_name=c.object_name;说明:如果没有t4表参与关联, t3与v_t1t2会使用Nested loops关联方法(因为t3结果集xiao,只返回9条记录),多了t4表参与关联后,t3和v_t1t2就只能选择hash join,这个选择是低效的.如果要得到高效的执行计划, 一般是需要改写. 也能通过hint解决(比较复杂).某些国产数据库没有这个问题.-------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time |-------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 22 | 1230 (1)| 00:00:01 || 1 | NESTED LOOPS | | 22 | 1230 (1)| 00:00:01 || 2 | NESTED LOOPS | | 22 | 1230 (1)| 00:00:01 ||* 3 | HASH JOIN | | 18 | 1176 (1)| 00:00:01 ||* 4 | TABLE ACCESS FULL | T3 | 9 | 392 (1)| 00:00:01 || 5 | VIEW | V_T1T2 | 150K| 783 (1)| 00:00:01 || 6 | UNION-ALL | | | | || 7 | TABLE ACCESS FULL | T1 | 75026 | 392 (1)| 00:00:01 || 8 | TABLE ACCESS FULL | T2 | 75028 | 392 (1)| 00:00:01 ||* 9 | INDEX RANGE SCAN | IDX_T4_OBJECT_NAME | 1 | 2 (0)| 00:00:01 || 10 | TABLE ACCESS BY INDEX ROWID| T4 | 1 | 3 (0)| 00:00:01 |-------------------------------------------------------------------------------------------
--下面几个SQL, 某些国产数据库也是可以走索引的,oracle数据库要想走索引, 必须通过改写或函数索引来实现:select * from t1 where status<>'VALID';select * from t1 where namespace not in(1,4,12);select * from t1 where status not like 'VALID%';
下面SQL,not exists里面使用了函数,导致执行计划无法选择效率相对较高的hash join,而是使用了低效的filter:select count(*) from t1 awhere not exists(select 1from t2 bwhere a.object_id=b.object_idand abs(a.DATA_OBJECT_ID-b.DATA_OBJECT_ID)>1 ---使用了函数);执行计划, 只能使用filter:--------------------------------------------------------------------------------------------| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time |--------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 138K (1)| 00:00:06 || 1 | SORT AGGREGATE | | 1 | | ||* 2 | FILTER | | | | || 3 | TABLE ACCESS FULL | T1 | 76913 | 1175 (1)| 00:00:01 ||* 4 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 2 (0)| 00:00:01 ||* 5 | INDEX UNIQUE SCAN | UIDX_T2_OBJECT_ID | 1 | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------------如果要得到hash join的执行计划, 也是需要改写的.其他数据库没有这个问题.
下面SQL,如果没有having count(*)>1,oracle优化器是可以做push predicate,加了having后就不行了, 只能使用hash join.某些国产数据库在这种情况下可以push predicate.select *from t1 aleft join(select object_name,count(*) as cntfrom t2group by object_namehaving count(*)>1) bon a.object_name=b.object_namewhere a.status='INVALID';oracle的执行计划,要想SQL高效执行, 必须改写:------------------------------------------------------------------------------------------------| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time |------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 14 | 416 (1)| 00:00:01 ||* 1 | HASH JOIN OUTER | | 14 | 416 (1)| 00:00:01 || 2 | JOIN FILTER CREATE | :BF0000 | 14 | 4 (0)| 00:00:01 || 3 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 14 | 4 (0)| 00:00:01 ||* 4 | INDEX RANGE SCAN | IDX_T1_STATUS | 14 | 3 (0)| 00:00:01 || 5 | VIEW | | 3207 | 412 (1)| 00:00:01 ||* 6 | HASH GROUP BY | | 3207 | 412 (1)| 00:00:01 || 7 | JOIN FILTER USE | :BF0000 | 77695 | 410 (1)| 00:00:01 ||* 8 | TABLE ACCESS FULL | T2 | 77695 | 410 (1)| 00:00:01 |------------------------------------------------------------------------------------------------
--关联条件带or , 即使加or_expand 也不生效:select /*+ or_expand */ count(*)from t1 awhere not exists(select 1 from t2 bwhere a.object_id=b.object_idora.data_object_id=b.data_object_id);oracle执行计划,使用的是filter,要想得到高效执行计划, 需要改写.有些国产数据库,可以做or_expand,执行效率更高.oracle当前执行计划:---------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |---------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 169K(100)| | 1 |00:00:00.65 | 7985 || 1 | SORT AGGREGATE | | 1 | 1 | | | 1 |00:00:00.65 | 7985 ||* 2 | FILTER | | 1 | | | | 638 |00:00:00.65 | 7985 || 3 | TABLE ACCESS FULL | T1 | 1 | 76913 | 1175 (1)| 00:00:01 | 76911 |00:00:00.04 | 4283 || 4 | BITMAP CONVERSION TO ROWIDS | | 76909 | | | | 76273 |00:00:00.50 | 3702 || 5 | BITMAP OR | | 76909 | | | | 76273 |00:00:00.44 | 3702 || 6 | BITMAP CONVERSION FROM ROWIDS| | 76909 | | | | 7727 |00:00:00.10 | 1306 ||* 7 | INDEX RANGE SCAN | IDX_T2_DATA_OBJECT_ID | 76909 | | 1 (0)| 00:00:01 | 8115 |00:00:00.05 | 1306 || 8 | BITMAP CONVERSION FROM ROWIDS| | 76909 | | | | 76272 |00:00:00.23 | 2396 ||* 9 | INDEX RANGE SCAN | IDX_T2_OBJECT_ID | 76909 | | 1 (0)| 00:00:01 | 76272 |00:00:00.13 | 2396 |---------------------------------------------------------------------------------------------------------------------------------------------
select count(*)from t1 awhere exists(select 1 from t2 bwhere a.object_id=b.object_idora.data_object_id=b.data_object_id);与not exists一样,exists也只能使用filter的执行计划,要想得到高效执行计划,也必须改写.某些国产数据库可以不需要改写,就可以实现or_expandoracle当前执行计划:------------------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads |------------------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 169K(100)| | 1 |00:00:00.57 | 7978 | 186 || 1 | SORT AGGREGATE | | 1 | 1 | | | 1 |00:00:00.57 | 7978 | 186 ||* 2 | FILTER | | 1 | | | | 76277 |00:00:00.56 | 7978 | 186 || 3 | TABLE ACCESS FULL | T1 | 1 | 76913 | 1175 (1)| 00:00:01 | 76913 |00:00:00.03 | 4283 | 0 || 4 | BITMAP CONVERSION TO ROWIDS | | 76911 | | | | 76277 |00:00:00.41 | 3695 | 186 || 5 | BITMAP OR | | 76911 | | | | 76277 |00:00:00.37 | 3695 | 186 || 6 | BITMAP CONVERSION FROM ROWIDS| | 76911 | | | | 7729 |00:00:00.10 | 1306 | 17 ||* 7 | INDEX RANGE SCAN | IDX_T2_DATA_OBJECT_ID | 76911 | | 1 (0)| 00:00:01 | 8117 |00:00:00.04 | 1306 | 17 || 8 | BITMAP CONVERSION FROM ROWIDS| | 76911 | | | | 76277 |00:00:00.18 | 2389 | 169 ||* 9 | INDEX RANGE SCAN | IDX_T2_OBJECT_ID | 76911 | | 1 (0)| 00:00:01 | 76277 |00:00:00.10 | 2389 | 169 |------------------------------------------------------------------------------------------------------------------------------------------------------
下面SQL,如果去掉create table(insert into test_xxx也是一样),优化器默认会选择hash join,加上了就只能使用低效的merge join:create table test_xxxasselect a.owner,b.object_namefrom t1 aleft join t2 bon a.object_id=b.object_idand a.owner in ('SYS','PUBLIC','SYSTEM');oracle数据库要想得到hash join的执行计划,需要改写.其他数据库没有这个问题.oracle当前执行计划:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Writes | OMem | 1Mem | Used-Mem |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 0 | CREATE TABLE STATEMENT | | 1 | | 151K(100)| | 0 |00:00:00.54 | 13266 | 424 | | | || 1 | LOAD AS SELECT | TEST_XXX | 1 | | | | 0 |00:00:00.54 | 13266 | 424 | 7355K| 7355K| 2070K (0)|| 2 | OPTIMIZER STATISTICS GATHERING | | 1 | 75594 | 151K (1)| 00:00:06 | 75594 |00:00:00.46 | 12231 | 0 | 256K| 256K| 256K (0)|| 3 | MERGE JOIN OUTER | | 1 | 75594 | 151K (1)| 00:00:06 | 75594 |00:00:00.42 | 12231 | 0 | | | || 4 | TABLE ACCESS FULL | T1 | 1 | 75594 | 410 (1)| 00:00:01 | 75594 |00:00:00.02 | 1451 | 0 | | | || 5 | BUFFER SORT | | 75594 | 1 | 151K (1)| 00:00:06 | 65513 |00:00:00.34 | 10780 | 0 | 2048 | 2048 | 2048 (0)|| 6 | VIEW | VW_LAT_DF9E236D | 75594 | 1 | 2 (0)| 00:00:01 | 65513 |00:00:00.21 | 10780 | 0 | | | ||* 7 | FILTER | | 75594 | | | | 65513 |00:00:00.16 | 10780 | 0 | | | || 8 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 66237 | 1 | 2 (0)| 00:00:01 | 65513 |00:00:00.12 | 10780 | 0 | | | ||* 9 | INDEX RANGE SCAN | IDX_T2_OBJECT_ID | 66237 | 1 | 1 (0)| 00:00:01 | 65513 |00:00:00.07 | 8289 | 0 | | | |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
create or replace view v_dualas(select '-1' as id from dualunion allselect to_char(data_object_id) as id from t1union allselect object_name from t3);--下面SQL不能push predicate:select * from t2 ainner join v_dual bon a.object_name=b.idand a.object_id=1;只有oracle数据库有这个问题,要想得到高效执行计划,需要较为复杂的改写.其他数据库没有这个问题.oracle当前执行计划:-------------------------------------------------------------------------------------------| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time |-------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | 1590 (100)| || 1 | NESTED LOOPS | | 2 | 1590 (1)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 2 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | UIDX_T2_OBJECT_ID | 1 | 1 (0)| 00:00:01 ||* 4 | VIEW | V_DUAL | 2 | 1588 (1)| 00:00:01 || 5 | UNION-ALL | | | | || 6 | FAST DUAL | | 1 | 2 (0)| 00:00:01 || 7 | TABLE ACCESS FULL | T1 | 76913 | 1175 (1)| 00:00:01 || 8 | TABLE ACCESS FULL | T3 | 75069 | 411 (1)| 00:00:01 |-----object_name字段上有索引也不使用-------------------------------------------------------------------------------------------
create view v_t1t2asselect * from t1union allselect * from t2;--下面SQL,子查询返回的值,不能push predicate到view:select a.owner,a.object_idfrom v_t1t2 awhere object_id=(select object_id from t2where object_name='TAB$');oracle数据库如果要得到高效执行计划,需要改写.某些国产数据库不需要改写,可以push predicate.下面是oracle的执行计划:----------------------------------------------------------------------------------------------------| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time |----------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | 1589 (100)| ||* 1 | VIEW | V_T1T2 | 154K| 1585 (1)| 00:00:01 || 2 | UNION-ALL | | | | || 3 | TABLE ACCESS FULL | T1 | 76913 | 1175 (1)| 00:00:01 || 4 | TABLE ACCESS FULL | T2 | 77695 | 410 (1)| 00:00:01 || 5 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 1 | 4 (0)| 00:00:01 ||* 6 | INDEX RANGE SCAN | IDX_T2_OBJECT_NAME | 1 | 3 (0)| 00:00:01 |----------------------------------------------------------------------------------------------------
select distinct object_namefrom t1 aorder by object_name descfetch first 5 rows only;oracle 数据库如果要得到高效执行计划,需要改写.某些国产数据库不需要改写,就可以得到高效执行计划.-----------------------------------------------------------------------------------------------------| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time | OMem | 1Mem | Used-Mem |-----------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | 2802 (100)| | | | ||* 1 | VIEW | | 5 | 2802 (1)| 00:00:01 | | | ||* 2 | WINDOW SORT PUSHED RANK| | 63760 | 2802 (1)| 00:00:01 | 9216 | 9216 | 8192 (0)|| 3 | VIEW | | 63760 | 1799 (1)| 00:00:01 | | | || 4 | HASH UNIQUE | | 63760 | 1799 (1)| 00:00:01 | 11M| 2194K| 5580K (0)|| 5 | TABLE ACCESS FULL | T1 | 76913 | 1175 (1)| 00:00:01 | | | |-----------------------------------------------------------------------------------------------------
文章转载自老虎刘谈oracle性能优化,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




