HINT优化:
虽然ORACLE如今很智能几乎不用我们去干扰sql语句的执行计划,它就会按照一个正确的执行逻辑执行完你的sql得到你所要的结果。
不过有时面对大量的数据和频繁DML操作的表,ORACLE自己在执行sql 的时候可能也会发生错误,走错执行路径,你可能有时会发现一条很简单的sql语句执行了半天还没出来。这时候你就需要通过查看sql的执行轨迹是否符合正确的最好的那一条。不对的话就需要我们人为的干扰sql的执行,这时候就需要Hint。
优化一个sql的执行计划大致可以从下面几个方向入手:
1:表之间的执行、连接顺序
表之间的关联顺序是很重要的,选定好一个驱动表它直接决定了你所每走一条路上所要查阅的数据量及关联所用的方法。此处只列出与之相关的常用的一些Hint语句:
/*+ order */:按照from后面的表顺序来选定主表
例:select /*+ order */b.name from class a,student b where a.classno = b.classno;
以a为驱动表关联b
/*+ leading(table1,table2) */:比order更加灵活的顺序指定
例:select /*+ leading(a,b) */b.name from class a,student b where a.classno = b.classno;
以a为驱动表关联b
注:有表别名需要括号中的表名需要使用别名
2:表之间的关联
表之间如何关联主要有三种方式:Merge Join([排序]合并联接)、Nested Loops(嵌套循环联接)、Hash Match
我的大致理解为Nested Loops:适合于驱动表数据量较小,连接字段上最好有索引
Merge Join:适用于连接的字段已经排好序,比如连接的字段是一个sequence之类的
Hash join:适用于大表之间的等值连接
/*+ use_nl(table1,table2) */:使用nest loop连接
例:select /*+ use_nl(a,b) */b.name from class a,student b where a.classno = b.classno;
/*+ use_merge(table_1,table2) */:使用merge join连接
例:select /*+ use_merge(a,b) */b.name from class a,student b where a.classno = b.classno;
/*+ use_hash(table1,table2) */:使用hash join连接
例:select /*+ use_hash(a,b) */b.name from class a,student b where a.classno = b.classno;
3:表的访问路劲
表的访问路径主要就是全表扫描还是用索引用什么索引?
/*+full(table_name)*/:对表全表扫描
例:select /*+ use_hash(a) */b.name from class a,student b where a.classno = b.classno;
/*+index(table_name index_name)*/:对表选择索引
例:select /*+ index (a index_a_classno) */a.name from class a where a.classno =1;
/*+ INDEX_FFS(TABLE_Name INDEX_NAME) */:对指定的表执行快速全索引扫描
例:select /*+ INDEX_FFS (a index_a_classno) */a.name from class a where a.classno =1;
/*+ INDEX_JOIN(TABLE INDEX_NAME1 INDEX_NAME2) */
当谓词中引用的列都有索引的时候,可以通过指定采用索引关联的方式,来访问数据
例:select /*+ INDEX_FFS (a index_a_classno index_a_class_level) */a.name from class a where a.classno =1 and a.class_level=3;
另外关于INDEX FULL SCAN和INDEX FAST FULL SCAN的区别在于,前者在对索引进行扫描的时候会考虑大索引的结构,而且会按照索引的排序,而后者则不会,INDEX FAST FULL SCAN不会去扫描根块和分支块,对索引像访问堆表一样访问,所以这两个扫描方式用在不同的场合。如果存在ORDER BY这样的排序,INDEX FULL SCAN是合适的,如果不需要排序,那INDEX FAST FULL SCAN效率是更高的。
4:表的并行度
/*+ parallel(table_name n) */ :在sql中指定执行的并行度,这个值将会覆盖自身的并行度
例:select /*+ parallel(t 10) */t.name from student t;
并行的实现机制是: 首先,Oracle 会创建一个进程用于协调并行服务进程之间的信息传递,这个协调进程将需要操作的数据集(比如表的数据块)分割成很多部分,称为并行处理单元,然后并行协调进程给每个并行进程分配一个数据单元。比如有四个并行服务进程,他们就会同时处理各自分配的单元,当一个并行服务进程处理完毕后,协调进程就会给它们分配另外的单元,如此反复,直到表上的数据都处理完毕,最后协调进程负责将每个小的集合合并为一个大集合作为最终的执行结果,返回给用户。
并行处理的机制实际上就是把一个要扫描的数据集分成很多小数据集,Oracle 会启动几个并行服务进程同时处理这些小数据集,最后将这些结果汇总,作为最终的处理结果返回给用户。
5:优化模式
优化模式其实可前可后。
/*+ ALL_ROWS */:选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化
例:select /*+ all_rows*/t.name from student t;
/*+ FIRST_ROWS(n) */:选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化
例:select /*+first_rows(20)*/t.name from student t;
/*+ FIRST_ROWS*/:不完全的基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化
例:select /*+first_rows*/t.name from student t;
/*+rule*/:基于规则的优化方法(RBO)
例:select /*+rule*/t.name from student t;
ALL_ROWS与FIRST_ROWS的区别在于,FIRST_ROWS可以以最快的速度响应并返回查询结果,相对于查询出某一单挑或者少量数据速度和效率比较好,ALL_ROWS对于查询大量的数据的时候,对于整体的查询结果速度会很快效率更高。
FIRST_ROWS并不完全是CBO模式,还包含了大量的基于规则的优化方式。而9i新增的FIRST_ROWS(N)则完全基于代价的方式,
rule直接就是RBO的基于规则的优化