别再给SQL加Hints了,它真的是“灵丹妙药”吗?
在Oracle中,Hints是用来约束型优化器行为的一种技术,用来辅助DBA用来做性能排查和优化,尽量避免在开发中使用!毕竟数据是不断变化的,大多数情况下我们应该让Oracle自行决定采用什么执行计划!
接下来就介绍一下Hints的应用场景...
1.表之间的连接
1.1 nested loops join
NESTED LOOP 一般用在连接的表中有索引,并且索引选择性较好的时候,对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。
Hints引导嵌套循环连接
select /*+ leading(test_1) use_nl(test_2)*/ *
from test_1,test_2 where test_1.name = test_2.name说明:
LEADING(test_1) 强制指定外表即即驱动表
Use_NL: 使用嵌套循环连接,即内表
1.2 hash join
HASH JOIN一般用在两个表的数据量差别很大的时候,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
Hints引导hash join连接
select /*+ leading(test_1) use_hash(test_2)*/ *
from test_1,test_2 where test_1.name = test_2.name说明:
LEADING(test_1) 为内存建立的hash表
use_hash: 较大的表并探测散列表,进行哈希连接
1.3 merge sort join
merge sort join用在没有索引,并且数据已经排序的情况,merge join需要首先对两个表按照关联的字段进行排序,分别从两个表中取出一行数据进行匹配,如果合适放入结果集.
Hints引导merge sort join连接
select /*+ leading(test_1) use_merge(test_2)*/ *
from test_1,test_2 where test_1.name = test_2.name说明:
LEADING(test_1) 表排序,作为引导
use_merge:排列合并连接
2.直接加载
INSERT的时候可通过APPEND选项不产生归档日志,以直接加载的方式插入数据。
append 属于direct insert,一是减少对空间的搜索;二是有可能减少redolog的产生。所以append方式会快很多,一般用于大数据量的处理。
1.用marge快速插入MERGE /*+ append */
INTO A d
USING (select * B where ...) f
ON (d.account_no = f.account_no)
WHEN MATCHED THEN
update set acc_date = f.acc_date,...
WHEN NOT MATCHED THEN
insert values ( f.account_no,f.acc_date..)
/
commit;
2.结合并行快速插入
insert /*+ append, parallel */
into ods_list_t nologging
select * from ods_list;
3.表连接的顺序
/*+ leading() */ 规定表连接的顺序,执行计划的顺序一般是按照,先从最开头一直往右看,直到看到最右边的并列的地方,对于不并列的,靠右的先执行:对于并列的,靠上的先执行。
4.访问路径
数据访问路径的选择和优化是一个复杂的过程,需要综合考虑多个因素.
4.1 index unique scan
适合唯一索引的情形,对唯一索引或者对主键列进行等值查找,就会走INDEX UNIQUE SCAN
hint指定一般用
/*+ index(table_name index_name) */
4.2 INDEX RANGE SCAN
大于,小于、或者普通索引等情况,对唯一索引或者主键进行范围查找,对非唯一索引进行等值查找,范围查找,就会发生INDEX RANGE SCAN,等待事件为db file sequential read。
hint指定一般用
/*+ INDEX(table_name index_name) */
4.3 INDEX FAST FULL SCAN
表示索引快速全扫描,多块读,当需要从表中查询出大量数据但是只需要获取表中部分列的数据的,或者统计计数的时候,我们可以利用索引快速全扫描代替全表扫描来提升性能。
hint指定一般用
/*+ INDEX_FFS(table_name index_name) */
4.4 INDEX FULL SCAN
表示索引全扫描,单块读,返回的数据是有序的,如果索引很大,会产生严重性能问题(因为是单块读)等待事件为db file sequential read。
hint指定一般用
/*+ INDEX(table_name index_name) */
4.5 index skip scan
表示索引跳跃扫描,where过滤条件对组合索引中非引导列进行过滤的时候就会发生索引跳跃扫描,等待事件为db file sequential read。
hint指定一般用
/*+ index_ss(table_name index_name) */
5.其他
/*+ dynamic sampling */ – 设置动态采样的级别
/+* PARALLEL */ – 指定并行度
/*+ DRIVING_SITE() */ – 决定一个分布式事物中,操作在哪个节点上完成
/*+ cardinality() */ – 模拟一个结果集的cardinality
总结
不建议在代码中使用hint,在代码使用hint使得CBO无法根据实际的数据状态选择正确的执行计划,毕竟 数据是不断变化的,大多数情况下我们应该让Oracle自行决定采用什么执行计划。但是它可以辅助来帮助我们分析SQL的执行计划。
👇🏻关注微信视频号「jeames007」,直播见!