MySQL慢sql优化思路详细讲解

目录
  • 1、开启Mysql慢查询
    • 1.1、查看慢查询相关配置
    • 1.2、查询慢查询sql耗时临界点
    • 1.3、开启Mysql慢查询
  • 2、explain查看SQL执行计划
    • 2.1、Select_type
    • 2.2、Type
    • 2.3、Possible_keys
    • 2.4、Key
    • 2.5、Key_len
    • 2.6、Rows
    • 2.7、Extra
  • 3、profile 分析执行耗时
    • 3.1、查询profile开启状态
    • 3.2、开启profiling
    • 3.3、查看最近运行的SQL
      • 3.3.1、show profiles
      • 3.3.2、show profile for query id
  • 4、Optimizer Trace分析详情
    • 4.1、分析流程
    • 4.2、结果分析
  • 5、慢查询经典案例总结
    • 5.1、隐式类型转换
    • 5.2、最左匹配
    • 5.3、limit深分页问题
    • 5.4、in元素过多
    • 5.5、order走文件排序导致的慢查询
    • 5.6、索引字段使用is null 或 is not null可能导致索引失效
    • 5.7、索引字段上使用(!= 或者 < >, not in)可能导致索引失效
    • 5.8、左右连接,关联的字段编码格式不一致
    • 5.9、delete + in子查询不走索引
  • 总结

1、开启Mysql慢查询

1.1、查看慢查询相关配置

show variables like 'slow_query_log%'

slow_query_log 表示慢查询开启的状态

slow_query_log_file 表示慢查询日志存放的位置

1.2、查询慢查询sql耗时临界点

show variables like 'long_query_time'

long_query_time  表示查询超过多少秒才记录到慢查询日志。

1.3、开启Mysql慢查询

方式一:修改配置文件开启慢查询

在my.ini增加如下配置

# 定义sql耗时多少秒就算是慢查询,记录慢查询日志
long_query_time=2

# 开启慢查询
slow_query_log=on

# 定义慢查询日志文件名
slow_query_log_file=/usr/local/mysql/mysql-slow-query.log

方式二:通过命令开启慢查询

set global slow_query_log=ON    # 开启慢查询日志
set global long_query_time=2    # SQL查询时间大于2秒,则记录慢查询日志

2、explain查看SQL执行计划

explain + SQL,查看SQL的执行计划。重点关注type、rows、extra、key指标。

2.1、Select_type

查询类型:

  • SIMPLE : 表示查询语句不包含子查询或union
  • PRIMARY:表示此查询是最外层的查询
  • UNION:表示此查询是UNION的第二个或后续的查询
  • DEPENDENT UNION:UNION中的第二个或后续的查询语句,使用了外面查询结果
  • UNION RESULT:UNION的结果
  • SUBQUERY:SELECT子查询语句
  • DEPENDENT SUBQUERY:SELECT子查询语句依赖外层查询的结果

2.2、Type

存储引擎查询数据时采用的方式:

性能:NULL > const > eq_ref > ref > range > index > ALL

  • ALL:表示全表扫描,性能最差。
  • index:表示基于索引的全表扫描,先扫描索引再扫描全表数据。
  • range:表示使用索引范围查询。使用>、>=、<、<=、in等等。
  • ref:表示使用非唯一索引进行单值查询。
  • eq_ref:一般情况下出现在多表join查询,表示前面表的每一个记录,都只能匹配后面表的一行结果。
  • const:表示使用主键或唯一索引做等值查询,常量查询。
  • NULL:表示不用访问表,速度最快。

2.3、Possible_keys

表示查询时可能使用到的索引。

2.4、Key

查询时真正使用到的索引。

2.5、Key_len

表示查询使用了索引的字节数量。可以判断是否全部使用了组合索引。

  • 字符串类型

字符串长度跟字符集有关:latin1=1、gbk=2、utf8=3、utf8mb4=4

char(n):n*字符集长度

varchar(n):n * 字符集长度 + 2字节

  • 数值类型

TINYINT:1个字节        SMALLINT:2个字节        MEDIUMINT:3个字节

INT、FLOAT:4个字节        BIGINT、DOUBLE:8个字节

  • 时间类型

DATE:3个字节        TIMESTAMP:4个字节        DATETIME:8个字节

  • 字段属性

NULL属性占用1个字节,如果一个字段设置了NOT NULL,则没有此项

2.6、Rows

SQL查询扫描的行数,行数越小越好。MySQL查询优化器会根据统计信息,估算SQL要查询到结果需要扫描多少行记录。

2.7、Extra

额外信息。

  • Using where:表示查询需要通过索引回表查询数据。
  • Using index:表示查询需要通过索引,索引就可以满足所需数据。
  • Using filesort:表示查询出来的结果需要额外排序,数据量小在内存,大的话在磁盘,因此有Using filesort建议优化。
  • Using temprorary:查询使用到了临时表,一般出现于去重、分组等操作。
  • Using index condition:MySQL5.6之后新增的索引下推。在存储引擎层进行数据过滤,而不是在服务层过滤,利用索引现有的数据减少回表的数据。

3、profile 分析执行耗时

观测SQL真正的执行线程状态及消耗的时间。

3.1、查询profile开启状态

show variables like '%profil%'

  • have_profiling:确定是否支持 profile
  • profiling:是否开启profiling
  • profiling_history_size:定义MySQL服务器最近接收到的SQL条数。

3.2、开启profiling

执行如下SQL:

set profiling=ON
set profiling_history_size=30

3.3、查看最近运行的SQL

3.3.1、show profiles

查询最近SQL的执行耗时。

-- 查询最近profiling_history_size条SQL
show profiles;

3.3.2、show profile for query id

查询一条SQL从开始到结束整个生命周期各个阶段的执行耗时。

-- 根据query_id查询指定SQL执行耗时
show profile for query id

4、Optimizer Trace分析详情

profile只能查询SQL执行耗时,无法看到SQL具体的执行信息。

Optimizer Trace:可以跟踪执行语句的解析优化执行的全过程。

4.1、分析流程

打开开关

set optimizer_trace="enabled=on"

执行需要分析的SQL执行跟踪

select * from information_schema.optimizer_trace

4.2、结果分析

  • join_preparation:准备阶段
  • join_optimization:分析阶段
  • join_execution:执行阶段

5、慢查询经典案例总结

以user表为例举例说明:

CREATE TABLE user (
  id int(11) NOT NULL AUTO_INCREMENT,
  user_id varchar(32) NOT NULL,
  age  varchar(16) NOT NULL,
  name varchar(255) NOT NULL,
  PRIMARY KEY (id),
  KEY idx_userid (userId) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

5.1、隐式类型转换

把userId设为索引,如果在查询条件中把一个数字传给user_id,则索引失效。

# user_id索引失效,传的是数字123,索引user_id类型为字符串,两者类型不匹配
# MySql会将user_id转换为字符串再进行比较。
select *from user where user_id = 123

# 走userId索引
select *from user where user_id = '123'

5.2、最左匹配

不满足最左匹配原则,索引不生效。

5.3、limit深分页问题

MySql会查询满足条件的100010行,然后丢弃前100000行,返回最后10行。

select *from user where age > 20 limit 100000,10

解决方案:减少回表

标签记录法:

标记一下上次查询到哪一条了,下次再来查的时候,从该条开始往下扫描。

# 标签记录法:局限是要求id连续
select *from user where id > 100000 limit 10

延迟关联法:

把条件转移到主键索引树,减少回表。

# 为age字段创建索引,通过age索引查询到满足条件的id,再与原表通过id内连接
select user1.id, user1.age, user1.name
FROM user user1
INNER JOIN (
    SELECT u.id FROM user u WHERE u.age > 20 limit 100000, 10
) AS user2 on user1.id= user2.id;

5.4、in元素过多

如果in中的元素过多,建议分组查询,一次200个。

select * from user where user_id in (1,2,3...200)
union all
select * from user where user_id in (201,202,203...400)

5.5、order走文件排序导致的慢查询

执行计划如下,Extra中包含了Using filesort(文件排序)。

因为数据是无序的,所以就需要排序。如果数据本身是有序的,那就不会再用到文件排序啦。而索引数据本身是有序的,我们通过建立索引来优化order by语句。

我们还可以通过调整max_length_for_sort_data、sort_buffer_size等参数优化;

5.6、索引字段使用is null 或 is not null可能导致索引失效

有时可能因为数据量问题,导致MySQL优化器放弃走索引。另外,用explain分析SQL的时候,需要注意type=range时,可能会因为数据量问题,导致索引无效。

5.7、索引字段上使用(!= 或者 < >, not in)可能导致索引失效

如果优化器觉得即使走了索引,还是需要扫描很多很多行的哈,它觉得不划算,不如直接不走索引。

5.8、左右连接,关联的字段编码格式不一致

select u.name, j.name, j.job
from user u
left join user_job j on u.name = j.name

将user表的name字段以及user_job表的name字段均设置索引

  • 假设user表的name字段编码为utf8,user_job表的name字段编码为utf8mb4,则上述sql查询不走索引。
  • 假设user表的name字段编码和user_job表的name字段编码均为utf8,则上述sql查询走索引。

5.9、delete + in子查询不走索引

delete from user where name in (select name from old_user)
  • delete + in子查询不走索引
  • select + in子查询走索引

这是因为,实际执行的时候,MySQL对select in子查询做了优化,把子查询改成join的方式,所以可以走索引。但是对于delete in子查询,MySQL却没有对它做这个优化。

总结

到此这篇关于MySQL慢sql优化思路详细讲解的文章就介绍到这了,更多相关MySQL慢sql优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mysql性能优化工具--tuner-primer使用介绍

    下载并改变执行权限: wget http://www.day32.com/MySQL/tuning-primer.sh chmod +x tuning-primer.sh ./tuning-primer.sh 结果报告: 会用几种颜色标记: 蓝色:总指标 绿色:表示此参数还可以 红色:表示此参数有严重问题 深红色:表示有问题参数 黄色:一些信息提示 而且还有警告: Note! This script will still suggest raising the join_buffer_size

  • Mysql表的约束超详细讲解

    目录 约束的概念 空属性 默认值 列描述 zerofill 主键 自增长 唯一键 外键 约束的概念 约束:通过限制用户操作的方式,来达到维护数据本身安全,完整性的一套方案. 为什么要有约束? Mysql是一套整体的数据存储解决方案,除了解决数据存储功能,还要保证数据的安全,减少用户的误操作. 表的约束有很多,主要介绍:null/not null,default, comment, zerofill,primary key, auto_increment,unique key . 空属性 数据库默

  • mysql数据库sql优化原则(经验总结)

    一.前提 这里的原则只是针对MySQL数据库,其他的数据库某些是殊途同归,某些还是存在差异.我总结的也是MySQL普遍的规则,对于某些特殊情况得特殊对待.在构造SQL语句的时候要养成良好的习惯. 二.原则总结 原则1.仅列出需要查询的字段,这对速度不会明显的影响,主要是考虑节省应用程序服务器的内存. 原来语句: select * from admin 优化为: select admin_id,admin_name,admin_password from admin 原则2.尽量避免在列上做运算,

  • 详细聊聊MySQL中慢SQL优化的方向

    目录 前言 SQL语句优化 记录慢查询SQL 如何修改配置 查看慢查询日志 查看SQL执行计划 如何使用 SQL编写优化 为何要对慢SQL进行治理 总结 前言 影响一个系统的运行速度的原因有很多,是多方面的,甚至可能是偶然性的,或前端,或后端,或数据库,或中间件,或服务器,或网络等等等等,真正的去定位一个问题需要对系统有一定的认知,可以根据自身的判断去缩小问题范围. 今天不说其他的优化,单独把数据库的优化拿出来说几个优化方向. 跟系统的优化方向一样,数据库的优化,同样也是多方面的,其中涵盖着SQ

  • 分区表场景下的 SQL 优化

    导读 有个表做了分区,每天一个分区. 该表上有个查询,经常只查询表中某一天数据,但每次都几乎要扫描整个分区的所有数据,有什么办法进行优化吗? 待优化场景 有一个大表,每天产生的数据量约100万,所以就采用表分区方案,每天一个分区. 下面是该表的DDL: CREATE TABLE `t1` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `date` date NOT NULL, `kid` int(11) DEFAULT '0', `uid` int(11)

  • MySql中sql语句执行过程详细讲解

    目录 前言: sql语句的执行过程: 查询缓存: 分析器: 优化器: 执行器: 总结 前言: 很多人都在使用mysql数据库,但是很少有人能够说出来整个sql语句的执行过程是怎样的,如果不了解执行过程的话,就很难进行sql语句的优化处理,也很难设计出来优良的数据库表结构.这篇文章主要是讲解一下sql语句的执行过程. sql语句的执行过程: 客户端.连接器.分析器.优化器.执行器.存储引擎几个阶段. 连接器的作用:管理链接.权限验证的处理. 分析器的作用:词法分析.语法分析. 优化器的作用:执行计

  • MySQL定位并优化慢查询sql的详细实例

    目录 1.如何定位并优化慢查询sql a.根据慢日志定位慢查询sql b.使用explain等工具分析sql c.修改sql或者尽量让sql走索引 2.联合索引的最左匹配原则的成因 简单说下什么是最左匹配原则 最左匹配原则的原理 3.索引是建立得越多越好吗 总结 1.如何定位并优化慢查询sql a.根据慢日志定位慢查询sql SHOW VARIABLES LIKE '%query%' 查询慢日志相关信息 slow_query_log 默认是off关闭的,使用时,需要改为on 打开 slow_qu

  • Mysql超详细讲解死锁问题的理解

    目录 1.什么是死锁? 2.Mysql出现死锁的必要条件 资源独占条件 请求和保持条件 不剥夺条件 相互获取锁条件 3. Mysql经典死锁案例 3.1 建表语句 3.2 初始化相关数据 3.3 正常转账过程 3.4 死锁转账过程 3.5 死锁导致的问题 4.如何解决死锁问题? 4.1 打破请求和保持条件 4.2 打破相互获取锁条件(推荐) 5.总结 1.什么是死锁? 死锁指的是在两个或两个以上不同的进程或线程中,由于存在共同资源的竞争或进程(或线程)间的通讯而导致各个线程间相互挂起等待,如果没

  • MySQL/Postgrsql 详细讲解如何用ODBC接口访问MySQL指南

    详细讲解如何用ODBC接口访问MySQL指南 MySQL的ODBC接口实现是通过安装MyODBC驱动,这个驱动程序是跨平台的.如果在Linux等Unix体系操作系统下使用,需要先安装Iodbc这些第三方ODBC标准支援平台. 简单的ASP示例代码:   复制代码 代码如下: <%   dim sql,mysql   set sql = server.createobject("adodb.connection")   mysql="driver={mysql odbc 

  • SQL之各种join小结详细讲解

    SQL Left Join, Right Join, Inner Join, and Natural Join 各种Join小结 在SQL语言中,存在着各种Join,有Left Join, Right Join, Inner Join, and Natural Join等,对于初学者来说肯定一头雾水,都是神马跟神马啊,它们之间到底有着怎样的区别和联系呢,我们先用一张图片来说明: 上面这张图很好的阐释了Left Join, Right Join, Inner Join,和Full Outer Jo

  • MyBatis 详细讲解动态 SQL的使用

    目录 MyBatis 框架动态 SQL 环境准备 动态 SQL 之 if 动态 SQL 之 where 动态 SQL 之 foreach 动态 SQL 之代码片段 MyBatis 框架动态 SQL 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句.这里的条件判断使用的表达式为 OGNL 表达式.常用的动态 SQL 标签有<if>.<where>.<choose/>.<foreach>等. MyBatis 的动态 S

随机推荐