目录1、开启Mysql慢查询1.1、查看慢查询相关配置1.2、查询慢查询sql耗时临界点1.3、开启mysql慢查询2、explain查看SQL执行计划2.1、Select_type2.2、Type2.3、Po
show variables like 'slow_query_log%'
slow_query_log 表示慢查询开启的状态
slow_query_log_file 表示慢查询日志存放的位置
show variables like 'long_query_time'
long_query_time 表示查询超过多少秒才记录到慢查询日志。
方式一:修改配置文件开启慢查询
在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秒,则记录慢查询日志
explain + SQL,查看SQL的执行计划。重点关注type、rows、extra、key指标。
查询类型:
存储引擎查询数据时采用的方式:
性能:NULL > const > eq_ref > ref > range > index > ALL
表示查询时可能使用到的索引。
查询时真正使用到的索引。
表示查询使用了索引的字节数量。可以判断是否全部使用了组合索引。
字符串长度跟字符集有关: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,则没有此项
SQL查询扫描的行数,行数越小越好。MySQL查询优化器会根据统计信息,估算SQL要查询到结果需要扫描多少行记录。
额外信息。
观测SQL
真正的执行线程状态及消耗的时间。
show variables like '%profil%'
执行如下SQL:
set profiling=ON
set profiling_history_size=30
查询最近SQL的执行耗时。
-- 查询最近profiling_history_size条SQL
show profiles;
查询一条SQL从开始到结束整个生命周期各个阶段的执行耗时。
-- 根据query_id查询指定SQL执行耗时
show profile for query id
profile只能查询SQL执行耗时,无法看到SQL具体的执行信息。
Optimizer Trace:可以跟踪执行语句的解析优化执行的全过程。
打开开关
set optimizer_trace="enabled=on"
执行需要分析的SQL执行跟踪
select * from infORMation_schema.optimizer_trace
以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;
把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'
不满足最左匹配原则,索引不生效。
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;
如果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)
执行计划如下,Extra中包含了Using filesort(文件排序)。
因为数据是无序的,所以就需要排序。如果数据本身是有序的,那就不会再用到文件排序啦。而索引数据本身是有序的,我们通过建立索引来优化order by
语句。
我们还可以通过调整max_length_for_sort_data、sort_buffer_size
等参数优化;
有时可能因为数据量问题,导致MySQL优化器放弃走索引。另外,用explain分析SQL的时候,需要注意type=range时,可能会因为数据量问题,导致索引无效。
如果优化器觉得即使走了索引,还是需要扫描很多很多行的哈,它觉得不划算,不如直接不走索引。
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字段均设置索引
delete from user where name in (select name from old_user)
这是因为,实际执行的时候,MySQL对select in子查询做了优化,把子查询改成join的方式,所以可以走索引。但是对于delete in子查询,MySQL却没有对它做这个优化。
到此这篇关于MySQL慢sql优化思路详细讲解的文章就介绍到这了,更多相关MySQL慢sql优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
--结束END--
本文标题: MySQL慢sql优化思路详细讲解
本文链接: https://lsjlt.com/news/176780.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-23
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0