SQL规范与性能(关于索引)

SQL规范与性能

 

说明:仅针对mysql 5.5.21 + innodb存储引擎

文档版本:  v1.0

 

. 索引的优缺点... 2

. innodb索引特点与原理&explain. 2

2.1 innodb索引特点... 2

2.2  explain查看执行计划... 3

三.创建索引列的选择判断... 4

. 索引规范与性能... 4

4.1 join连接方式代替子查询... 4

4.2索引在外嵌套层(派生表)失效... 5

4.3 like如何利用索引... 5

4.4字符类型隐性转换导致索引失效... 7

4.5勿对索引列修饰(比如:对列计算,对列使用函数等)... 7

4.6去除不必要的order bygroup by. 8

4.7去除不必要的外嵌套层... 9

4.8减少不必要的自连接... 10

4.9利用索引避免排序(order by ) 11

4.10 where条件中or如何使用索引... 12

4.11使用前缀索引与覆盖索引... 12

4.12使用索引最左侧特性... 14

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

. 索引的优缺点

1)、优点:加快查询速度

2)、缺点:增加DML的维护成本

#从下图可以看出,增加5个索引后,插入同样的数据量时间由0.02s->0.04s,

增加了插入的时间;

. innodb索引特点与原理&explain

2.1 innodb索引特点

1)、组合索引最左侧原则(一般情况:最左侧索引列须存在于where条件中)

2)、聚簇索引与辅助索引关联: 每个普通索引(辅助索引,有些称为二级索引)的索引列后会自动添加主键列键值)

#箭头方向代表:根据辅助索引列的后面自动添加的主键值访问主键索引(聚集索引),再通过聚焦索引的值来访问对应的行;

3)、包含键值且键值按大小排序存放,如以下2列组合索引值的存放顺序:a->b->c, 同时为a类的后面列值也是按序排序:1->2

 ('a',1),('a',2),('b',1),('b',2),('b',3),('c',1),('c',2)

 

2.2  explain查看执行计划

主要讲述type类型(如下表性能从左到右,由低向高)

ALL

index

range

ref

eq_ref

const,system

NULL

 

ALL: 全表扫描 ,index: 索引全扫描 ,range: 索引范围扫描 ,ref: 使用非唯一索引或唯一索引前缀扫描 ,eq_ref: 使用主键或唯一索引扫描 ,const,system: 查询结果最多有一行匹配 ,NULL: 不用访问表或索引直接得出结果;


 

 

三.创建索引列的选择判断

#对于表上的哪些列需要创建索引,哪些不适合创建索引:

1)、根据日常查询SQL的需求,where条件中包含哪些列,综合考虑;

2)、根据结果集以及列的基数判断;

#如下图,考虑table_name’EVENTS’,table_schema’test’所占的结果集大小,可以看出数据量很大;

#如下图,可看出此两列的选择率(基数)很差,不适合建索引;

. 索引规范与性能

#ts1,ts2的表行数

4.1 join连接方式代替子查询

#如下在等逻辑的修改下,嵌套子查询较慢(2.02s),这是当前mysql的一个不足;

4.2索引在外嵌套层(派生表)失效

#在逻辑的条件下:尽量将过滤条件置,以减少后续的结果集数量和使用上索引;

 

 

#从下图可看到时当将索引列放置于外层时(temp外)将不能使用上索引;等价修改放置里层后可使用上索引,执行时间从1.86s->0.00s

 

4.3 like如何利用索引

4.3.1 放置于”%”

 

4.3.2 通过idx_column_name索引后的主键的关系来匹配使用索引,相对于全表扫描执行的时间上从1.43->0.61s

 

#从执行计划可以看出改写后的SQL使用上索引idx_column_name

 

4.4字符类型隐性转换导致索引失效

#其中表ts4.col1列的类型为varchar

#从下图看出当数值100加上单引后可使用上索引(idx_col1),执行时间上也由0.11s->0.00s

4.5勿对索引列修饰(比如:对列计算,对列使用函数等)

4.5.1 对索引列的算术运算使用索引失效

#从下图可看出,=左边计算的表达式等价移到右边后可使用上索引

 

4.5.2 #索引列加上函数后导致索引失效

#其中列ts5.create_timedatetime类型

#经过等价的改写后可使用上索引idx_create_time

4.6去除不必要的order bygroup by

#如下图对于统计总数的查询没有必要在派生表temp内使用order by;额外的排序使用SQL执行时间从1.43s->1.70s

#从下图中看出对于group by 的结果默认会进行排序,如果结果无排序要求可考虑加入order by null来取消排序;

4.7去除不必要的外嵌套层

#如下图:对于等逻辑的写法尽量不要加入嵌套层,执行的时间从0.03s->52.95s

#从下图执行计划看出:没有嵌套层的语句优化器选择采用索引的方式,而有嵌套层的则采用全表扫描;

4.8减少不必要的自连接

 

#如下图:在使用自连接的时候,对于等逻辑的改写可考虑采用mysqlgroup by用法来消除不必要的自连接;执行时间上由8.569s->3.299s

 

 

 

4.9利用索引避免排序(order by )

#如上图:

1: where条件的索引列与order by为两个独立的索引引起filesort;

2: where条件的索引顺序读取已排好序的数据;

3: 虽然table_name上建有索引,但优化器认为全表扫描更快而产生filesort(type=ALL)

4:优化器认为直接从索引列上读取已排序好的数据更快;

 

#新增组合索引idx_name_schema

5:对于组合索引idx_name_schema,where条件与order by 的索引列都是已排好序的;

6:where条件与order by的索引列数据未排好序,主要由table_schema”>”引起;

7条:虽然order by后的索引列变为”desc”,where条件=配合一起取出的数据是有序的,只是逆排序,避免了filesort;

 

 

8:table_name上有独立的索引,且该索引会自动加上主键列值,因而避免filesort;

9:对于主键列的访问,结果仅为1条,因而不存在排序;

10:由于order by 的两索引列不同的排序方式引起了数据的无序而产生的filesort;

4.10 where条件中or如何使用索引

#对于含有orwhere条件列都应为索引列,否则将出现全表扫描;

#增加table_name的索引列后,与or相关的索引列都使用上了索引(index_merge);

 

4.11使用前缀索引与覆盖索引

 

4.11.1前缀索引: 对于较长列blob,longtext,varchar(n),可以截取前x位的字符来减少索引的大小(具体x的大小可多次通过统计总数来确定一个合适的值)

 

#如下图原来table_name列的分组数量和总分组数;截取前10个字符后此列值的分组数量(具体可抽样检查)和总分组数的变化(100 rows->87rows

 

 

4.11.2覆盖索引: 避免了回表,由扫描表转化为扫描索引而使性能提高

1条:优化器自动选择一索引列进行全索引扫描(索引比表小);

2条:索引idx_name_schema上已包含所有的table_name值,优化器选择全索引扫描;

3: 索引列table_schema上含有主键列上的值因而避免了回表;

4条:table_namewhere条件的索引列table_schema没有关联,需要回表取值;

 

4.12使用索引最左侧特性

对于上图:

1:刚好与组合索引idx_name_schema匹配;

2:table_name为非最左侧索引而产生了全表扫描;

3:最左侧列匹配%后放在后面可以使用上索引与第一句类似;

4:最左侧索引由于两个%失效而产生了全表扫描;

 

对于上图(含有3列的组合索引):

1条与第2条:同为存在最左侧索引列table_schema,因而可使用上索引;

3条:由于table_name为非最左侧索引导致索引失效;

.注意事项

    脚本提交时,需用 utf-8 编码保存,脚本文件名不要有中文。





posted @ 2017-01-17 14:19  糖饼好吃  阅读(325)  评论(0编辑  收藏  举报