课程 10.3 · 阅读时间:~9 分钟
本课程介绍了 SQL 性能分析和优化的实用工具。您将学习数据库引擎如何读取您的查询,什么是执行计划,以及如何在复杂选择中找到瓶颈。我们将重点使用 EXPLAIN 并解释最重要的字段。到本课程结束时,您不仅能够编写 SQL,还能够诊断查询缓慢的原因。
课程 10.3:理解查询优化方法
在上一课中,我们介绍了编写高效 SQL 的核心原则。但如果查询仍然很慢呢?要解决性能问题,您必须用分析替代猜测。每次提交查询时,DBMS 优化器都会构建一个执行计划。
理解 DBMS 打算如何检索数据是更深层次优化的关键。在本课程中,我们将使用开发者的主要诊断工具:执行计划,深入了解引擎内部。
什么是执行计划
执行计划是 DBMS 为运行特定 SQL 查询准备的一组详细步骤。它描述了:
- 表连接的顺序。
- 使用的访问方法(表扫描与索引查找)。
- 每一步的估计行数。
- 估计操作成本(
cost)。
使用 EXPLAIN
在大多数关系型 DBMS 引擎(MySQL、PostgreSQL、MariaDB)中,计划分析的主要命令是 EXPLAIN。
基本语法
在查询前添加 EXPLAIN:
EXPLAIN
SELECT customer_id, first_name, last_name
FROM customer
WHERE active = 1;
结果:DBMS 返回一个表,每一行代表一个执行步骤。
在计划分析中关注的内容
在阅读 EXPLAIN 时,这些字段尤其重要。
1. 访问类型(type 或 access_type)
此字段显示行是如何读取的:
const/eq_ref:优秀;唯一键查找。ref:非常好;可能返回多行的索引查找。range:良好;索引范围扫描(BETWEEN、>等)。index:中等;全索引扫描。ALL:风险;全表扫描,通常在大表上成本高。
2. 使用的索引(key / possible_keys)
您可以看到优化器选择了哪个索引。如果 key 为 NULL,则没有选择合适的索引,可能会进行扫描。
3. 估计行数(rows)
这是估计要检查的行数。较小的数字通常意味着工作量较少,执行速度更快。
实际示例:找到问题
假设我们运行此查询以获取特定时间戳的付款:
EXPLAIN
SELECT *
FROM payment
WHERE payment_date = '2005-05-25 11:30:37';
如果 type 为 ALL 且 key 为 NULL,则缺少或未使用日期索引。
修复方向:
一个典型的下一步是在 WHERE 中使用的字段上添加索引。我们将在下一课中讨论索引设计,但 EXPLAIN 是揭示需求的工具。
动态优化技术
- 子查询优化: 用
JOIN替换嵌套子查询可以产生更好的计划。 - 物化: 对于经常重用的复杂逻辑,考虑使用物化视图或临时表。
- 逻辑简化: 子查询中不必要的
DISTINCT或ORDER BY可能会阻碍优化器的改进。
本课的关键要点:
- 执行计划是 DBMS 跟随的主要文档,以运行您的查询。
- 使用
EXPLAIN查看数据的实际访问方式。 - 尽量避免在大表上使用
ALL(全表扫描)。 rows有助于估计服务器完成的工作量。- 如果
key为NULL,请检查索引和可 SARG 的谓词。
常见问题解答
如果我的查询已经足够快,为什么还要运行 EXPLAIN?
EXPLAIN 可以在数据量增长之前揭示隐藏的风险。今天可以接受的查询,可能在未来会显著下降。
在计划中最令人担忧的信号是什么?
在大表上,ALL 通常是一个警告信号,因为这意味着全表扫描。它并不总是错误,但应该有正当理由。
为什么 rows 如此重要?
rows 近似于 DBMS 预计在每一步处理的数据量。较大的值通常指示优化应从哪里开始。
面试问题
什么是 SQL 执行计划?
执行计划是 DBMS 优化器 为生成查询结果而构建的策略。它描述了操作顺序、访问方法和估计成本。
您首先检查哪些 EXPLAIN 字段,为什么?
我首先查看 type/access_type、key/possible_keys 和 rows。它们一起显示索引是否被使用、数据是如何访问的,以及主要工作负载出现在哪里。
如何从 EXPLAIN 检测到需要索引?
如果 key 经常为 NULL 且访问类型显示扫描,则应检查 WHERE/JOIN 列的索引。然后比较索引更改前后的计划。
在下一课中,我们将转向最强大的加速工具——索引,并学习如何正确设计它们。
-> 课程大纲