`

基于索引的SQL语句优化之降龙十八掌

阅读更多

基于索引的SQL语句优化之降龙十八掌

1     前言... 2

2     总纲... 2

3     降龙十八掌... 3

第一掌 避免对列的操作... 3

第二掌 避免不必要的类型转换... 4

第三掌 增加查询的范围限制... 4

第四掌 尽量去掉"IN""OR". 4

第五掌 尽量去掉 "<>". 5

第六掌 去掉Where子句中的IS NULLIS NOT NULL. 5

第七掌 索引提高数据分布不均匀时查询效率... 5

第八掌 利用HINT强制指定索引... 6

第九掌 屏蔽无用索引... 6

第十掌 分解复杂查询,用常量代替变量... 7

第十一掌 like子句尽量前端匹配... 7

第十二掌 Case语句合并多重扫描... 7

第十三掌 使用nls_date_format 8

第十四掌 使用基于函数的索引... 8

第十五掌 基于函数的索引要求等式匹配... 9

第十六掌 使用分区索引... 9

第十七掌 使用位图索引... 9

第十八掌 决定使用全表扫描还是使用索引... 9

4     总结... 10

 

1      前言

客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急剧下降,小型机idle所剩无几,应用服务器断连、超时,严重影响业务的正常运行。因此,称低效的SQL语句为客服业务的‘恶龙’并不过分。数据库的优化方法有很多种,在应用层来说,主要是基于索引的优化。本次秘笈根据实际的工作经验,在研发原来已有的方法的基础上,进行了一些扩充,总结了基于索引的SQL语句优化的降龙十八掌,希望有一天你能用其中一掌来驯服客服业务中横行的‘恶龙’。

2      总纲

l  建立必要的索引

这次传授的降龙十八掌,总纲只有一句话:建立必要的索引,这就是后面降龙十八掌的内功基础。这一点看似容易实际却很难。难就难在如何判断哪些索引是必要的,哪些又是不必要的。判断的最终标准是看这些索引是否对我们的数据库性能有所帮助。具体到方法上,就必须熟悉数据库应用程序中的所有SQL语句,从中统计出常用的可能对性能有影响的部分SQL,分析、归纳出作为Where条件子句的字段及其组合方式;在这一基础上可以初步判断出哪些表的哪些字段应该建立索引。其次,必须熟悉应用程序。必须了解哪些表是数据操作频繁的表;哪些表经常与其他表进行连接;哪些表中的数据量可能很大;对于数据量大的表,其中各个字段的数据分布情况如何;等等。对于满足以上条件的这些表,必须重点关注,因为在这些表上的索引,将对SQL语句的性能产生举足轻重的影响。不过下面还是总结了一下降龙十八掌内功的入门基础,建立索引常用的规则如下:

1、表的主键、外键必须有索引;

2、数据量超过300的表应该有索引;

3、经常与其他表进行连接的表,在连接字段上应该建立索引;

4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;

5、索引应该建在选择性高的字段上;

6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;

7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:

   A、正确选择复合索引中的主列字段,一般是选择性较好的字段;

   B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;

   C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;

   D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;

   E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;

8、频繁进行数据操作的表,不要建立太多的索引;

9、删除无用的索引,避免对执行计划造成负面影响;

以上是一些普遍的建立索引时的判断依据。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。因为太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。 另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大。

3      降龙十八掌

第一掌 避免对列的操作

任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。  

1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢:  

select * from record where  substrb(CardNo,1,4)='5378'(13) 

select * from record where  amount/30< 100011秒) 

select * from record where  to_char(ActionTime,'yyyymmdd')='19991201'10秒) 

由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的,因此它不得不进行表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表扫描,因此将SQL重写如下:

select * from record where CardNo like  '5378%'< 1秒)

select * from record where amount  < 1000*30< 1秒)

select * from record where ActionTime= to_date ('19991201' ,'yyyymmdd')< 1秒)

差别是很明显的!

第二掌 避免不必要的类型转换

需要注意的是,尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致全表扫描。

2:表tab1中的列col1是字符型(char),则以下语句存在类型转换:

select col1,col2 from tab1 where col1>10

应该写为: select col1,col2 from tab1 where col1>'10'

第三掌 增加查询的范围限制

增加查询的范围限制,避免全范围的搜索。

3:以下查询表record 中时间ActionTime小于200131日的数据:

       select * from record where ActionTime < to_date ('20010301' ,'yyyymm')

查询计划表明,上面的查询对表进行全表扫描,如果我们知道表中的最早的数据为200111日,那么,可以增加一个最小时间,使查询在一个完整的范围之内。修改如下: select * from record where

ActionTime < to_date ('20010301' ,'yyyymm')

and   ActionTime > to_date ('20010101' ,'yyyymm')

后一种SQL语句将利用上ActionTime字段上的索引,从而提高查询效率。把'20010301'换成一个变量,根据取值的机率,可以有一半以上的机会提高效率。同理,对于大于某个值的查询,如果知道当前可能的最大值,也可以在Where子句中加上 AND 列名< MAX(最大值)”。

第四掌 尽量去掉"IN""OR"

含有"IN""OR"Where子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。  

4     select count(*) from stuff where id_no in('0','1')23秒)

可以考虑将or子句分开:  

select count(*) from stuff where id_no='0' 

select count(*) from stuff where id_no='1'

然后再做一个简单的加法,与原来的SQL语句相比,查询速度更快。

第五掌 尽量去掉 "<>"

尽量去掉 "<>",避免全表扫描,如果数据是枚举值,且取值范围固定,则修改为"OR"方式。

5

UPDATE SERVICEINFO SET STATE=0 WHERE STATE<>0;

以上语句由于其中包含了"<>",执行计划中用了全表扫描(TABLE ACCESS FULL),没有用到state字段上的索引。实际应用中,由于业务逻辑的限制,字段state为枚举值,只能等于012,而且,值等于=12的很少,因此可以去掉"<>",利用索引来提高效率。

修改为:UPDATE SERVICEINFO SET STATE=0  WHERE STATE = 1 OR STATE = 2 进一步的修改可以参考第4种方法

第六掌 去掉Where子句中的IS NULLIS NOT NULL

Where字句中的IS NULLIS NOT NULL将不会使用索引而是进行全表搜索,因此需要通过改变查询方式,分情况讨论等方法,去掉Where子句中的IS NULLIS NOT NULL

第七掌 索引提高数据分布不均匀时查询效率

索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。A、数据分布不均匀的特殊情况下,选择性不高的索引也要创建。

ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取值范围为枚举值:[01234567]。按照前面说的索引建立的规则,“选择性不高的字段不应该建立索引,该字段只有8种取值,索引值的重复率很高,索引选择性明显很低,因此不建索引。然而,由于该字段上数据值的分布情况非常特殊,具体如下表:

取值范围

1~5

6

7

占总数据量的百分比

1%

98%

1%

而且,常用的查询中,查询DisposalCourseFlag<6 的情况既多又频繁,毫无疑问,如果能够建立索引,并且被应用,那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。

第八掌 利用HINT强制指定索引

ORACLE优化器无法用上合理索引的情况下,利用HINT强制指定索引。

继续上面7的例子,ORACLE缺省认定,表中列的值是在所有数据行中均匀分布的,也就是说,在一百万数据量下,每种DisposalCourseFlag值各有12.5万数据行与之对应。假设SQL搜索条件DisposalCourseFlag=2,利用DisposalCourseFlag列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE因此对索引“视而不见”,从而在查询路径的选择中,用其他字段上的索引甚至全表扫描。根据我们上面的分析,数据值的分布很特殊,严重的不均匀。为了利用索引提高效率,此时,一方面可以单独对该字段或该表用analyze语句进行分析,对该列搜集足够的统计数据,使ORACLE在查询选择性较高的值时能用上索引;另一方面,可以利用HINT提示,在SELECT关键字后面,加上“/*+ INDEX(表名称,索引名称)*/”的方式,强制ORACLE优化器用上该索引。

比如: select * from  serviceinfo where DisposalCourseFlag=1 ;

上面的语句,实际执行中ORACLE用了全表扫描,加上蓝色提示部分后,用到索引查询。如下:

select /*+  INDEX(SERVICEINFO,IX_S_DISPOSALCOURSEFLAG)  */  *

from  serviceinfo where DisposalCourseFlag=1;

请注意,这种方法会加大代码维护的难度,而且该字段上索引的名称被改变之后,必须要同步所有指定索引的HINT代码,否则HINT提示将被ORACLE忽略掉。

第九掌 屏蔽无用索引

继续上面8的例子,由于实际查询中,还有涉及到DisposalCourseFlag=6的查询,而此时如果用上该字段上的索引,将是非常不明智的,效率也极低。因此这种情况下,我们需要用特殊的方法屏蔽该索引,以便ORACLE选择其他字段上的索引。比如,如果字段为数值型的就在表达式的字段名后,添加“+ 0”,为字符型的就并上空串:“||""

如: select * from  serviceinfo where DisposalCourseFlag+ 0 = 6 and workNo =  '36'

不过,不要把该用的索引屏蔽掉了,否则同样会产生低效率的全表扫描。

第十掌 分解复杂查询,用常量代替变量

对于复杂的Where条件组合,Where中含有多个带索引的字段,考虑用IF语句分情况进行讨论;同时,去掉不必要的外来参数条件,减低复杂度,以便在不同情况下用不同字段上的索引。

继续上面9的例子,对于包含

Where (DisposalCourseFlag < v_DisPosalCourseFlag) or (v_DisPosalCourseFlag is null) and ....的查询,(这里v_DisPosalCourseFlag为一个输入变量,取值范围可能为[NULL01234567]),可以考虑分情况用IF语句进行讨论,类似:

IF v_DisPosalCourseFlag =1 THEN

Where DisposalCourseFlag = 1 and ....

 

分享到:
评论

相关推荐

    sql语句优化之降龙十八掌

    本文将详细阐述"sql语句优化之降龙十八掌",逐一解析这十八个优化技巧,帮助你成为SQL优化的高手。 第一掌:避免对列的操作 在编写SQL语句时,尽量避免在WHERE子句中对列进行计算或函数操作,因为这样会导致无法...

    基于索引的SQL语句优化之降龙十八掌.doc

    本文将深入探讨“基于索引的SQL语句优化之降龙十八掌”,帮助数据库管理员和开发者提升SQL执行效率。 1. **前言** SQL优化是数据库性能调优的核心,特别是对于大型系统,一个精心设计的索引策略和优化的SQL语句...

    基于索引的sql语句优化之降龙十八掌

    ### 基于索引的SQL语句优化之降龙十八掌 #### 1. 前言 在大规模的应用场景中,一个未优化的SQL语句可能会导致数据库性能显著下降,进而影响整个系统的稳定性和用户体验。为了应对这种挑战,我们需要掌握一系列针对...

    基于索引的SQL语句优化之降龙十八掌.docx

    【降龙十八掌详解】 1. **第一掌:避免对列的操作** 避免在SQL语句中对列进行函数运算或表达式计算,这可能导致数据库无法使用索引,转而进行全表扫描。应尽可能将这类操作移到查询的外部处理。 2. **第二掌:...

    基于SQL索引优化的降龙十八掌

    【标题】:“基于SQL索引优化的降龙十八掌” 【描述】:这是一份关于SQL索引优化的重要资料,适用于面试准备,提供了宝贵的数据库优化知识。 【标签】:“SQL”、“优化”、“数据优化资料”、“数据库面试题” ...

    sql语句之降龙十八掌

    以上就是"sql语句之降龙十八掌"所涵盖的优化策略,它们旨在帮助开发者写出更高效的SQL语句,避免因细节问题导致的性能瓶颈,从而提升数据库系统的整体运行效率。在实际应用中,应结合具体环境和需求灵活运用,以达到...

    SQL语句索引优化_sql索引降龙十八掌(Oracle)

    让我们一起领略"SQL索引降龙十八掌"的精髓。 一、了解索引 1. 索引类型: - B树索引:最常见的索引类型,适用于等值查询。 - bitmap索引:适用于多列组合查询和数据仓库场景。 - 全文索引:用于全文搜索。 - ...

    基于索引的SQL语句优化

    以下将详细介绍基于索引的SQL优化的“降龙十八掌”,旨在帮助开发者和DBA们更好地理解和应用这些优化技巧。 【降龙十八掌】 1. **避免对列的操作**:在WHERE子句中直接使用列名,避免对列进行计算或函数操作,因为...

    索引的SQL语句优化

    **降龙十八掌**,这里被比喻成18条关键的优化策略,每一条都是针对特定情境下SQL语句优化的实战技巧。它们基于一个核心原则:**建立必要的索引**。这不仅是策略的基石,也是实现高效查询的前提条件。正确的索引能够...

    sql优化加索引[参考].pdf

    本文旨在探讨基于索引的SQL优化策略,通过一系列实践建议,即所谓的“降龙十八掌”,帮助开发者理解和应用索引优化,以解决系统性能问题。 首先,建立必要的索引是优化数据库查询性能的基础。开发者需要对应用程序...

    oracle性能优化

    1. **基于索引的SQL语句优化之降龙十八掌.doc** 这个文件可能详细阐述了利用索引来提升SQL查询性能的18种策略。在Oracle中,索引可以显著加速数据检索。优化SQL语句时,应考虑创建合适的索引,如单列索引、复合索引...

    Oracle优化教材

    本文档详细介绍了基于索引优化的"降龙十八掌",旨在帮助学习者掌握优化技巧,应对数据库性能问题。 一、降龙十八掌详解 1. 避免对列的操作:对列进行函数或计算可能导致全表扫描,应尽量将操作移到等式右侧或避免...

    oracle链接查询

    四、降龙十八掌——基于索引的SQL语句优化策略 1. 龙战于野:避免在索引列上使用非确定性函数,如日期函数、字符串函数等,这会导致无法使用索引。 2. 飞龙在天:使用索引合并(INDEX MERGE)策略,当多个索引可以...

    【IT十八掌徐培成】Java基础第22天-03.MySQL常用命令avi.zip

    本资源"【IT十八掌徐培成】Java基础第22天-03.MySQL常用命令avi.zip"主要涵盖了Java学习过程中的MySQL数据库操作知识。 首先,让我们了解一下MySQL的基本概念。MySQL是一种客户端-服务器结构的数据库系统,它支持...

    【IT十八掌徐培成】Java基础第22天-02.MySQL安装-调错.zip

    总之,【IT十八掌徐培成】的Java基础课程中的MySQL安装与调错部分,将带你走进数据库的世界,掌握基本操作和故障排除技巧,为后续的Java开发工作奠定坚实基础。通过不断实践和学习,你将能够熟练应对各种数据库相关...

Global site tag (gtag.js) - Google Analytics