oracle hint无效,聊聊oracle+hint 的使用

  • Post author:
  • Post category:其他


Oracle拥有非常好的优化算法,尤其是在8i版本之后引入CBO,很多的sql oracle都可以帮我们选择非常好的执行计划,但是有些时候oracle也会犯犯傻,会帮我们选择非常不好的执行计划,这个时候就需要我们来手工的优化优化,帮助oracle 提高下运行效率。

所谓hint,如翻译成中文的意思一样是示意、暗示,就是暗示数据库应该怎么运行。

Hint的语法也很简单,一般就是在select、update、insert后边加一个注释/*+hint*/。

例如有两个表TABLE_A和TABLE_B,想让这两个表关联的时候以hash_join、nest loop、merge join的方式进行关联,就可以这样写:

Select /*+use_hash(a,b)*/ * from table_a a,table_b b where a.id=b.id;

Select /*+use_nl(a,b)*/ * from table_a a,table_b b where a.id=b.id;

Select /*+use_merge(a,b)*/ * from table_a a,table_b b where a.id=b.id;

使用hint的目的是为了提高oracle的执行效率。

1b73b99f0e0f

谈起执行效率,这里我们不得不说下索引,在一个业务订单系统表中,一般会在这个表的时间字段上建立一个索引,当我们想要取某一天的数据的时候,可以直接以这个时间作为一个限制字段,系统正常来说会走索引取出这天的数据,但业务系统很多时候晚上是最忙的时候,这时候oracle中的收集表统计信息的功能大部分是被dba关掉的,所以这就很容易造成一种情况就是oracle根据表统计信息选择执行计划的时候,由于表统计信息过于老旧,oracle会选择一个错误的执行计划。

例如:TABLE_A和TABLE_B 关联之前我们限制了TABLE_A的数据是昨天的数据,sql如下:

Select * from table_a a,table_b b wherea.id=b.id and a.gmt_create>=trunc(sysdate-1) and a.gmt_create

这段sql由于oracle统计信息的老旧可能没有选择table_a 表中gmt_create这个字段的索引(假设索引名字是index_gmt_create),我们就可以用hint加以干预。Sql如下:

Select/*+index(a index_gmt_create)*/ * fromtable_a a,table_b b where a.id=b.id and a.gmt_create>=trunc(sysdate-1) anda.gmt_create

这个时候还发现其实tabe_a这个表经过时间过滤之后数据量变的已经很小,但是table_b还是很大,并且table_b的id字段建立的有索引的时候,便可以再加一个hint让两个表做nest loop关联,sql如下:

Select/*+index(a index_gmt_create)  use_nl(a,b)*/ * from table_a a,table_b bwhere a.id=b.id and a.gmt_create>=trunc(sysdate-1) and a.gmt_create

上面的例子加了两个hint,从中可以看到两个hint我们是用空格隔开的,所以当我们想要在一个sql语句中加多个hint的时候,以空格隔开就可以了。

有的时候,加一个hint可以把数据量变得很小,然而当我们要取的数据很大时,有可能占据了一个表数据的百分之八十,根据索引优化的可能性就没有了。oracle还有一个hint 叫做parallel,中文名叫做并行,一般情况下数据库执行的时候只会选择服务器的一个cpu核心进行计算,但是我们的服务器一般情况下都是多核心的,全表计算的时候加一个/*+parallel(table_name  n)*/(n是要使用的cpu核心数)很多时候比走索引还要快。

上面几个列子都是对select语句加hint的优化,下面我们举一个对insert语句优化的例子。

1b73b99f0e0f

我们知道oracle执行语句的时候会伴随着产生归档日志,这些日志是可以保证读写数据的数据一致性,帮助备份、容灾……

有的时候我们也不一定要这些日志,因为这些日志会影响插入数据的速度。例如当我们想把table_a表中的数据插入到table_b表的时候,想要提高速度,怎么办呢,hint可以帮忙,sql如下:

Insert/*+append*/into table_b select *from table_a;

当然oracle的hint还有很多,今天只找出几个比较有代表性的分享给了大家,希望可以帮助到大家。

本文作者:孙向东(点融黑帮),目前就职于点融网工程部data team,中国象棋,足球爱好者。