MySQL 慢查询优化 10 个策略索引优化

编程入门 行业动态 更新时间:2024-10-11 01:14:56

MySQL 慢查询优化 10 个策略<a href=https://www.elefans.com/category/jswz/34/1771159.html style=索引优化"/>

MySQL 慢查询优化 10 个策略索引优化

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 
  • 原创 | Java 2021 超神之路,很肝~

  • 中文详细注释的开源项目

  • RPC 框架 Dubbo 源码解析

  • 网络应用框架 Netty 源码解析

  • 消息中间件 RocketMQ 源码解析

  • 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

  • 作业调度中间件 Elastic-Job 源码解析

  • 分布式事务中间件 TCC-Transaction 源码解析

  • Eureka 和 Hystrix 源码解析

  • Java 并发源码

来源:wwwblogs/gavincoder/

p/14056731.html

  • 1 慢查询优化方式

  • 2 数据源

  • 3 分析工具

  • 4 索引策略

  • 5 策略1:尽量考虑覆盖索引

  • 6 策略2:遵循最左前缀匹配

  • 7 策略3:范围查询字段放最后

  • 8 策略4:不对索引字段进行逻辑操作

  • 9 策略5:尽量全值匹配

  • 10 策略6:Like查询,左侧尽量不要加%

  • 11 策略7:注意NULL/NOT NULL可能对索引有影响

  • 12 策略8:尽量减少使用不等于

  • 13 策略9:字符类型务必加上引号

  • 14 策略10:OR关键字前后尽量都为索引列


1 慢查询优化方式

  • 服务器硬件升级优化

  • Mysql服务器软件优化

  • 数据库表结构优化

  • SQL语句及索引优化

本文重点关注于SQL语句及索引优化,关于其他优化方式以及索引原理等,请关注本人《MySQL慢查询优化》系列博文。优化我个人遵循的原则:积小胜为大胜,以空间换时间。-《论持久战》

推荐下自己做的 Spring Boot 的实战项目:

2 数据源

工欲善其事必先利其器,为了测试与验证的方便,数据库可以直接采用MySQL官方提供的测试数据库employees,该数据库关系复杂度适中以及数据量较大,适合做SQL语句及索引优化 分析,引用官方instruction:

The database contains about 300,000 employee records with 2.8 million salary entries. 
The export data is 167 MB, which is not huge, but heavy enough to be non-trivial for testing.
  • 数据库获取方式

  • 数据库E-R关系图

推荐下自己做的 Spring Cloud 的实战项目:

3 分析工具

采用explain指令直接模拟Mysql优化器执行SQL语句,查看SQL语句的执行计划。

示例

explain命令执行结果包括若干参数:id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra;重点关注type、possible_keys、key、key_len、extra 这五个参数。

  • possible_keys :此次查询中可能会被选用的索引,注意这些索引不一定被查询使用到。

  • key :此次查询中真正使用到的索引 。当为复合索引 时,不确定是否被充分使用。

  • type :访问类型,表示MySQL 在表中查找所需行的方式。常用的类型有:ALL, index, range, ref, eq_ref, const, system, NULL(性能从左到右逐步提升),其中:

ALLFull Table Scan, MySQL将遍历全表以找到匹配的行;
indexFull Index Scan,index与ALL区别为index类型只遍历索引树;
range只检索给定范围的行,使用一个索引 来选择行;
ref表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值;
eq_ref类似ref,区别就在使用的索引 是唯一索引 ,对于每个索引 键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件;
constsystem当MySQL对查询某部分进行优化 ,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL 就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system;
NULLMySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
  • *key_len:*表示索引中使用的字节数,用来计算索引是否被充分使用,不损失精确性的情况下,长度越短越好 ;

key_len=字符长度*字节数+类型+是否允许为空
索引是否充分使用:复合索引每个列都需要计算,所有索引列都生效了才是充分利用。
计算规则:。字节数相关:长度、字符编码、类型(int+0,char+0,varchar+2)、是否允许为空(空+1,非空+0);。int类型字节数为4;。char和varchar的长度是指字符数,一个字符在编码gbk为2个字节、utf-8为3个字节,需要:字符数*字节。
示例:name varchar(50)表示是varchar类型,长度为50,允许为空,假设是utf8编码key_len=50*3+2+1=153emp_no int(255)表示int类型,字节数为4,允许为空,跟长度和编码无关key_len=4+0=4
  • extra

Using where说明: SQL使用了where条件过滤数据;
**** Using index说明:**** 表示已经使用了覆盖索引。SQL所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录。(聚簇型索引,innodb的主键索引)

4 索引策略

索引策略是指创建使用索引所要遵循的规则,换句话说,违背了这些规则会导致索引失效或者查询效率降低。

策略1:尽量考虑覆盖索引
策略2:遵循最左前缀匹配
策略3:范围查询字段放最后
策略4:不对索引字段进行逻辑操作
策略5:尽量全值匹配
策略6:Like查询,左侧尽量不要加%
策略7:注意null/not null 可能对索引有影响
策略8:尽量减少使用不等于
策略9:字符类型务必加上引号
策略10:OR关键字左右尽量都为索引列

测试数据表:

show index from employees;

5 策略1:尽量考虑覆盖索引

覆盖索引:SQL只需要通过遍历索引树就可以返回所需要查询的数据,而不必通过辅助索引查到主键值之后再去查询数据(回表操作)。回表操作的详细介绍可以参考本人《MySQL 慢查询优化 》系列博文之索引。

例子

EXPLAIN SELECT emp_no,birth_date,gender FROM employees WHERE  gender  ='M' ;

*Using index: * 表示已经使用了覆盖索引。

6 策略2:遵循最左前缀匹配

联合索引命中必须遵循“最左前缀法则”。即SQL查询Where条件字段必须从索引的最左前列开始匹配,不能跳过索引中的列。联合索引又称复合索引,类似于书籍的目录,多级的目录结构中子目录依赖于父级目录存在,也是遵循“最左前缀法则”。

联合索引结构分析,示例:

联合索引INDEX idx_empno_birthdate_gender(emp_no,birth_date,gender)
等价建立的索引实际上联合索引idx_empno_birthdate_gender等价建立了三个索引:index_1(emp_no)index_2(emp_no,birth_date)index_3(emp_no,birth_date,gender)
联合索引命中的where条件字段列表index_1命中:emp_no 或 emp_no,genderindex_2命中:emp_no,birth_dateindex_3命中:emp_no,birth_date,gender以上where子句查询条件联合索引idx_empno_birthdate_gender都会命中,只是使用的程度不一样(走的子索引不一样),因此,联合索引有“是否充分使用”衡量指标(key_len),当然使用最充分的条件是:所有字段都命中,即使用了index_3。
EXPLAIN SELECT * FROM employees WHERE  birth_date  = '1963-06-01' AND gender ='F';

注:表存在多个索引时,即使Where条件满足最左前缀规则,SQL执行时也未必一定会命中联合索引,根据性能可能直接使用了主键索引。

例子:

EXPLAIN SELECT * FROM employees WHERE emp_no  = 10010 AND  birth_date  = '1963-06-01'  AND gender ='F';

PRIMARY KEY (emp_no)

7 策略3:范围查询字段放最后

联合索引定义时,尽量将范围查询字段放在最后(放在最后联合索引使用最充分,放在中间联合索引使用不充分)。使用联合索引时范围列(当前范围列索引生效)后面的索引列无法生效,同时索引最多用于一个范围列,如果查询条件中有多个范围列,也只能用到一个范围列索引。

例子1:

EXPLAIN SELECT emp_no,birth_date,gender FROM employees WHERE  emp_no  > 10015  AND gender ='F';

只是使用到了主键索引PRIMARY(emp_no),联合索引未生效idx_empno_birthdate_gender(emp_no,birth_date,gender);

删除idx_empno_birthdate_gender索引,新建联合索引idx_gender_birthdate_empno(gender,birth_date,emp_no);

例子2:

EXPLAIN SELECT emp_no,birth_date,gender FROM employees WHERE  emp_no  > 10015 AND birth_date = 1953-09-02 AND gender ='F';

8 策略4:不对索引字段进行逻辑操作

索引 字段上进行计算、函数、类型转换(自动\手动)都会导致索引失效。

例子:

CREATE INDEX idx_first_name ON employees(first_name);

EXPLAIN SELECT * FROM employees WHERE LEFT(first_name,3) ='Geo';

9 策略5:尽量全值匹配

全值匹配也就是精确匹配不使用like查询(模糊匹配),使用like会使查询效率降低。

10 策略6:Like查询,左侧尽量不要加%

like 以%开头,当前列索引无效(当为联合索引时,当前列和后续列索引不生效,可能导致索引使用不充分);当like前缀没有%,后缀有%时,索引有效。

例子1:

EXPLAIN SELECT * FROM employees WHERE first_name like'Geo%';

例子2:

EXPLAIN SELECT * FROM employees WHERE first_name like'%Geo%';

11 策略7:注意NULL/NOT NULL可能对索引有影响

在索引列上使用 IS NULL 或 IS NOT NULL条件,可能对索引有所影响。

  • 字段定义默认为NULL时,NULL索引 生效,NOT NULL索引 不生效;

  • 字段定义明确为NOT NULL ,不允许为空时,NULL/NOT NULL索引列,索引均失效;

列字段尽量设置为NOT NULL,MySQL难以对使用NULL的列进行查询优化,允许Null会使索引 值以及索引 统计更加复杂。允许NULL值的列需要更多的存储空间,还需要MySQL内部进行特殊处理。

例子1:

EXPLAIN SELECT * FROM employees WHERE first_name IS  NULL;

例子2:

EXPLAIN SELECT * FROM employees WHERE first_name IS NOT NULL;

例子3:

EXPLAIN SELECT * FROM employees WHERE first_name IS NOT NULL;

12 策略8:尽量减少使用不等于

不等于操作符是不会使用索引的。不等于操作符包括:not,<>,!=。

优化 方法:数值型 key<>0 改为 key>0 or key<0。

例子:

EXPLAIN SELECT * FROM employees WHERE first_name != 'Georgi';

13 策略9:字符类型务必加上引号

若varchar类型字段值不加单引号,可能会发生数据类型隐式转化,自动转换为int型,使索引 无效。

例子:

EXPLAIN SELECT * FROM employees WHERE first_name = 1;

14 策略10:OR关键字前后尽量都为索引列

当OR左右查询字段只有一个是索引 ,会使该索引 失效,只有当OR左右查询字段均为索引 列时,这些索引 才会生效。OR改UNION效率高。

例子1:

EXPLAIN SELECT * FROM employees WHERE first_name = 'Georgi' OR emp_no = 20001;

例子2:

EXPLAIN SELECT * FROM employees WHERE first_name = 'Georgi' OR last_name = 'Facello';

后续:

  • 索引的创建需要参照具体的SQL实现。

  • 当全表扫描速度比索引 速度快时,MySQL 会使用全表扫描,此时索引 失效。

  • 表中存在多个索引时,即使where条件满足某个索引策略,MySQL查询优化器也不一定会使用该索引,可能使用其他索引,取决于性能。另外,当某个索引没有命中也不一定会走全表扫描,可能走其他索引。

  • 理论上索引 对顺序是敏感的,也就是说where子句的字段列表需要讲究顺序,但是由于MySQL 的查询优化 器会自动调整where子句的条件顺序以匹配适合的索引 ,因此,允许我们不去刻意关注where子句的条件顺序。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)

更多推荐

MySQL 慢查询优化 10 个策略索引优化

本文发布于:2024-03-08 23:52:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1722919.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:索引   策略   MySQL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!