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

本文详细介绍了MySQL中InnoDB存储引擎的索引原理及如何通过合理创建和使用索引来提升查询性能,包括索引的优点与缺点、创建索引的原则、如何避免索引失效以及各种场景下的索引优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,

增加了插入的时间;

990382-20170117141826614-407659434.jpg

. innodb索引特点与原理&explain

2.1 innodb索引特点

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

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

990382-20170117141827536-1527303709.jpg

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

990382-20170117141828364-101538287.jpg

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查看执行计划

990382-20170117141829177-962212197.jpg主要讲述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’所占的结果集大小,可以看出数据量很大;

990382-20170117141830161-1516886157.jpg

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

990382-20170117141830974-1457825478.jpg

. 索引规范与性能

#ts1,ts2的表行数

990382-20170117141831724-202114205.jpg

4.1 join连接方式代替子查询

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

990382-20170117141832786-176243639.jpg

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

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

990382-20170117141833677-1225721446.jpg

 

990382-20170117141834802-480793088.jpg

 

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

990382-20170117141835333-48011467.jpg

 

4.3 like如何利用索引

4.3.1 放置于”%”

990382-20170117141835974-1214358132.jpg

 

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

990382-20170117141836646-1722730503.jpg

 

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

990382-20170117141837286-1142092474.jpg

 

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

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

990382-20170117141838271-802843.jpg

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

990382-20170117141839052-1136594825.jpg

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

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

990382-20170117141839661-1737026280.jpg

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

990382-20170117141840364-993054411.jpg

 

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

#其中列ts5.create_timedatetime类型

990382-20170117141841099-1033623061.jpg

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

990382-20170117141841817-1440984432.jpg

4.6去除不必要的order bygroup by

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

990382-20170117141842521-847504464.jpg

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

990382-20170117141843646-195338798.jpg

4.7去除不必要的外嵌套层

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

990382-20170117141844255-162840127.jpg

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

990382-20170117141845271-938631964.jpg

4.8减少不必要的自连接

 

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

990382-20170117141845942-1854366470.jpg

 

990382-20170117141846724-261063194.jpg

 

 

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

990382-20170117141847380-467456499.jpg

#如上图:

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

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

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

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

 

#新增组合索引idx_name_schema

990382-20170117141847927-203438487.jpg

990382-20170117141848536-999437595.jpg

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

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

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

 

 

990382-20170117141849224-2127567891.jpg

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

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

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

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

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

990382-20170117141849989-399492161.jpg

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

990382-20170117141850692-850673239.jpg

 

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

 

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

 

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

990382-20170117141851396-1162578959.jpg

 

990382-20170117141852036-69951465.jpg

 

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

990382-20170117141852771-927031432.jpg

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

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

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

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

 

4.12使用索引最左侧特性

990382-20170117141853536-373890776.jpg

对于上图:

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

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

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

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

 

990382-20170117141854239-1917671902.jpg

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

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

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

.注意事项

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





转载于:https://www.cnblogs.com/tangbinghaochi/p/6292914.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值