导读:本期聚焦于过客创作的《为什么你的SQL查询这么慢?浅谈SQL语句优化该从哪入手》,敬请观看详情。一张千万级订单表上执行模糊查询竟耗时十二秒,问题往往出在索引失效与全表扫描。本文从数据库执行计划切入,说明如何通过复合索引覆盖高频查询字段,避免SELECT星号带来的额外IO。同时对比子查询与连接查询在分页场景下的性能差异,指出在WHERE子句中对字段使用函数会导致优化器放弃索引。掌握EXPLAIN工具解读rows与type列,就能定位大多数慢查询瓶颈,而不必盲目增加硬件资源。

SQL语句优化是后端开发中无法绕开的话题。当业务数据量从几万行膨胀到上千万行,原本在测试环境秒回的查询可能在生产环境直接拖垮数据库连接池。优化的本质不是改写几句语法,而是理解数据库引擎如何存取数据、如何选择合适的访问路径。

为什么你的SQL查询这么慢?浅谈SQL语句优化该从哪入手

从执行计划看数据库怎么跑你的SQL

很多开发者调优时习惯凭直觉改语句,但真正科学的起点是看执行计划。在MySQL中只需在查询前加上EXPLAIN关键字,就能得到优化器对这条语句的执行预估。计划中的type列显示了访问类型,从最优的systemconst到最差的ALL(全表扫描),差距可达几个数量级。rows列代表引擎认为需要扫描的行数,如果这个值接近全表总量,基本可以确定没走索引。

举个例子,一张用户表有索引在age字段,但查询写成WHERE YEAR(create_time)=2023,由于对字段套了函数,优化器无法利用create_time上的索引,只能全表逐行计算。改用范围查询create_time >= '2023-01-01' AND create_time < '2024-01-01'后,执行计划的type会从ALL变为range,扫描行数骤减。

除了基础列,还要关注Extra里的Using filesortUsing temporary。前者意味着排序没用到索引,后者常出现在GROUP BY或DISTINCT缺乏合适索引时。一旦出现这两个提示,在大数据集上就会有明显的性能悬崖。通过联合索引把排序字段纳入,往往能直接消除文件排序。

索引设计中的常见误区与正确姿势

索引不是越多越好。每个索引都会占用存储空间,并在增删改时带来维护开销。最常见误区是为每列单独建索引,然后写WHERE a=1 AND b=2,以为两个单列索引能被同时使用。实际上多数存储引擎一次查询通常只选一个索引,这时复合索引(a,b)才是正解,且要遵循最左前缀原则:查询条件必须从索引第一列开始连续匹配。

另一个容易被忽视的点是索引覆盖。如果查询只需要idstatus两列,而这两列恰好都在复合索引里,引擎无需回表取数据,直接在索引树读完就返回,执行计划Extra显示Using index。这比SELECT *再回主键查找要快得多。因此写查询时应明确列出所需字段,而不是图省事用星号。

对于文本字段的模糊查询,前置通配符LIKE '%abc'必然导致索引失效,因为B+树无法从中间匹配。若业务允许,尽量用LIKE 'abc%'保留左前缀;实在需要全文检索,应考虑倒排索引或专用搜索引擎。以下示例展示了一个合理的复合索引建立方式:

-- 订单表常按用户和状态筛选并按时间倒序
CREATE INDEX idx_user_status_time ON orders (user_id, status, create_time DESC);

-- 可命中索引的查询
SELECT id, amount, create_time
FROM orders
WHERE user_id = 1001 AND status = 1
ORDER BY create_time DESC
LIMIT 20;

改写语句结构带来的实质性提升

除了索引,语句自身的结构也大有可为。分页场景里LIMIT 100000, 20的写法会让引擎先排序再丢弃前十万行,越翻页越慢。改用游标分页,以最后一页的最大ID为基准:WHERE id > 上次最大ID ORDER BY id LIMIT 20,把全量排序变成索引范围扫描,性能直线上升。

子查询与连接的选择也需具体分析。早期MySQL版本对子查询优化较弱,IN (SELECT ...)可能被改写成多次查询;现代版本虽已改善,但在某些统计场景下,左连接配合聚合仍比嵌套子查询更可控。如下代码对比了两种写法:

-- 子查询写法
SELECT u.name, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS cnt
FROM users u;

-- 连接与聚合写法
SELECT u.name, COUNT(o.id) AS cnt
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.name;

此外,避免在WHERE中对字段做隐式类型转换,例如字段是字符串却用数字比较,也会让索引失效。养成用EXPLAIN验证的习惯,结合慢查询日志定位高频耗时语句,才能把优化工作做得精准而不是盲目。当数据量进一步膨胀,还可考虑分库分表、读写分离,但那属于架构层手段,语句与索引优化永远是性价比最高的第一道防线。

SQL优化索引设计执行计划修改时间:2026-08-16 12:00:14

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。