如果你曾试图加快运行缓慢的查询,想必有人会建议你“只需查看执行计划”。这是一条不错的建议,但如果你之前从未读过执行计划,其输出内容可能会让你觉得像是看不懂的外星语言。本文将解释什么是执行计划、如何理解它们,以及现代工具如何能大大减轻这一过程中的困扰。
什么是查询执行计划?
当你运行 SQL 查询时,数据库不会突然行动,随机扫描表。相反,查询优化器——每个主要数据库引擎内置的一个组件——会评估数十甚至数百种可能的数据检索策略,估算每种策略的成本,并最终确定它评估出最快的方案。执行计划是数据库中对该决策的书面记录。
这与导航系统规划路线的方式颇为相似。如果你要求从 A 点前往 B 点,导航系统会计算出最佳的行车路线;它给你呈现的逐段指引就是该路线规划。理解这个规划能让你知道是行驶在高速公路上还是土路上,更重要的是,还能让你知道哪里是交通瓶颈所在。
如何生成执行计划
在大多数数据库中,你可以通过在查询前加上“EXPLAIN关键字来生成计划。MySQL、PostgreSQL、MariaDB 和 SQLite 都支持这种语法,而 SQL Server 则通过设置“SET SHOWPLAN_ALL ON”或在其工具中使用图形执行计划按钮来实现。不同数据库的输出会有所不同,但其基本概念在所有数据库中是相同的。
例如,执行“EXPLAIN SELECT * FROM orders WHERE customer_id = 42”这一操作并不会实际执行该查询。相反,它会返回关于数据库计划“如何”执行该查询的描述。然后,你可以根据这一描述来决定是否需要进行任何优化。
需要注意的关键事项
执行计划乍一看可能会让人感到有些难以理解,因为它们会一次性呈现大量信息。不过幸运的是,大多数性能问题通常会通过一些明显的迹象表现出来:
首先要留意的是全表扫描,这种操作在 MySQL 中通常被标记为“ALL”,在 PostgreSQL 中则被称为“Seq Scan”。这意味着数据库会读取表中的每一行以找到所需的数据——这相当于逐本书地在图书馆中查找,而不是利用目录进行查找。对于小型表来说,这种操作并无大碍,但对于大型表而言,几乎总是会造成问题。
接下来,请注意估计的行数。优化器的估计值会决定其决策过程,因此如果估计值与实际情况相差甚远,那么它所选择的方案可能会效率低下。较大的差异通常表明统计信息已过时,对此你可以通过运行 ANALYZE 或 UPDATE STATISTICS 命令(具体取决于你的数据库)来修正。
最后,我们来看一下连接类型。嵌套循环连接在连接的一侧数据量较小的情况下表现良好,而哈希连接则更适合处理较大的数据集。如果计划是在两个大型表之间选择使用嵌套循环连接,那么添加适当的索引或重新设计查询可能会促使优化器采用更高效的策略。
Navicat 可视化解释功能
直接将原始的 EXPLAIN 输出以纯文本形式进行阅读需要一定的练习和耐心。而 Navicat 17 则通过显著增强的“可视化解释”功能解决了这一问题,它能将执行计划数据转化为图形形式,使得一目了然地理解变得非常容易。
它不会逐行解析文本,而是将执行计划以可视化流程的形式呈现出来,每个操作都被显示为一个节点。Navicat 会突出显示成本高或效率低的操作,这样你的目光就能立即被吸引到计划中需要关注的部分——无需进行任何心算!对于那些更喜欢处理原始数据的用户,Navicat 还提供了多种格式来展示同一计划:包括可视化、JSON、文本和统计视图,你可以根据需要切换查看这些不同的视图。
这种多格式方法在跨不同数据库平台工作时尤其有用,因为每个引擎的 EXPLAIN 输出格式不同。Navicat 会规范使用体验,无论你使用的是 MySQL、PostgreSQL 或其他支持的数据库,检查执行计划的工作流程都能保持一致。
实用的规划分析方法
通过执行计划来建立信心的最佳方法是先从你已经熟悉的一个查询开始,生成其计划,然后逐步跟踪该计划。添加一个索引并再次运行“EXPLAIN”命令。你会实时看到计划的变化,这能帮助你直观地了解优化器如何应对模式变化。
随着时间的推移,识别出全表扫描或不准确的行估计这类情况会变得轻车熟路。执行计划不再让人感觉像是对内部细节的晦涩表述,而开始让人觉得它确实就是它本身的样子:即对数据库正在做什么以及为何如此操作的清晰解释。
结语
执行计划是开发人员或数据库管理员性能工具包中最强大的工具之一——而且它们的使用方法远比其表面看起来要容易得多。一旦你了解了全表扫描的样子、行计数估计的意义以及连接类型的不同之处,你就具备了诊断大多数查询性能问题所需的大部分知识。将这些知识与像 Navicat内置的解释可视化工具这样的可视化工具相结合,你就能在比预期更短的时间内从困惑中走向自信的诊断。

