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

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

测试使用工具:DataGrip

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

SELECT * FROM PAYADM.RPMTORD WHERE CRE_DT =20171229;

执行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转换的情况;

Oracle执行计划分析是否命中索引_第1张图片

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

更正后的执行SQL
Oracle执行计划分析是否命中索引_第2张图片
更正后的执行计划

当前我们测试环境下表的数据量将近13万条,而我们实际线上生产环境的数据量已经超过了2000万条,所以全表扫描导致的“慢查询”现象将会变得非常的十分的明显,一个全表扫描可以耗时超过十分钟之上,造成阻塞甚至数据库挂掉。所以我们无论是在开发还是在查数据的时候,所有的带有“WHERE”条件的语句都要在测试环境做一次执行计划,以免出现慢查询的问题。

下面收集了其它博主对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 语句,如果只更改1、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

你可能感兴趣的:(Oracle执行计划分析是否命中索引)