目录
查询转换
查询转换是指把经过语法、语义分析的查询块之间的连接类型、嵌套关系进行调整,生成一个更好的查询计划。
查询转换是优化器自动做的,在生成执行计划之前,等价改写查询语句的形式,以便提升效率和产生更好的执行计划。它决定是否重写用户的查询,常见的转换有谓词传递、视图拆分、谓词推进、关联/非关联子查询改写等。
谓词传递
原理:根据A=B,B=C,可以推导出A=C
--原始sql
select * from t1 inner join t2
on t1.c2=t2.c2
where t1.c1=100
and t2.c1=t1.c1
--CBO转换后,等价于下面的sql
select * from t1 inner join t2
on t1.c2=t2.c2
where t1.c1=100
and t2.c1=t1.c1
and t2.c1=100 –-谓词传递
视图拆分
--视图定义
create or replace view v_t1 as
select t1.c1+t2.c1 as c11,
t2.c2,t1.c1
from t1,t2
where t1.c2=t2.c2;
--原始sql
select a.c11,b.c2
from v_t1 a,t1 b
where a.c1=b.c1
and a.c1=100;
观察原始sql的执行计划,发现视图部分的子计划已经没有了。说明优化器进行等价改写,将视图的查询拆散了,和其他部分作为一个整体来生成计划。视图拆分有很多限制,如果视图查询中含有distinc、union、group by等操作,优化器就无法进行视图拆分。
sql中使用过多的视图,会使sql变得复杂,优化器也难以生成最佳的执行计划,不能过度依赖优化器进行视图拆分。开发时应尽量减少视图的使用。
谓词推进
--原始sql,子查询x相当于一个内联视图
select * from
(select c1,c2 from t1 where c2='C') x
where c1=100;
观察执行计划,由于C2字段无索引,子查询X部分本应该走全表扫描,但是计划中却走了C1字段的索引。说明优化器对原始sql做了如下的等价改写,将条件c1=100推到子查询X中:
--查询转换
select * from
(select c1,c2 from t1 where c2='C' and c1=100) x;
非关联子查询的转换
--原始sql
select * from t1
where c1 in (select c1 from t2 )
and c2='A';
观察原始sql,T2的子查询是个非关联的子查询,完全可以把它生成一个独立的子计划。但是计划中TI和T2做了关联,说明优化器进行了如下的等价改写:
--查询转换
select * from t1
where exists (select 1 from t2 where t1.c1=t2.c1)
and c2='A';
外连接转换
--原始sql
select t1.c1,t2.c2
from t1 left join t2
on t1.c1=t2.c1
where t2.c1=100 and t1.c2='A';
观察计划发现,原始sql是外连接,计划中却变成了内连接。这是优化器根据sql语义判断,就是等价于下面的内连接:
--查询转换
select t1.c1,t2.c2
from t1 inner join t2 on t1.c1=t2.c1
where t2.c1=100 and t1.c2='A';