滚动新闻 →
法球星姆巴佩梗图现两版本 反映中外信息落差 以色列总理维持最大党但未过半 有三种结果 长沙汽车在公交站前冲撞人群 现场惨烈 美国务院点名中共:跨国镇压威胁异议人士 突发!朝鲜射10多枚导弹 日本:强烈谴责 选举倒数六天 川普俄亥俄助选 打击非公民投票 中共反腐实为权斗工具 评:专制腐朽越反越腐 用姆巴佩风波转移焦点? 专家析中共政治算计 五中全会清洗33人 胡春华露面 张升民上位 俄乌局部停火持续 人道救援与排雷同步展开 Kubernetes 多集群为什么适合大型 AI 平台,多个 GPU 集群如何统一管理 Google Cloud 资源标签怎么规划,如何知道每个项目到底花了多少钱 博索纳罗抵达迈阿密筹备记者会 称选举遭操控 美国或于11月大选后对伊朗采取军事行动,波斯、湾多国已获知会 小博索纳罗一家获准入境迈阿密 沈阳高中筛查事件引家长抗议 共用针头疑涉艾滋风险 MySQL EXPLAIN 怎么看?SaaS 开发者优化查询必须掌握的几个字段 U盘插入电脑以后发热严重,还能继续通电测试吗 匈牙利突袭行动揭露新冠医疗采购疑云:仓库堆积中国产呼吸机 美情报机构披露:中国女子疑似接近黄仁勋,涉中共间谍活动 美国中期选举前夕FEC遭黑客攻击 电子申报系统中断 法国球星姆巴佩涉辱华争议 梗图言论引中方强烈反应 朝鲜密集发射弹道导弹,回应韩方对话提议 路透社揭露伊朗军火供应链:5000个秘密机构如何绕过制裁 Windows 11 账户头像怎么修改?个人账户信息可以这样管理 MySQL 数据库越来越大怎么办?从表结构到历史数据逐步优化 五中全会通报刘建超被处理 政治局委员仍缺两人 中共推动献血任务以提取救命制剂应对严峻疫情 中国古代文学中的旅行书写 江南地区的传统饮食养生观 美军强化供应链自主性 Anduril联合高通推出纯国产军用笔记本 经济学家:民众抢购黄金应对中国经济低迷 中共前副总理刘延东病逝于五中全会期间 胡春华现身五中全会 状态引关注 中国传统文房用品有哪些 让孩子懂得承认错误也是对别人的尊重 美使馆升级警告!伊领袖:终结现状 蒋万安开抄沈伯洋? 纽约州长选举临近 布莱克曼承诺取消拥堵费并终结庇护州政策 美司法部指控加州超2万非公民登记,法官将周三裁决 中共五中全会出席率创历史新低 空位数量激增

MySQL EXPLAIN 怎么看?SaaS 开发者优化查询必须掌握的几个字段

发布时间: 2026-10-29 10:00:01    最后更新: 2026-10-29 10:45:57    阅读:7  约12 分钟阅读     

MySQL EXPLAIN 怎么看?SaaS 开发者优化查询必须掌握的几个字段
图片说明:示意图   图片来源:Public Domain(公有领域)
MySQL EXPLAIN 怎么看 从执行计划判断SaaS查询是否存在性能问题

在SaaS系统中,一条SQL可能每天执行几百万次。即使单次查询只增加几毫秒,累计起来也可能成为数据库CPU、I/O和连接池的长期负担。MySQL提供的EXPLAIN,是开发人员分析SQL执行计划最重要的工具之一。

但EXPLAIN并不是一张简单的“红绿灯表”。看到ALL、Using filesort或者key=NULL就立即加索引,往往会把问题越改越复杂。真正有效的优化方法,是理解优化器为什么选择这种执行方式,再结合实际数据量和运行时间判断它是否合理。

一、先看type,但不要把它当成绝对排名

type描述MySQL访问表或索引的方式。常见类型包括const、eq_ref、ref、range、index和ALL等。

例如:

EXPLAIN
SELECT *
FROM users
WHERE id = 1000;

如果id是主键,优化器通常可以使用非常直接的索引访问方式。

ref常见于通过非唯一索引进行等值匹配,range则常见于范围查询,例如:

WHERE created_at >= '2026-09-01'
AND created_at < '2026-10-01'

ALL表示全表扫描,但“全表扫描”本身并不是错误。

如果一张表只有几百行,优化器可能认为直接扫描整张表比走索引更加便宜。真正需要关注的是:表有多大、实际需要读取多少行、查询多久、执行频率多高。

因此,不要制定“看到ALL就必须加索引”的规则。

二、key告诉你最终用了哪个索引

key是判断索引是否被实际采用的重要字段。

例如表上存在:

CREATE INDEX idx_users_email
ON users(email);

查询:

SELECT id, name
FROM users
WHERE email = 'tom@example.com';

如果执行计划中的key显示idx_users_email,说明优化器选择了这个索引。

但如果key为NULL,也不能直接得出“数据库没有索引”或者“SQL一定很慢”的结论。

可能的原因包括表太小、条件选择性太低、优化器判断全表扫描成本更低,或者现有索引并不适合这个查询。

因此,应该同时查看possible_keys、key、rows以及实际执行时间。

三、联合索引最容易被误解

SaaS系统经常存在类似查询:

SELECT id, status, created_at
FROM orders
WHERE tenant_id = 100
AND status = 1
ORDER BY created_at DESC
LIMIT 50;

如果大量查询都具有这种访问模式,可以考虑针对实际SQL建立联合索引,例如:

CREATE INDEX idx_orders_tenant_status_created
ON orders(tenant_id, status, created_at);

但联合索引并不是“字段越多越好”。

字段顺序决定了索引能够有效利用哪些前导条件。还要考虑等值条件、范围条件、排序要求以及字段选择性。

例如:

INDEX(tenant_id, status, created_at)

与:

INDEX(created_at, tenant_id, status)

并不能简单互换。

因此,索引设计应该从真实SQL出发,而不是先设计一个“万能索引”。

四、rows比很多人想象得更重要

rows表示优化器估算需要检查的行数。

例如两个执行计划都显示使用索引,一个估算需要读取几十行,另一个需要读取数十万行,它们的性能风险显然不同。

但rows是估算值,不是真实执行过程中精确读取的行数。因此不能简单规定“rows超过1000就必须加索引”。

更值得关注的是估算是否严重偏离实际情况。

这也是EXPLAIN ANALYZE非常有价值的原因:

EXPLAIN ANALYZE
SELECT ...

它会实际执行SQL,并提供实际运行过程中的信息。对于慢SQL排查,可以将优化器估算与实际执行情况结合起来观察。

如果估算和实际差距很大,就应该进一步检查统计信息、数据分布以及查询条件,而不是马上继续堆索引。

五、Extra中的Using filesort并不等于磁盘爆炸

Extra包含很多有用的信息。

Using filesort表示MySQL需要采用额外的排序过程。这个名字很容易造成误解,它并不意味着一定在使用磁盘文件,也不代表看到它就必须建立索引。

如果查询只返回很少的数据,排序成本可能完全可以接受。

例如:

SELECT id, name
FROM users
WHERE status = 1
ORDER BY created_at DESC
LIMIT 20;

如果排序涉及的数据规模并不大,那么Using filesort未必是需要解决的问题。

真正需要优化的是高频、大数据量、排序成本明显影响延迟的查询。

Using temporary表示查询过程中使用了临时表等中间处理机制。复杂的GROUP BY、DISTINCT、ORDER BY等操作都可能出现相关执行行为。它是否构成问题,同样需要结合数据规模和实际耗时判断。

Using index通常意味着查询可以直接从索引中获得所需列,也就是常说的覆盖索引场景。这通常有利于减少额外的数据访问,但也不能简单称为“最佳状态”,因为一个复杂查询即使使用覆盖索引,也可能仍然需要处理大量数据。

Using where则只是说明WHERE条件参与了过滤,并不意味着索引有问题。

六、SaaS中的tenant_id要结合数据模型设计

多租户系统经常使用tenant_id进行数据隔离,因此类似:

WHERE tenant_id = ?
AND status = ?

的查询非常常见。

但“所有查询必须包含tenant_id”并不是数据库层面的通用规则。

如果一张表本身就是租户数据表,那么应用和数据访问层确实需要确保租户边界不能被绕过;但系统配置表、国家代码表、汇率表、公共字典表等可能根本不存在租户归属。

更重要的是,不能仅靠开发人员“记得加tenant_id”来保证隔离。Repository、ORM、后台任务、缓存键、消息消费者以及管理接口都需要统一考虑租户边界。

索引方面,如果业务查询长期采用:

WHERE tenant_id = ?
AND created_at >= ?
ORDER BY created_at DESC

那么围绕这种实际访问模式设计联合索引,通常比给tenant_id、created_at分别建立孤立索引更值得研究。

七、不要用SELECT *掩盖真正的I/O成本

查询:

SELECT *
FROM users
WHERE id = ?;

在单行主键查询中通常没有太大问题。

但如果API查询大量记录,SELECT *会让数据库读取和网络传输不必要的字段,也可能让原本可以使用覆盖索引的查询失去这一机会。

例如列表页面只需要:

SELECT id, name, email, created_at
FROM users
WHERE tenant_id = ?
ORDER BY created_at DESC
LIMIT 50;

就没有必要把大型TEXT、JSON或者其他不需要展示的字段全部取出来。

不过也不要为了追求“绝对覆盖索引”而把所有字段都塞进索引。索引本身也会占用空间,并增加写入维护成本。

八、大OFFSET分页是另一个经常被忽视的问题

很多后台系统采用:

SELECT ...
FROM orders
ORDER BY id DESC
LIMIT 100000, 50;

当OFFSET越来越大时,数据库可能需要处理大量前面的记录才能返回最终的50条数据。

对于不断向后翻页的大型数据集,可以考虑Keyset Pagination,也就是基于上一页最后一条记录继续查询,例如:

SELECT ...
FROM orders
WHERE id < ?
ORDER BY id DESC
LIMIT 50;

这种方式尤其适合按照递增或递减主键、时间等稳定字段连续翻页的场景。

九、不要为了EXPLAIN漂亮而优化数据库

实际数据库优化最容易出现的错误,就是为了让执行计划看起来“高级”而不断添加索引。

例如某个查询显示:

type: ALL
key: NULL

开发人员马上建立三个索引;结果SELECT快了一点,却导致INSERT和UPDATE明显变慢,数据库磁盘空间增加,优化器还可能出现更多选择。

正确流程应该是:

先从慢查询日志、APM或者数据库监控找到真正有影响的SQL,再执行EXPLAIN;然后查看访问类型、实际使用索引、估算行数、排序和临时操作;如果需要,再使用EXPLAIN ANALYZE验证真实执行情况。

最后根据实际数据设计索引,并通过压测和生产指标确认优化是否真的有效。

十、EXPLAIN还要结合锁和事务一起看

一条SQL慢,不一定是SQL执行计划慢。

如果查询本身只需要几十毫秒,却因为锁等待最终让API等待几秒,那么单纯研究索引并不能解决问题。

SaaS系统还需要观察事务持续时间、锁等待、死锁、连接池、CPU、磁盘I/O以及并发量。

例如一个看起来使用正确索引的UPDATE,如果长期被另一个长事务阻塞,用户感受到的仍然是“数据库很慢”。

所以EXPLAIN解决的是执行计划问题,而不是整个数据库性能问题。

十一、真正应该建立的是持续诊断体系

对于生产SaaS系统,可以重点观察P95、P99查询延迟、慢查询数量、扫描行数、数据库CPU、磁盘I/O、锁等待、死锁以及连接池使用情况。

发现异常以后,再回到具体SQL。

如果一个查询突然从几毫秒变成几百毫秒,应该检查数据量是否增长、统计信息是否变化、执行计划是否改变、索引是否发生变化,以及是否出现新的锁竞争。

这比定期“给表加几个索引”可靠得多。

EXPLAIN最重要的价值,不是告诉开发人员哪个字段应该建立索引,而是把MySQL优化器准备怎样执行一条SQL展示出来。真正的数据库优化,是理解这个执行计划为什么出现,再判断它与实际业务数据和系统负载是否匹配。

对于SaaS开发者来说,可以把EXPLAIN理解成数据库故障排查中的“诊断仪器”:它提供证据,但最终的判断必须结合SQL、数据规模、访问频率、索引结构、事务和硬件资源共同完成。掌握这一点以后,看到一个ALL或者Using filesort时,就不会条件反射式地拿起“加索引”这把锤子了。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP