【MySQL】SQL调优-如何分析SQL性能 - 指南

news/2025/11/7 13:20:04/文章来源:https://www.cnblogs.com/yangykaifa/p/19199421

目录

压力测试工具

SQL语句性能分析

select_type

* type列

* Extra 列

* Using temporary

Using filesort

Using where

Using index

索引覆盖

回表查询


        MySQL的优化涉及多个级别的配置、调优和性能评估。根据职位(开发人员或DBA),可以在单个 SQL语句、整个应用程序、单个数据库服务器或多个联网数据库服务器的级别进行优化;

别影响性能的重要因素:表结构、查询语句和数据库配置。

        软件级别的因素会导致硬件级别的CPU和I/O操作。在优化数据库性能时,首先要学习软件级别的规则,但在真实的企业中,通常数据库遇到瓶颈 首先考虑换⼀个高性能的存储设置,比如把机械硬盘换成SSD,再考虑软件层面,最后考虑操作系 统层面的优化;

这里只讨论索引级别的优化;本文将介绍一些性能分析的方法;

压力测试工具

使用MySQL自带的压测工具(mysqlslap)模拟多个客户端同时查询,观察测试结果:

# 使用主键查询 查询100w次
mysqlslap -uroot -proot123 \--concurrency=100 \--iterations=100 \--create-schema="test" \--engine="innodb" \--number-of-queries=10000 \--query="SELECT id, sn, name, mail, age, gender, class_id FROM test.index_demo WHERE id = 1020000"
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
BenchmarkRunning for engine innodbAverage number of seconds to run all queries: 0.257 secondsMinimum number of seconds to run all queries: 0.169 secondsMaximum number of seconds to run all queries: 0.345 secondsNumber of clients running queries: 100Average number of queries per client: 100# 使⽤⾮索引列查询 查询300次
mysqlslap -uroot -proot123   --concurrency=30   --iterations=3   --create-schema="test"   --engine="innodb"   --number-of-queries=100   --query="SELECT id, sn, name, mail, age, gender, class_id FROM test.index_demo WHERE sn = '1020000';"
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
BenchmarkRunning for engine innodbAverage number of seconds to run all queries: 3.982 secondsMinimum number of seconds to run all queries: 3.956 secondsMaximum number of seconds to run all queries: 3.997 secondsNumber of clients running queries: 30Average number of queries per client: 3

命令参数解析:

基本连接选项

  • -uroot:使用 root 用户连接 MySQL

  • -proot123:使用密码 "root123"

性能测试核心参数

  • --concurrency=100:模拟 ​​100个并发客户端​​ 同时连接数据库。这个值越高,测试压力越大。

  • --iterations=100:整个测试将 ​​重复执行100次​​,用于获取更稳定的平均性能数据。

  • --create-schema="test":测试将在名为 "test" 的数据库中执行(如果数据库不存在会自动创建)

  • --engine="innodb":指定使用 ​​InnoDB 存储引擎​​ 进行测试(如果表已存在,会临时改为使用InnoDB)

  • --number-of-queries=10000:整个测试期间将 ​​总共执行10000次查询​​(所有客户端总查询数,比如:示例中100个客户端一轮总共需要执行1w次,执行100轮)

测试查询定义

  • --query="SELECT id, sn, name, mail, age, gender, class_id FROM test.index_demo WHERE id = 1020000"

    要测试的SQL查询语句:从test数据库的index_demo表中查询id=1020000的记录;

使用 show processlist 命令查看正在运行的线程:

SQL语句性能分析

在执行 SELECT , DELETE , INSERT , REPLACE ,和 UPDATE 之前都可以用执行计划分析SQL语句的执行情况,以便优化SQL语句。

注意:并不会真正的执行SQL,只是对SQL进行分析,最终返回一个分析结果

# 索引列
mysql> EXPLAIN select id, sn, name, mail, age, gender, class_id from index_demo where id = 1020000\G
*************************** 1. row ***************************id: 1                     # SELECT标识符,表示查询序列号,如果使用子查询或联表查询就会查到多个执行计划id也会递增;select_type: SIMPLE                # 查询类型,简单查询(无子查询/UNION)table: index_demo            # 查询的表名partitions: NULL                  # 查询涉及的分区(未分区则为NULL)type: const                 # 连接类型,const表示通过主键/唯一索引查找
possible_keys: PRIMARY               # 可能使用的索引(此处显示主键索引可用)key: PRIMARY               # 实际使用的索引(最终选择主键索引)key_len: 8                     # 使用的索引长度(字节)ref: const                 # 与索引比较的列/常量rows: 1                     # 预估需要检查的行数filtered: 100.00                # 按条件过滤后剩余行的百分比Extra: NULL                  # 附加执行信息
1 row in set, 1 warning (0.00 sec)
# 非索引列
mysql> EXPLAIN select id, sn, name, mail, age, gender, class_id from index_demo where sn = '1020000'\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: ALL
possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 993231filtered: 10.00Extra: Using where
1 row in set, 1 warning (0.00 sec)

在性能分析时主要关注以下字段:

# 使用非索引列
type: ALL             # 全表扫描
key: NULL             # 未用索引
rows: 100000          # 扫描10万行
Extra: Using where    # 存储引擎层未过滤
# 使用索引列
type: const           # 主键精准定位
key: PRIMARY          # 使用主键
rows: 1               # 扫描1行
Extra: NULL           # 无额外操作

分析上边两个查询语句,第一个查询:实际用到的索引是主键索引,索引长度为8字节,索引比较的列是常量,估算要检查的行数为1行,按条件筛选率是100%;

第二个查询:没有用到索引,估算要检查的行数为993231行,按条件筛选率仅为10%;

select_type

select_type 值说明
SIMPLE简单SELECT(不使用UNION或子查询)
PRIMARY外层查询
UNIONUNION中的第⼆个及之后的SELECT语句
UNION RESULTUNION的结果。
SUBQUERY子查询中
INSERTINSERT 语句
UPDATEUPDATE 语句
DELETEDELETE 语句

测试语句:

explain select * from student where id = (select id from student1 where name = '宋江')\G
explain select * from student union select * from student1\G

* type列

性能排序与说明​

EXPLAIN输出的type列描述了表是如何连接的,性能从最高往低依次降低;​

类型

名称

触发场景

性能

优化建议

​system​

系统表

查询系统表或只有1行的表

★★★★★

无需优化

​const​

常量

用主键/唯一索引精确匹配
WHERE id = 1

★★★★★

理想状态

​eq_ref​

等值引用

JOIN时用主键/唯一索引关联
A.id = B.id

★★★★☆

检查JOIN字段索引

​ref​

普通索引

用非唯一索引查找
WHERE age = 20

★★★☆☆

确保索引选择性高

​fulltext​

全文索引

使用全文索引搜索

★★★☆☆

优化MATCH条件

​ref_or_null​

含NULL的索引

索引查询包含NULL值
WHERE age = 20 OR age IS NULL

★★☆☆☆

避免字段允许NULL

​index_merge​

索引合并

合并多个索引的结果
WHERE a=1 OR b=2

★★☆☆☆

改用复合索引

​unique_subquery​

唯一子查询

子查询使用主键
WHERE id IN (SELECT...)

★★☆☆☆

改写成JOIN

​index_subquery​

索引子查询

子查询使用普通索引

★★☆☆☆

改写成JOIN

​range​

范围扫描

索引范围查询
WHERE id > 100

★☆☆☆☆

控制范围数据量

​index​

全索引扫描

遍历整个索引树
SELECT indexed_col FROM table

☆☆☆☆☆

避免SELECT无覆盖索引

​ALL​

全表扫描

无索引可用

⚠️最差

必须加索引

  • system:查询系统表或只有1行的表;
  • const:用主键/唯一索引精确匹配 (WHERE id = 1),结果最多有⼀个匹配的行,类型显示

    为 const ,这种类型查询性能极高,且只会返回一行数据;

  • eq_ref:应⽤于多表连接的场景,表关联条件是主键索引或唯一非空索引时使⽤等号 ( = ) 进行索引列的比较,每行只匹配⼀条记录
select * from student s, account a where s.id = a.id;
  • ref:使用了普通索引,返回的结果可能是多行组成的结果集(WHERE age = 20
  • fulltext:使用全文索引搜索
  • ref_or_null:索引查询包含NULL值(WHERE age = 20 OR age IS NULL
  • index_merge:在查询中使用了多个索引,OR 两边必须是单独索引,最终通过不同索引检索数据,然后对结果集进行合并,Key_len显示最长的索引长度。
select * from index_demo where name = 'user_1020021' or id = 1030300\G
-- name 和 id 都是单独的索引列
  • unique_subquery:子查询使用主键(WHERE id IN (SELECT...)
-- ⼦查询中返回的是外层表的主键索引或唯⼀索引
value IN (SELECT primary_key FROM single_table WHERE some_expr)
  • index_subquery:类似于unique_subquery,只不过子查询中返回的是普通索引列;
  • range:使用索引列进行范围查询,当使用<>、>、>=、<、<=、is NULL、<=>、BETWEEN、LIKE或IN()操作符,索引列与常量进行较时为range;
  • index:扫描整个索引树而不扫描整个表,比如只使用索引排序而不使用条件查询时:
select * from index_demo order by sn limit 10\G
  • ALL:最差的情况,表示MySQL必须对全表进行逐行扫描才可以以找到匹配行;

针对这些type类型,在全文索引(fulltext)性能之下的其实都可以根据业务进行调整优化,尽可能的使用索引;特别需要避免的就是全表扫描;

* Extra 列

Extra 列中如果出现 Using filesort 和 Using temporary ,将会对查询效率有比较严重的影响;

Using filesort:使用文件排序,该场景必须要进行优化;

Using temporary:使用临时表排序,临时表所占用的是内存中的一片区域,当内存占满之后,就需要申请临时文件此时发生磁盘IO;

* Using temporary

当使用非索引列进行分组时,会用临时表进行排序,优化时可以考虑为分组的列加索引;

mysql> explain select avg(age) from index_demo group by gender\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: ALL
possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 993231filtered: 100.00Extra: Using temporary
1 row in set, 1 warning (0.01 sec)
-- 使用索引列,减少内存的使用
mysql> explain select avg(age) from index_demo group by class_id\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: index
possible_keys: class_idkey: class_idkey_len: 8ref: NULLrows: 993231filtered: 100.00Extra: NULL
1 row in set, 1 warning (0.00 sec)

Using filesort

当使用非索引列进行排序时会用到文件内排序,优化时可以考虑为排序的列加索引;

mysql> explain select * from index_demo where id < 1020000 order by age limit 10\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: range
possible_keys: PRIMARYkey: PRIMARYkey_len: 8ref: NULLrows: 496615filtered: 100.00Extra: Using where; Using filesort -- 使用了文件内排序,进行了磁盘IO
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from index_demo where id < 1020000 order by class_id limit 10\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: index
possible_keys: PRIMARYkey: class_idkey_len: 8ref: NULLrows: 20filtered: 50.00Extra: Using where
1 row in set, 1 warning (0.00 sec)

Using where

使用了非索引列进行检索数据,且进行了全表扫描;

-- gender 非索引列
explain select * from index_demo where gender = 1\G

当使用索引列进行检索数据时,行范围查找,此时扫描的是索引树,也显示的是 Using where;

mysql> explain select * from index_demo where id < 102000\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: range
possible_keys: PRIMARYkey: PRIMARYkey_len: 8ref: NULLrows: 3674filtered: 100.00Extra: Using where -- 扫描索引树,使用了索引
1 row in set, 1 warning (0.00 sec)

Using index

发生索引覆盖时显示using index,表示这是⼀个高效查询;

主键索引:主键索引的B+树叶子节点中,保存的是完整的数据行;

普通索引:普通索引生成的索引树的叶子节点中,保存的是索引列的值和主键值;

索引覆盖

当查询可以​​完全通过索引获取所需数据​​时,性能会有显著提升;查询的​​所有字段都包含在某个索引中​​,引擎无需回表查数据文件。

比如:

-- 创建一个包含 mail, age, class_id 的复合索引
create index idx_mail_age_classId on index_demo(mail, age, class_id);
-- 查询 mail,age,class_id 这三个列,判定条件也是索引中最左前缀列
mysql> explain select mail,age,class_id from index_demo where mail = '1020000@qq.com'\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: ref
possible_keys: idx_mail_age_classIdkey: idx_mail_age_classIdkey_len: 83ref: constrows: 1filtered: 100.00Extra: Using index
1 row in set, 1 warning (0.00 sec)

如果新增一个列:

select mail,age,class_id,sn from index_demo where mail = '1020000@qq.com'\G

由于sn 不是索引中的列,只能通过索引记录中的主键ID,再到主表中查询所有的数据,最终返回结果集,这个现象叫回表查询

回表查询

当使用索引检索数据时,查询的列不只包含索引列,这时需要通过索引中记录的主键值到主表中进行查询,这个现象叫做回表查询;

mysql> explain select * from index_demo where mail = '1020000@qq.com'\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: index_demopartitions: NULLtype: ref
possible_keys: idx_mail_age_classIdkey: idx_mail_age_classIdkey_len: 83ref: constrows: 1filtered: 100.00Extra: NULL
1 row in set, 1 warning (0.00 sec)

即使使用了复合索引,但也发生了回表查询;回表查询需要额外的磁盘I/O(如果数据页不在缓冲池中),对于高频查询,建议优化为覆盖索引查询;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/958760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp.net网站编译后出现“发现不明确的匹配”的错误

asp.net网站编译后出现“发现不明确的匹配”的错误参考文章——asp.net系统发布后,报错 :Ambiguous match found. 解决办法 没想到asp.net编译后,变量竟然没有区分大小写。

量化选股与量化交易第820篇:趋势突破K线均线平台指标公式 - Leone

趋势突破K线均线平台指标简介 一、核心指标: 1、MA25:25日简单移动平均线,用于平滑股价数据,反映中期趋势。 2、EMA135:135日指数移动平均线,对价格变化更为敏感,用于捕捉长期趋势。 3、EMA250:250日指数移动平均线…

Docker 部署 Oracle Linux 实操全流程

Oracle Linux 不只是普通的 RHEL 兼容发行版,更是经过 Oracle 每日超 12 万小时工作负载测试的企业级系统,自带 Ksplice(零停机内核补丁)、DTrace(实时诊断)等独家功能,尤其适合搭配 Oracle 数据库、中间件等生…

Redis Key 命名规范文档(含图表与命名规则)

Redis Key 命名规范文档(含图表与命名规则) 一、命名规范与结构说明 统一 Redis Key 命名规范有助于: ✅ 快速定位缓存来源模块 ✅ 避免 Key 冲突与重复写入 ✅ 支持多语言、多租户缓存隔离 ✅ 方便统一监控与清理 …

AI可能的发展

我觉得AI的发展,突破关键是:不会有“意外”  事情是这样的,我最近一直在用AI去了解一些事情。但只是内容的更新,只是从我从别人那里获得了新信息和疑惑之后。我请AI帮我分析。(从AI的本质上可以看出来)但得到的…

联想瑞天500无法禁用安全启动的解决办法

联想瑞天500无法禁用安全启动的解决办法最近给一台联想瑞天500-161Rh的台式机安装银河麒麟系统,用安装盘启动弹出红色警告框,提示要关闭安全启动。进入bios后,在Security菜单最下面找到安全启动选项,但点击进去发现…

2025年中国婚姻家事律师财富管理推荐:专业实力与口碑对比榜

一、引言与行业趋势分析 过去五年,全国法院受理的婚姻家事案件年均增长11.3%,其中涉及股权、信托、跨境保单等复杂财产形态的占比已突破42%。高净值人群在婚姻危机中最关心的不再是“能否离”,而是“如何安全、合规…

【2025膨润土厂家信息:东北防水毯原料名录】

2025年,膨润土在造纸、涂料、非开挖泥浆、防水防渗等场景需求持续放大,但产地分散、指标差异大,采购方常因“区域匹配度”与“应用适配性”两大痛点延误工期。本文按“地域分布—技术专长—服务场景”三维梳理,把最…

2025年膨润土厂家信息:造纸涂料领域应用优选

引言 膨润土作为“工业味精”,在造纸、涂料、环保、石油钻井等场景不可替代。2025年,华东、华北、华南三大产区产能已占全国七成,但厂家在改性工艺、认证等级、配送半径上差异巨大。本文按“区域就近、认证齐全、应…

【2025年】撕碎机厂家信息:华东固废处理五强榜单

2025年,固废资源化政策趋严,企业亟需高效、低耗、智能的撕碎设备。本文按地域分布、技术专长、典型场景三大维度,对国内五家主流撕碎机厂家进行梳理,帮助终端用户、回收商及环保工程公司在短时间内锁定可靠供应商,…

【2025年撕碎机厂家信息:生活垃圾资源化方案】

引言 2025年,固废减量化、资源化政策全面落地,撕碎机成为垃圾处理、再生金属、塑料回收等场景的刚需装备。本文按“地域分布—技术专长—典型应用”三维梳理,精选五家撕碎机厂家,覆盖华东、华南、华北三大产业带,…

Mediatr第一课

第一步 引入NuGet安装该包 MediatR(新版就可以) 第二步 服务注入 builder.Services.AddMediatR(cfg => { cfg.RegisterServicesFromAssemblyContaining<Program>();}); 说明: MediatR 有两种消息进行分发: …

【2025年膨润土厂家信息:华东高纯钠基五强榜单】

2025年,膨润土在造纸、涂料、非开挖、铸造、环保等细分场景的需求持续分化,用户对“高纯度、高分散、高稳定性”指标的关注度显著提升。为帮助采购、技术、工程部门在一个月内完成供应商比选,本文把公开渠道可核实的…

LLMOps+DeepSeek:大模型赋能一体化运维

本文来自腾讯蓝鲸智云社区用户: CanWay01.背景 蛇年伊始,DeepSeek凭借其卓越表现火爆出圈,让AI大模型瞬间成为街头巷尾热议的焦点,也让大众重新燃起对AGI(通用人工智能)“平民化”的信心,DeepSeek通过先进的模型…

量化选股与量化交易第823篇:通达信潜伏涨停板 - Leone

通达信潜伏涨停板主图MA5:MA(C,5); MA10:MA(C,10); MA20:MA(C,20); MA60:MA(C,60); N:=7; N1:=20; M:=20;V1:=MA(VOL,5); V2:=VOL/REF(V1,1)>2; ZYG1:=MA(CLOSE,M); ZYG2:=HHV(HIGH,M); ZYG3:=LLV(LOW,M); ZYG4:=(Z…

深入解析:权限管理混乱微服务安全架构:OAuth2.0+JWT无感刷新方案非法请求拦截率

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

量化选股与量化交易第822篇:通达信超级暗盘买入 - Leone

通达信超级暗盘买入主图ZK1:(EMA(EMA(H,25),25)-EMA(EMA(L,25),25))*1+EMA(EMA(H,25),25),DOTLINE,COLORBLUE; ZD1:EMA(EMA(L,25),25)-(EMA(EMA(H,25),25)-EMA(EMA(L,25),25))*1,LINETHICK2,COLORRED; ZD2:EMA(ZD1,25)…

2025年中国婚姻家事律师财富管理推荐:专业实力与口碑对比排行榜

一、引言与行业趋势分析 2024年民政部数据显示,全国办理离婚手续的夫妻仍维持在287.9万对,其中涉及房产、股权、跨境资产等复杂财产分割的比例已升至43%,较五年前增长近12个百分点。高净值人群婚姻纠纷中,隐匿、代…

电脑中英文切换的问题,实时显示输入法状态

电脑中英文切换的问题,实时显示输入法状态电脑中英文切换的问题,实时显示输入法状态https://inputtip.abgox.com/zh-CN/download/

2025年200元左右美白精华产品推荐:基于成分与肤感的权威对比榜

一、行业趋势与用户需求洞察 中国美白精华赛道在2024年零售额已突破210亿元,其中200元价格带贡献近38%销量,成为年轻消费者“第一瓶功效精华”的核心入口。艾瑞咨询《2024护肤趋势白皮书》指出,18-30岁用户购买美白…