关于oracle中什么是内联视图(in-line view)?
内联视图就是from后面再套一个select的子查询,例如:
select ename, job, dname, loc from (select ename, job, deptno
from emp where sal > (select avg(sal) from emp)) emp1,dept
where emp1.deptno = dept.deptno;
写sql的时候,我们还会经常的遇到真正的视图(create view …as select)
select …. from view where ……..;
有时候更变态的是,视图里面还套视图,一直给你套n个视图
在oracle ebs/sap/erp系统中经常遇见,要优化这样的sql,必须改代码
其实,视图套视图…..套一堆的视图,这种设计就是垃圾
如果非要这么设计,必须严格测试性能
本文摘自落落优化博客。
==========================================
每日一句SQL:内联视图
内联视图:
select * from ( select sal as salary,comm as commission from emp ) x where salary <5000
将取别名的查询作为内联视图,便可以在外部查询中引用其中的别名列。为什么要这么做呢?where 字句是在select 之前进行处理的,这样,在处理求解“问题”查询的where子句之前,Salary和Commission并不存在,要到where子句处理完之后,别名才生效。然后,From子句是在where之前处理的。 所以,将原查询放在FROM子句中,那么,在最外层的WHERE子句之前,以及最外层的WHERE子句“看到”别名之前,那么已经生成了查询结果。这个技巧特别有用。
注意:这个解决方案中的内联视图取名为X。并非所有的数据库都需要内联视图显式给内联视图取别名,但一些数据库是这样子的。所有的DB都接受这种方式。
===========================================
OCP考题解析_007: 内联视图优化all或any操作符
any表示数据集中的任何一个、相当于or
x > any (select sal from emp where job='ANA')
等价于:
exists (select sal from emp where job='ANA' and x > sal)
使用ALL和ANY的子查询总是可以用内嵌视图来代替,而且这个视图的性能要好的多,因为它利用了被连接表上的索引。
比如:any操作符
需求:返回所有birthday > 出生于1985年之后的任何客户 的职员名称
- select ename
- from emp
- where birthdate > any
- (select birthdate from customer where birthdate > '31-DEC-1985')
上面的SQL语句可以优化为
- select ename
- from emp,(select min(birthdate) min_bday from customer where birthdate > '31-DEC-1985') in_line_view
- where emp.birthdate > in_line_view.min_bday;
OCP考题:
- Q: 8 Click the Exhibit button and examine the data from the ORDERS and
- CUSTOMERS tables.
- Evaluate this SQL statement:
- SELECT cust_id, ord_total
- FROM orders
- WHERE ord_total > ANY(SELECT ord_total
- FROM orders
- WHERE cust_id IN (SELECT cust_id
- FROM customers
- WHERE city LIKE
- 'New York'));
- What is the result when the above query is executed?
Oracle 内联视图优化,视图合并的抉择
内联视图in-line view,就是sql中from后面有select子查询,或者sql中包含有用create view创建的视图,CBO可能会将内联视图或者视图展开,进行相应的等价改写,这种就叫视图合并。直接看一个sql的执行计划
1. user_tables和dba_objects都是静态数据字典,我们来看下sql的执行计划
可以看到id=12这一步有一个view关键字,这一步正好是提取dba_objects视图的数据,然后此表和id=34这一步进行hash join,但hash join的表并不是sql当中的user_tables,而且在整个执行计划当中都找不到这个视图的信息,此视图被展开了。但这种情况我们是不需要展开的
2. 既然不需要展开,我们直接使用hint禁止视图合并
现在可以在执行计划中看到id=3和id=25这两步都是视图,通过hash join连接。
疑问:为什么这里不需要视图合并?
答曰:如果不视图合并,那整个视图就会当成一整块,在sql执行的时候,这个视图就是一个结果集,然后再去和另一个结果集关联。如果合并了的话,那这个视图就会被拆散,视图里面的关联就会分开run,并不是每次视图合并都是高效的。
在执行计划中,如果看到view关键字,说明视图没有展开,也就是视图没有合并,如果本来sql中有内联视图或者视图,但执行计划中没有看到view关键字,那这个sql就进行了视图合并。
此外还需要注意的是,如果sql中的内联视图有聚合等操作,比如rownum,start with,connect by,union,union all,rollup,cube等,这种内联视图就不能展开,因为内联视图被固化了,碰到这种情况就需要注意,如果内联视图中结果集很大,那sql估计就要改写了,因为这个内联视图会最先执行。
- 本文固定链接: http://www.savedba.com/?p=816
- 转载请注明: 版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!
3.1.1.1 内联视图合并
《Oracle高性能SQL引擎剖析:SQL优化与调优机制详解》第3章查询转换,在本章中,我们将会了解到以下内容:Oracle的逻辑优化技术中,存在哪些启发式查询转换技术,以及它们的具体含义和示例;Oracle的逻辑优化技术中,存在哪些基于代价的查询转换技术,以及它们的具体含义和示例。本节为大家介绍内联视图合并。
3.1.1.1 内联视图合并
我们以下面两个执行计划为例,简要说明视图合并技术对执行计划优化的影响,见代码清单3-1。
代码清单3-1 内联视图合并
- HELLODBA.COM>exec sql_explain('select /*+no_merge(o)*/* from t_tables t, v_objects_sys o where
- t.owner=o.owner and t.table_name = object_name and t.tablespace_name = :A and t.table_name
- like :B and o.status=:C', 'TYPICAL');
- Plan hash value: 3284354748
- ----------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ----------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 3 | 840 | 87 (3)| 00:00:01 |
- |* 1 | HASH JOIN | | 3 | 840 | 87 (3)| 00:00:01 |
- | 2 | TABLE ACCESS BY INDEX ROWID | T_TABLES | 9 | 1836 | 13 (8)| 00:00:01 |
- | 3 | BITMAP CONVERSION TO ROWIDS | | | | | |
- | 4 | BITMAP AND | | | | | |
- | 5 | BITMAP CONVERSION FROM ROWIDS| | | | | |
- |* 6 | INDEX RANGE SCAN | T_TABLES_IDX3 | 184 | | 1 (0)| 00:00:01 |
- | 7 | BITMAP CONVERSION FROM ROWIDS| | | | | |
- | 8 | SORT ORDER BY | | | | | |
- |* 9 | INDEX RANGE SCAN | T_TABLES_PK | 184 | | 2 (0)| 00:00:01 |
- | 10 | VIEW | V_OBJECTS_SYS | 571 | 43396 | 73 (0)| 00:00:01 |
- | 11 | TABLE ACCESS BY INDEX ROWID | T_OBJECTS | 571 | 47393 | 73 (0)| 00:00:01 |
- |* 12 | INDEX RANGE SCAN | T_OBJECTS_IDX1 | 103 | | 3 (0)| 00:00:01 |
- ----------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("T"."OWNER"="O"."OWNER" AND "T"."TABLE_NAME"="OBJECT_NAME")
- 6 - access("T"."TABLESPACE_NAME"=:A)
- 9 - access("T"."TABLE_NAME" LIKE :B)
- filter("T"."TABLE_NAME" LIKE :B AND "T"."TABLE_NAME" LIKE :B)
- 12 - access("STATUS"=:C AND "OWNER"='SYS' AND "OBJECT_NAME" LIKE :B)
- filter("OBJECT_NAME" LIKE :B)
- PL/SQL procedure successfully completed.
- HELLODBA.COM>exec sql_explain('select * from t_tables t, v_objects_sys o where t.owner=o.owner and
- t.table_name = object_name and t.tablespace_name = :A and t.table_name like :B and o.status=:C',
- 'TYPICAL OUTLINE');
- Plan hash value: 2603737735
- -----------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- -----------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 3 | 843 | 16 (7)| 00:00:01 |
- | 1 | TABLE ACCESS BY INDEX ROWID | T_OBJECTS | 1 | 77 | 3 (0)| 00:00:01 |
- | 2 | NESTED LOOPS | | 3 | 843 | 16 (7)| 00:00:01 |
- | 3 | TABLE ACCESS BY INDEX ROWID | T_TABLES | 3 | 612 | 7 (15)| 00:00:01 |
- | 4 | BITMAP CONVERSION TO ROWIDS | | | | | |
- | 5 | BITMAP AND | | | | | |
- | 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
- |* 7 | INDEX RANGE SCAN | T_TABLES_IDX3 | 184 | | 1 (0)| 00:00:01 |
- | 8 | BITMAP CONVERSION FROM ROWIDS| | | | | |
- | 9 | SORT ORDER BY | | | | | |
- |* 10 | INDEX RANGE SCAN | T_TABLES_PK | 184 | | 2 (0)| 00:00:01 |
- |* 11 | INDEX RANGE SCAN | T_OBJECTS_IDX1 | 1 | | 2 (0)| 00:00:01 |
- -----------------------------------------------------------------------------------------------------
- Outline Data
- -------------
- /*+
- BEGIN_OUTLINE_DATA
- USE_NL(@"SEL$F5BB74E1" "T_OBJECTS"@"SEL$2")
- LEADING(@"SEL$F5BB74E1" "T"@"SEL$1" "T_OBJECTS"@"SEL$2")
- INDEX(@"SEL$F5BB74E1" "T_OBJECTS"@"SEL$2" ("T_OBJECTS"."STATUS" "T_OBJECTS"."OWNER"
- "T_OBJECTS"."OBJECT_NAME"))
- BITMAP_TREE(@"SEL$F5BB74E1" "T"@"SEL$1" AND(("T_TABLES"."TABLESPACE_NAME")
- ("T_TABLES"."TABLE_NAME" "T_TABLES"."OWNER")))
- OUTLINE(@"SEL$2")
- OUTLINE(@"SEL$1")
- MERGE(@"SEL$2")
- OUTLINE_LEAF(@"SEL$F5BB74E1")
- OPTIMIZER_FEATURES_ENABLE('10.2.0.4')
- IGNORE_OPTIM_EMBEDDED_HINTS
- END_OUTLINE_DATA
- */
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 7 - access("T"."TABLESPACE_NAME"=:A)
- 10 - access("T"."TABLE_NAME" LIKE :B AND "T"."OWNER"='SYS')
- filter("T"."OWNER"='SYS' AND "T"."TABLE_NAME" LIKE :B AND "T"."TABLE_NAME" LIKE :B)
- 11 - access("STATUS"=:C AND "OWNER"='SYS' AND "T"."TABLE_NAME"="OBJECT_NAME")
- filter("OBJECT_NAME" LIKE :B)
- PL/SQL procedure successfully completed.
示例分析:上面第一个执行计划是未使用视图合并(通过提示强制)所生成的执行计划。它为视图V_OBJECTS生成了一个子计划(即操作10~12)。该计划从视图查询语句及主查询中获得的谓词条件为("STATUS"=:C AND "OWNER"='SYS' AND "OBJECT_NAME" LIKE :B),并且优化器估算出它会返回571条数据记录。在这种情况下,优化器选择其与另外一个表T_TABLES做哈希关联,估算代价为49。
第二个执行计划使用了视图合并技术,在选择执行计划之前,用视图的依赖表T_OBJECTS替换了视图V_OBJECTS,并且将视图查询中WHERE条件"OWNER"='SYS'与主查询WHERE条件"STATUS"=:C和关联条件"T"."TABLE_NAME"="OBJECT_NAME"合并,最终决定由这些条件访问索引T_OBJECTS_IDX1后与表T_TABLES做嵌套关联,估算代价仅为9。
==============================Oracle更新的两种方式(merge/update内联视图)
对于Oracle的两表联合更新的场景(有A、B两表,以A.id=B.id关联,根据B表中的记录更新A表中的相应字段),一般有update内联视图和merge两种方式,下面举例介绍:
创建用例表:
CREATE TABLE test1(IDNUMBER(10),NAME VARCHAR2(20));
INSERT INTO test1VALUES(1,'lucy');
INSERT INTO test1VALUES(2,'lily');
CREATE TABLE test2(IDNUMBER(10),NAME VARCHAR2(20));
INSERT INTO test2VALUES(1,'lucy');
INSERT INTO test2VALUES(2,'hanmeimei');
merge方式:
MERGE INTO test1USING test2
ON (test1.id =test2.id)
WHEN MATCHED THENUPDATE
SET test1.name =NVL2(test1.name,test2.name,test1.name);
merge方法是最简洁,效率最高的方式,在大数据量更新时优先使用这种方式。
update内联视图方式:
使用这种方式必须在test2.id上有主键(这里很好理解,必须保证每一个test1.id对应在test2里只有一条记录,如果test2中有多条对应的记录,怎么更新test1?),一般而言这种方式代价比merge方式稍高。
ALTERTABLE test2 ADD CONSTRAINT pk_test2 PRIMARY KEY(ID);
UPDATE (SELECT a.idaid,a.name aname,b.id bid,b.name bname FROM TEST1 a,test2 b WHERE a.id=b.id) t
SETaname = NVL2(aname,bname,aname);
使用并行,加快大量数据更新:
MERGE /*+parallel(test1,4)*/ INTO test1 USING test2
ON (test1.id =test2.id)
WHEN MATCHED THENUPDATE
SET test1.name =NVL2(test1.name,test2.name,test1.name);
oracle 内联视图 谷歌