with as的写法, 有一个专有名词, 叫common table expression, 简称CTE,很多开发人员把使用这种写法当成一个提高SQL执行效率的方法, 事实究竟如何, 请往下看.
在 oracle优化培训之<SQL写法与改写>第二期 的课程中, 我给学员讲了with as的几个用途,下面逐一介绍:
1. 通过materilize生成临时表, 达到优化SQL目的.
比如一个大表(或一段查询块), 在SQL中被多次使用, 每次访问表, 都有一些共同的过滤条件, 过滤之后, 结果集变小, 这种情况就比较适合使用with as的写法. 注意, 不要以为使用了with as, 就能提高性能, 使用不当反而会降低性能. 只在特定情况下才能提升效率.
我的另一篇公众号文章 记一个Enq: ss - contention性能问题处理 , 就是这样一个案例, 不过这个案例的最佳解决方案是进一步改写, 表只需要被访问一次.
相关知识点:
如果with as 查询块被使用2次或两次以上, 会自动做materialize, 如果不想被物化, 可以使用/*+ inline */的hint ;
如果查询块只被调用一次, 默认不会做materialize, 可以用/*+ materialize*/的hint来使其物化生成临时表.
注意:如果返回列中含有lob字段, 不能被materialize.
在12.2及以上版本中, materialize 有个新特性, 叫CURSOR DURATION MEMORY, 可以把结果集保存在内存中, 而不是写到temp表空间, 可以提升效率.
2.提高代码可读性
使代码有层次感, 增强可读性, 下面是对连续编号进行分组的一个写法:
with t as
( select rownum+1 as id from xmltable('1 to 5')
union
select rownum+10 from xmltable('1 to 4')
union
select rownum+20 from xmltable('1 to 2')
union
select rownum+30 from xmltable('1 to 3')
)
,mid1 as (select id,nvl(id-1-lag(id) over (order by id),0) as cal_id from t)
,mid2 as (select id,sum(cal_id) over (order by id) as sum1 from mid1)
select id,dense_rank() over (order by sum1) as group_no
from mid2
order by id;
对复杂的SQL, 都可以考虑使用这种写法, 增强代码的可读性.
3.实现递归算法
下面是计算9以内阶乘的写法
WITH temp (n, fact) AS
(SELECT 0, 1 from dual
UNION ALL
SELECT n+1, (n+1)*fact FROM temp
WHERE n < 9
)
SELECT * FROM temp;
connect by层级查询语法,很多都可以使用with as的递归写法替代实现.
4. 12c新特性 inline function, SQL里面可以内嵌函数
如下面示例(这个with , 没有as):
WITH
function cal_new_sal(p_sal number, p_hiredate date)
return number
is
begin
return p_sal*(1+ceil((sysdate-p_hiredate)/365)*0.05);
end;
select empno,ename,sal,hiredate
,cal_new_sal(sal,hiredate) as new_sal
,1+ceil((sysdate-hiredate)/365)*0.05 as factor
from emp;
/
function代码没有保存在数据库中.
5.构造测试用例用临时数据
前面提高代码可读性的示例已经用到了, 下面示例是在19c之前, 使用listagg并去重的一种写法, with as的作用是生成了几行测试记录, 避免了建表和插入记录的麻烦:
with test_data(col1,col2,created_by) as
(
select 1, 2, 'Smith' from dual
union all select 1, 2, 'John' from dual
union all select 1, 3, 'Ajay' from dual
union all select 1, 4, 'Ram' from dual
union all select 1, 5, 'Jack' from dual
union all select 2, 5, 'Smith' from dual
union all select 2, 6, 'John' from dual
union all select 2, 6, 'Ajay' from dual
union all select 2, 6, 'Ram' from dual
union all select 2, 7, 'Jack' from dual
)
SELECT col1 ,
listagg(col2 , ',') within group (order by col2 ASC) AS orig_value,
listagg(CASE WHEN rn=1 THEN col2 END , ',') within group (order by col2 ASC) AS distinct_value
from
(
select a.*,row_number() over (partition by col1,col2 order by 1) as rn from test_data a
) a
GROUP BY col1;
总结:
用的最多的功能应该是提高代码可读性; 利用 materialize 特性优化SQL, 也是开发人员需要考虑的.
本文分享自 老虎刘谈oracle性能优化 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!