下面是测试其中一种subquery语句不能正常的unnest,测试来至于朋友发的一条SQL语句,消耗了大量的逻辑读,猜测是由于subquery没有unnest导致走FILTER,消耗大量的逻辑。这里只是简单的测试一下不能嵌套,并没有考虑性能问题。
1,环境介绍
www.htz.pw > select * from V$version; BANNER ——————————————————————————– Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 – 64bit Production PL/SQL Release 11.2.0.3.0 – Production CORE 11.2.0.3.0 Production TNS for Linux: Version 11.2.0.3.0 – Production NLSRTL Version 11.2.0.3.0 – Production www.htz.pw > !lsb_release -a LSB Version: :core-3.0-amd64:core-3.0-ia32:core-3.0-noarch:graphics-3.0-amd64:graphics-3.0-ia32:graphics-3.0-noarch Distributor ID: RedHatEnterpriseAS Description: Red Hat Enterprise Linux AS release 4 (Nahant Update 8) Release: 4 Codename: NahantUpdate8
2,创建测试表
这里以dba_objects视图来创建2张测试表
www.htz.pw > create table htz.test1 as select * from dba_objects; Table created. www.htz.pw > create table htz.test2 as select * from dba_objects; Table created.
3,测试SQL语句
3.1 原始SQL语句
www.htz.pw > explain plan for select * 2 from htz.test1 a 3 where (a.owner = 'SCOTT' or exists 4 (select 1 5 from htz.test2 b 6 where a.owner = b.owner 7 and b.object_id < 1000)) 8 and a.object_id < 1000 9 ; Explained. www.htz.pw > @plan_by_explain.sql PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------- Plan hash value: 1896454807 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 91 | 18837 | 298 (1)| 00:00:04 | |* 1 | FILTER | | | | | | |* 2 | TABLE ACCESS FULL| TEST1 | 1521 | 307K| 298 (1)| 00:00:04 | |* 3 | TABLE ACCESS FULL| TEST2 | 1 | 30 | 298 (1)| 00:00:04 | ---------------------------------------------------------------------------- 这里看到了FILTER这个关键字 Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("A"."OWNER"='SCOTT' OR EXISTS (SELECT 0 FROM "HTZ"."TEST2" "B" WHERE "B"."OWNER"=:B1 AND "B"."OBJECT_ID"<1000)) 2 - filter("A"."OBJECT_ID"<1000) 3 - filter("B"."OWNER"=:B1 AND "B"."OBJECT_ID"<1000)
3.2 改写SQL语句
下面将SQL语句改写成UNION ALL,生产环境需要开发他们确认一下是否等效
www.htz.pw > explain plan for 2 select * 3 from htz.test1 a 4 where (a.owner = 'SCOTT') 5 and a.object_id < 1000 6 union all 7 select * 8 from htz.test1 a 9 where a.object_id < 1000 10 and lnnvl(a.owner = 'SCOTT') 11 and exists (select 1 12 from htz.test2 b 13 where a.owner = b.owner 14 and b.object_id < 1000); Explained. www.htz.pw > @plan_by_explain.sql www.htz.pw > set lines 170 www.htz.pw > set pages 1000 www.htz.pw > select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Plan hash value: 2697857779 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 726 | 167K| 895 (67)| 00:00:11 | | 1 | UNION-ALL | | | | | | |* 2 | TABLE ACCESS FULL | TEST1 | 35 | 7245 | 298 (1)| 00:00:04 | |* 3 | HASH JOIN RIGHT SEMI| | 691 | 159K| 597 (1)| 00:00:08 | |* 4 | TABLE ACCESS FULL | TEST2 | 12 | 360 | 298 (1)| 00:00:04 | |* 5 | TABLE ACCESS FULL | TEST1 | 1521 | 307K| 298 (1)| 00:00:04 | ------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("A"."OWNER"='SCOTT' AND "A"."OBJECT_ID"<1000) 3 - access("A"."OWNER"="B"."OWNER") 4 - filter("B"."OBJECT_ID"<1000) 5 - filter("A"."OBJECT_ID"<1000 AND LNNVL("A"."OWNER"='SCOTT'))
3.3 使用with来改写SQL
使用WITH来改写SQL性能不一定高,但是多数情况下还是可以接受的
www.htz.pw > explain plan for with tt as 2 (select /*+ materialize */ 3 b.owner 4 from htz.test2 b 5 where b.object_id < 1000) 6 select * 7 from htz.test1 a 8 where (a.owner = 'SCOTT' or exists 9 (select 1 from tt where a.owner = tt.owner)) 10 and a.object_id < 1000; Explained. www.htz.pw > @plan_by_explain.sql PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Plan hash value: 1918954582 -------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 91 | 18837 | 596 (1)| 00:00:08 | | 1 | TEMP TABLE TRANSFORMATION | | | | | | | 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6601_5F1475 | | | | | |* 3 | TABLE ACCESS FULL | TEST2 | 12 | 360 | 298 (1)| 00:00:04 | |* 4 | FILTER | | | | | | |* 5 | TABLE ACCESS FULL | TEST1 | 1521 | 307K| 298 (1)| 00:00:04 | |* 6 | VIEW | | 12 | 204 | 2 (0)| 00:00:01 | | 7 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6601_5F1475 | 12 | 204 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter("B"."OBJECT_ID"<1000) 4 - filter("A"."OWNER"='SCOTT' OR EXISTS (SELECT 0 FROM (SELECT /*+ CACHE_TEMP_TABLE ("T1") */ "C0" "OWNER" FROM "SYS"."SYS_TEMP_0FD9D6601_5F1475" "T1") "TT" WHERE "TT"."OWNER"=:B1)) 5 - filter("A"."OBJECT_ID"<1000) 6 - filter("TT"."OWNER"=:B1)
subquery statement can not unnest:等您坐沙发呢!