Oracle执行计划分析是否命中索引

最近一次在数据库查询一条数据时,发现查询速度变得巨慢,看了一下查询的where条件也的确是索引字段,由于是基础服务部开发的数据库查询平台,本觉得是本身平台出的问题,后来发现其余使用用户并无出现这样的问题,确定是SQL自己性能的问题了,因而拿着这个SQL去测试库作了一次执行计划的分析。sql

测试使用工具:DataGrip数据库

执行这句SQL,咱们查看一下执行的时间,执行的时间占用131毫秒,拉取数据占用161毫秒函数

SELECT * FROM PAYADM.RPMTORD WHERE CRE_DT =20171229;工具

9165224-2aacee4913dc154a.png
执行SQL

在Oracle中执行下面的命令,咱们能够看一下这句sql的执行过程:性能

EXPLAIN PLAN FOR SELECT * from PAYADM.RPMTORD WHERE CRE_DT =20171229;测试

SELECT * FROM TABLE (dbms_xplan.display);优化

 下图就是咱们这句命令的执行计划,咱们能够看见在表中第二行Operation中出现“TABLE ACCESS FULL”,意思就是咱们这句sql使用的是“按全表扫描”,而不是索引检索,接着往下看:1 - filter(TO_NUMBER("CRE_DT")=20171229),到这里真相就大白了,CREDT字段在数据库中实际上一个字符串类型,然而咱们where条件中的参数传的是number类型,所以会出现放弃索引,而且每次检索都会作一次TO_NUMBER转换的状况;设计

9165224-d02947a57202d19a.png

而后咱们更正sql后再次执行一下,咱们发现这个时候执行时间是42毫秒,拉取数据占用161毫秒,执行时间上已经比以前提速了89毫秒,拉取数据花费的时间暂不考虑,由于他和是否有索引无关,同时咱们能够看一下此时的执行计划是什么,第二行“Table Access By Index RowID”,此时很明显咱们能够看到这次检索使用的是“按索引查找”。3d

9165224-02f558863e8c23d8.png
更正后的执行SQL
9165224-43129bd6bb398819.png
更正后的执行计划

当前咱们测试环境下表的数据量将近13万条,而咱们实际线上生产环境的数据量已经超过了2000万条,因此全表扫描致使的“慢查询”现象将会变得很是的十分的明显,一个全表扫描能够耗时超过十分钟之上,形成阻塞甚至数据库挂掉。因此咱们不管是在开发仍是在查数据的时候,全部的带有“WHERE”条件的语句都要在测试环境作一次执行计划,以避免出现慢查询的问题。blog

下面收集了其它博主对SQL优化的总结和一些避免全盘扫描的注意事项:

1.应尽可能避免在 where 子句中使用 != 或 <> 操做符,不然将引擎放弃使用索引而进行全表扫描。

2.应尽可能避免在 where 子句中使用 or 来链接条件,若是一个字段有索引,一个字段没有索引,将致使引擎放弃使用索引而进行全表扫描

能够考虑用union

select id from t where num=10 or Name = 'admin' 

能够替换为

select id from t where num = 10

union all

select id from t where Name = 'admin'

3. in  和 not in 也要慎用,不然会致使全表扫描,能够用 exists 代替 in

select id from t where num in(1,2,3)

能够替换为

select id from t where num between 1 and 3

4.若是在 where 子句中使用参数,也会致使全表扫描。

select id from t where num = @num (bad !!!)

5.避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描

select id from t where num/2 = 100

应该为

select id from t where num = 100*2

6.应尽可能避免在where子句中对字段进行函数操做

select id from t where substring(name,1,3) = ’abc’

应改成

select id from t where name like 'abc%'

7.Update 语句,若是只更改一、2个字段,不要Update所有字段,不然频繁调用会引发明显的性能消耗

8.尽可能使用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会下降查询和链接的性能,并会增长存储开销。这是由于引擎在 处 理查询和连 接时会逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了。

9.尽量的使用 varchar/nvarchar 代替 char/nchar,由于首先varchar是一个变长的字段, 变长字段存储空间小,

能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。

10.删除JOIN和WHERE子句中的计算字段

SELECT * FROM sales a 

JOIN budget b ON ((YEAR(a.sale_date)* 100) + MONTH(a.sale_date)) = b.budget_year_month

应改成

SELECT * FROM PRODUCTSFROM sales a 

JOIN budget b ON a.sale_year_month = b.budget_year_month