控制连结的强制关键字:
循环嵌套:select /*+ leading(emp,dept) use _nl(emp) */ ename,empno,dname,loc from emp,dept where emp.deptno=dept.deptno;
以emp为驱动一次性取出所有满足where筛选的数据逐行匹配内层的dept表,根据连结条件查询符合条件的dept行。改变驱动表可以看到不同的执行计划,优化器会选择最低cost。
特点:最低内存消耗,耗时长,用于小结果集的查询效果很好。
排序-合并连结:select /*+ ordered */ ename,empno,dname,loc from emp,dept where emp.deptno=dept.deptno;
这种连结先将两个表分别排序然后再合并。排序消耗内存巨大,但是一旦完成排序则很快产生合并结果。合并时轮流操作两个表,比较最上层数据丢弃序列中出现比另一表最上一行更早数据。特点:如果没有合适的用于连结键直接访问数据的索引,那么使用排序连结。谓语为where emp.deptno between 20 and 30这类。
hash连结:select /*+ use_hash(dept,emp) */ ename,empno,dname,loc from emp,dept where emp.deptno=dept.deptno;
和循环嵌套连结不同,仅仅读取两个表数据各一次。这种连结同时读取两个表到内存(不够大时使用临时表空间),生成连结键hash然后使用生成最少数据行的表完全散列到内存,匹配位桶中的hash,生成结果。前提必须是相等连结条件。
笛卡尔连结不须赘述,伪代码如下:
determine the smaller table --此处假设小表为dept
select dname,loc from dept
select ename,empno from emp
for each row in dept match it to every row in emp retaining all rows
需要特别关注的是如果sql书写的时候不注意产生了笛卡尔连结,必须优化重写sql 而不是简单的添加一个distinct,这样的语句对于大查询来说将是性能灾难。
索引
索引唯一扫描 select * from emp where empno =7369; ##条件empno有索引,从根到叶子块遍历,读取数据块次数为索引高度+1
索引范围扫描 略
索引全扫描 略
索引跳跃扫描:复合索引,谓语不是引导列且子索引不多
索引快速扫描:结果集是索引键,通过扫描索引代替全表扫描
查询转换
视图合并、连结消除、排序消除、子查询解嵌套、谓词进动、物化视图重写查询
子查询解嵌套和视图合并的区别是子查询解嵌套发生在谓语中有子查询,而视图合并发生在select后面。in、not in、exists、not exists都可解嵌套。然后转化成连结查询。
连结消除发生在仅仅在连结键出现且消除后并不影响结果集,用于:1、父字表外键消除 2、外连结 限制:select以外的地方有连结键 、外键包含多列不支持。
排序消除经常发生在order by子句后的数据是被优化器选择的索引。
谓词进动一句话:能早完成的工作绝不拖到下一步。
物化视图重写顾名思义,实验未成功待定。