SQL没法走索引的状况及解决思路

上次丁俊大师在社群上作了CBO优化器和坑爹案例的分享后,反响不是通常的强烈,但其中也有一部分同窗表示过高大上了(我也是这样以为的),消化起来至关有难度,因而便有了本文。绕开复杂的CBO优化器不说,本文将帮你理清那些由于SQL语句编写规范问题致使没有充分利用索引来大幅提高效率的使用场景。html

1、SQL没法走索引的状况及解决思路linux

由于数据库优化器不够智能,或者一些逻辑缘由,致使SQL在比较适合走索引的状况下却没法正确利用索引。这时候,除了给数据库须要的统计信息以外,SQL语句自己还必需要给优化器足够多的额外有效信息,帮助优化器可以选择更好的执行计划。要让优化器正确选择须要的索引,要考虑两点:sql

  • 如何避免优化器的限制
  • 根据业务数据特色改写SQL语句

说明:这里说的走不了索引,是指走不了正常的RANGE SCAN,非(FAST) FULL INDEX SCAN。数据库

SQL没法走索引常见的有以下8种状况:运维

  1. 统计信息不许确
  2. 索引列的值容许为NULL
  3. 谓词使用了不等于(<>, !=)
  4. LIKE前通配或全通配的查询
  5. 索引列使用了函数、数学运算、其它表达式等
  6. 使用了隐式类型转换
  7. 查询转换失败
  8. 其它语句逻辑缘由

第1、二种状况在现实中比较常见,解决办法也相对比较简单,下面就再也不做详细展开了。ide

谓词使用了不等于(<>,!=),走不了索引函数

解决方法:工具

  1. 若是不等条件以外的值很少,并且是肯定的,能够改成等值或IN查询,好比status状态字段通常值类别不多;
  2. 若是不等条件以外的值不少,能够改成“> OR <”的形式,固然第2种方法包含了方法1。

举个例子,先构建测试场景:性能

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

谓词使用<>,没法利用索引:测试

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

将<>改写为OR链接后,可以正确使用索引,走OR扩展:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

若是业务容许,改写为下列语句也是走索引的,再也不演示。

SELECT * FROM t WHERE t.NAME IN (‘ORADB1′,’ORADB2′,’ORADB3’);

LIKE前通配或全通配的查询,走不了索引

解决方法,有以下三种:

(1)根据业务需求,是否能够把前通配去掉

原来全通配,没法走索引:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

把前通配去掉,改成后通配,能够正常使用索引:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

(2)和此LIKE同样的前通配或全通配的SQL有不少,此谓词的LIKE变化不大?若是是,考虑创建函数索引,不然对于全通配问题最好办法就是全文索引。

建立instr函数索引:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

(3)若是只是前通配,可使用reverse函数索引(不是翻转键索引)

原始语句:
SELECT  * FROM t WHERE t.NAME LIKE ‘%ORADB1’;

建立reverse函数索引,并改写语句,注意查找值要倒序:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

注意:若是通配查询的是中文,要注意使用REVERSE翻转条件值,由于REVERSE内部会按字节翻转的,正确写法如:

SELECT * FROM t WHERE REVERSE(t.name) LIKE REVERSE(‘数据’)||’%’;

不然查询出来的数据不对,将可能影响到业务的正常运行。

索引列使用了函数、数学运算、其余表达式等,走不了索引

解决方法:去掉对索引列的相关运算,保持索引列纯净。

目前优化器对一些数学运算,还没法作很好的消除动做,因此对于索引列应该尽可能保持纯净,不然可能没法用上正确的索引。

举例:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

把语句的条件改写一下,将运算去掉:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

以上例子只是简单的数学运算,可能的运算还有和其余列运算,好比where ID+ext_col…

记住一个原则:尽可能保持索引列纯净。

使用了隐式类型转换,走不了索引

解决方法:必须避免隐式类型转换,所有要求显式类型转换(非索引列),且避免对索引列进行类型转换(有函数索引除外)。若是类型不一致,无论是否发生自动类型转换,谓词的右值应该显式转换为与索引列保持一致(对于非索引列的运算也应该如此)。

举例:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

从以上两次查询对比来看,第一次查询发生了类型转换,能够经过执行计划中的谓词信息获知。经过分析发现,X由于是VARCHAR2,优先级比数值类型低,遇到数值类型,会TO_NUMBER隐式转换,因此索引失效。第二次查询,经过传入与索引列类型一致的字符串后,得以解决。

查询转换失败,走不了索引

查询转换是很是复杂的过程,ORACLE CBO的查询转换有好几十种,好比CVM :complex view merging ,SU:subquery unnest, JPPD:JOIN PREDICATE PUSH DOWN等(在10053文件里均可以看到)。若是查询转换失败,那么必将影响后续优化器的一些操做,好比JPPD中JOIN谓词没法推入到视图中,那么极可能视图就没法走索引了。并且,查询转换有不少BUG,触发BUG须要找到缘由,好比设置隐含参数、fix control等,或者改写SQL绕过BUG。以下例所示:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

其中AB_XRTOFFREC_201703是UNION ALL查询组成的视图,这个查询在10.2.0.4上很正常,升级到11.2.0.4后执行计划显示不走索引,性能很是差。

在10g中的执行计划:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

在11g中的错误执行计划:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

经过收集统计信息都无效,将优化器降级到10.2.0.4即有效。很显然,这是引入了BUG或者新的限制。一旦遇到这种是BUG或限制致使的,能够经过10053跟踪文件或者SQLT来进行分析。对于这条语句没法走JPPD查询转换,在10053中就能够找到缘由:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

而后在MOS中查看得知是BUG:9380298,默认开关关闭。

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

ORACLE针对这样的查询,为了防止遇到笛卡尔积,默认把修复BUG的补丁关闭了。显然经过设置_fix_control参数打开9380298 fix便可。

语句逻辑问题,致使优化器选择不了索引

举一个典型的例子,先准备测试表,并在其上建立一个组合索引:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

查询需求:查找建立时间是2013年的,而且最后ddl时间比建立时间大1天以上的对象。

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

这个索引是组合索引,上面的语句对前导列进行了运行,也不符合走index skip scan的条件,因此,走FULL TABLE SCAN。那么是否能够经过逻辑改写走索引呢,基于保持索引列纯净的原则,将create_date移到右边,语句以下:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

改写后发现,仍是没有走索引,由于Oracle认为前导列右边的created不固定,没法从指定索引处查找。经过分析得知,Oracle谓词传递有必定限制,create_date+1没法作谓词传递给last_ddl_time。再次改写:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

此时Oracle知道将谓词传递给last_ddl_time了,T.LAST_DDL_TIME>=TO_DATE(‘ 2013-01-01 00:00:00’, ‘syyyy-mm-dd hh24:mi:ss’)。固然,也能够手动谓词传递,last_ddl_time确定大于等于DATE’2013-1-2′

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

还未完,咱们继续往下看:

若是查询条件中无t.created>=DATE’2013-1-1’,即以下面语句:

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

–由此两数据比较可知,应该走索引更佳。由于没有其余过滤条件,能够考虑创建函数索引:

SQL> CREATE INDEX idx1_t_object ON t_objects(last_ddl_time-created);

–注意收集直方图,由于分布不均

SQL> exec dbms_stats.gather_table_stats(ownname => USER,tabname => ‘t_objects’,estimate_percent => 100,method_opt => ‘for all indexed columns’,cascade => TRUE);

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

固然,对于两个都是范围的查询,这里只能经过一个列来轮询索引,先作access,再作filter。

SQL语句的逻辑改写很重要,每每经过逻辑改写就能改变SQL的执行计划,从很差的计划到好的计划,好比semi join,anti join与or,每每走FILTER致使执行计划较差,这时候就须要经过逻辑等价改写。逻辑等价改写每每须要掌握一些集合的知识,好比NOT (A AND B)==NOT A OR NOT B,NOT (A OR B)==NOT A AND NOT B等。

总结

SQL有索引而不走索引的状况还有不少,好比在DBLINK查询中,可能走不了索引,这时候须要经过driving_site hint或者远程库创建视图等方式解决等,须要综合从语法语义、索引选择性、索引访问特色等多方面进行分析。

2、如何将SQL开发规范落地

上面说到的问题,说到底都是不遵照数据库开发规范的问题。说到数据库开发规范,估计不少企业都有制定对应的规范及要求,但说到落地执行状况,这个就比较困难了。若是企业在乎旨上是指望开发人员去学懂规范,而后学以至用,就有点太理想化了。因而,为了保证开发人员真的是按照数据库开发规范来编写代码,不少企业就在应用上线前增长了一道SQL上线审核的工序。

说到SQL上线审核,关键要解决三个问题:

一、如何在上线的应用版本中发现新增的SQL语句;

二、新增SQL存在哪些问题,如何快速准确的定位;

三、对于问题SQL,如何快速提供优化方案。

这三个问题,是一环扣一环的,解决不了前面的问题,就无从解决后面的问题。然而,应用系统SQL众多,若是单靠人工,难度是很大的,专家资源投入就更不说了,显然不能知足当今IT系统高速发展的须要。

这里跟你们分享咱们在这方面的一些实践和成果。经过结合多年的运维和优化经验,咱们自主研发了SQL审核工具,不只能够自动化完成SQL上线审核,还能够作到SQL的性能监控和自动优化,达到SQL全生命周期管理的效果。对于SQL上线审核,咱们将开发规范规则化后落到SQL审核平台,内置了4个维度、200多种常见的审查规则,还支持灵活的按需添加规则。同时,审查的不仅是SQL语句自己,还包括了对表的模型设计、索引的构建。

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

在应用新版本上线前,经过SQL审核平台,自动分析出版本的新增SQL,基于以上规则对新增SQL进行审查,并自动提供优化建议,可生成可视化的报表和详细报告。无论是DBA仍是开发人员均可以基于此平台,对问题进行确认和解决,实现系统优化前移、提高应用版本质量的目标。

SQL没法走索引的状况及解决思路SQL没法走索引的状况及解决思路

3、总结

本文主要和你们分享了SQL没法走索引的一些常见情景及解决方法,固然,SQL的规范化使用是十分重要的,SQL的优化也不只仅局限于索引的优化。因此,只有平时多积累,结合理论多实践,遇到问题时才能指挥若定,对症下药、药到病除。另外,企业在IT建设中要重视开发规范的落地执行,必要时使用合适的工具,在加速IT环境建设效率的同时,还能兼顾到IT系统的建设质量,作到两不误。

原文来自:https://www.linuxprobe.com/sql-solution-ideas.html

相关文章
相关标签/搜索