【问题标题】:How do you interpret a query's explain plan?你如何解释查询的解释计划?
【发布时间】:2025-11-29 14:00:02
【问题描述】:

当试图了解 SQL 语句的执行方式时,有时建议查看解释计划。在解释(理解)解释计划时应该经历什么过程?什么应该突出,“哦,这很出色?”与“哦,不,那不对。”

【问题讨论】:

    标签: sql database performance oracle sql-execution-plan


    【解决方案1】:

    查看计划的每个子部分所花费的时间百分比,并考虑引擎正在做什么。例如,如果它正在扫描一个表,请考虑在正在扫描的字段上放置一个索引

    【讨论】:

      【解决方案2】:

      解释的输出告诉您每个步骤花费了多长时间。第一件事是找到花费了很长时间的步骤并理解它们的含义。顺序扫描之类的事情告诉您,您需要更好的索引 - 这主要是研究您的特定数据库和经验的问题。

      【讨论】:

        【解决方案3】:

        “哦,不,那不对”通常是表格扫描。表扫描不使用任何特殊索引,并且有助于清除内存缓存中的所有有用信息。例如,在 postgreSQL 中,你会发现它看起来像这样。

        Seq Scan on my_table  (cost=0.00..15558.92 rows=620092 width=78)
        

        有时表扫描比使用索引查询行更理想。但是,这似乎是您正在寻找的危险信号模式之一。

        【讨论】:

        • (完整)表扫描不一定会清除内存缓存。
        【解决方案4】:

        基本上,您会查看每个操作,并根据您对操作应该如何工作的了解,看看这些操作是否“有意义”。

        例如,如果您在各自的列 C 和 D (AC=BD) 上连接两个表 A 和 B,并且您的计划显示聚集索引扫描(SQL Server 术语 -- 不确定 oracle 术语) 在表 A 上,然后对表 B 上的一系列聚集索引进行嵌套循环连接,您可能会认为有问题。在这种情况下,您可能希望引擎执行一对索引扫描(在连接列上的索引上),然后进行合并连接。进一步的调查可能会发现错误的统计数据使优化器选择了该连接模式,或者一个实际上不存在的索引。

        【讨论】:

          【解决方案5】:

          我主要寻找索引或表扫描。这通常告诉我我在 where 语句或 join 语句中的重要列上缺少索引。

          来自http://www.sql-server-performance.com/tips/query_execution_plan_analysis_p1.aspx

          如果您在 执行计划,你应该考虑 他们警告标志并调查 他们的潜在表现 问题。他们每个人都小于 从性能的角度来看是理想的。

          * Index or table scans: May indicate a need for better or  additional indexes.
          * Bookmark Lookups: Consider changing the current clustered index,
            consider using a covering index, limit
            the number of columns in the SELECT
            statement.
          * Filter: Remove any functions in the WHERE clause, don't include wiews
            in your Transact-SQL code, may need
            additional indexes.
          * Sort: Does the data really need to be sorted? Can an index be used to
            avoid sorting? Can sorting be done at
            the client more efficiently? 
          

          并非总是可以避免 这些,但你可以避免的越多 他们,更快的查询性能 会的。

          【讨论】:

          • 表扫描并不全是坏的——取决于从表返回/处理的记录数量,全表扫描可能比索引扫描更快(如果你要带回记录无论如何,您将执行索引扫描并从表中完整读取 - 2 步而不是 1)。
          【解决方案6】:

          下面的两个示例显示了使用 INDEX 的 FULL 扫描和 FAST 扫描。

          最好专注于成本和基数。查看示例,使用索引可以降低运行查询的成本。

          它有点复杂(我没有 100% 的处理)但基本上成本是 CPU 和 IO 成本的函数,基数是 Oracle 期望解析的行数。减少这两者是一件好事。

          不要忘记查询的成本会受到您的查询和 Oracle 优化器模型(例如:COST、CHOOSE 等)以及您运行统计信息的频率的影响。

          示例 1:

          SCAN http://docs.google.com/a/shanghainetwork.org/File?id=dd8xj6nh_7fj3cr8dx_b

          使用索引的示例 2:

          INDEX http://docs.google.com/a/fukuoka-now.com/File?id=dd8xj6nh_9fhsqvxcp_b

          如前所述,请注意 TABLE SCAN。您通常可以避免这些。

          【讨论】:

          • 呃,规则模式没有成本......所以我猜你的陈述在某种绝对的方式上是正确的,但我会说它从根本上是不准确的。如果您说 CHOOSE,您可以获得 RBO 或 CBO。 CBO 是唯一计算成本的。
          【解决方案7】:

          寻找诸如顺序扫描之类的东西可能会有些用处,但现实就在数字中……除非数字只是估计值!通常比查看查询计划更有用的是查看实际执行。在 Postgres 中,这是 EXPLAIN 和 EXPLAIN ANALYZE 之间的区别。 EXPLAIN ANALYZE 实际执行查询,并获取每个节点的真实时间信息。这让您可以看到实际发生了什么,而不是计划者认为会发生什么。很多时候,您会发现顺序扫描根本不是问题,而是查询中的其他内容。

          另一个关键是确定实际昂贵的步骤是什么。许多图形工具将使用不同大小的箭头来指示计划中不同部分的成本。在这种情况下,只需寻找有细箭头进入和粗箭头离开的步骤。如果您不使用 GUI,则需要观察数字并寻找它们突然变大的地方。稍加练习,就可以很容易地找出问题所在。

          【讨论】:

            【解决方案8】:

            经验法则

            (您可能也想了解详细信息:

            不好

            几个大表的表扫描

            使用唯一索引
            索引包括所有必填字段

            最常见的胜利

            在我见过的大约 90% 的性能问题中,最简单的方法是将包含大量(4 个或更多)表的查询分解为 2 个较小的查询和一个临时表。

            【讨论】:

            • Table Scan 经常被视为坏事,而且最初是没有经验的人会关注的。这在很大程度上取决于从该表返回的记录数,当它更快地执行全表扫描而不是索引查找时存在阈值。
            • 对这个离谱的建议投了反对票。临时表和拆分查询无法解决 90% 的性能问题。你生活在哪个世界?!
            • @Jedi,我生活在这样一个世界里,大多数情况下都是正确的,并且数据库的结构非常合理。不过,我有兴趣阅读您的回答。
            【解决方案9】:

            对于此类问题,最好的办法是ASKTOM。特别是他对该问题的回答包含指向在线 Oracle 文档的链接,其中解释了许多此类规则。

            要记住的一件事是,解释计划确实是最好的猜测。

            学习使用 sqlplus 并尝试使用 AUTOTRACE 命令是个好主意。有了一些硬性数字,您通常可以做出更好的决定。

            但你应该问。他什么都知道:)

            【讨论】:

              【解决方案10】:

              这个主题太大了,无法在这样的问题中回答。你应该花点时间阅读Oracle's Performance Tuning Guide

              【讨论】:

              【解决方案11】:

              每当我看到 cmets 说全表扫描不好而索引访问好时,我都会不寒而栗。全表扫描、索引范围扫描、快速全索引扫描、嵌套循环、合并连接、哈希连接等都是分析人员必须理解的简单访问机制,并结合数据库结构和查询目的的知识为了得出任何有意义的结论。

              完全扫描只是读取数据段(表或表(子)分区)的大部分块的最有效方式,虽然它通常可以指示性能问题,但仅在它是否是实现查询目标的有效机制的背景下。作为一名数据仓库和 BI 人员,我对性能的第一个警告标志是基于索引的访问方法和嵌套循环。

              因此,对于如何阅读解释计划的机制,Oracle 文档是一个很好的指南:http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/ex_plan.htm#PFGRF009

              请仔细阅读性能调优指南。

              还有一个关于“基数反馈”的谷歌,这是一种技术,其中解释计划可用于将查询中各个阶段的基数估计与执行期间经历的实际基数进行比较。我相信 Wolfgang Breitling 是该方法的作者。

              所以,底线是:了解访问机制。了解数据库。了解查询的意图。避免经验法则。

              【讨论】:

              • 在前 9 个字之后我就知道是你。这就像“命名那首曲子”......我可以用 n 个单词或更少的词识别 Dave A 的帖子......
              • 我会对你使用“大”有点狡辩......有时数据可能在索引列周围聚集得很差,以至于 FTS 甚至会执行 10% 的索引扫描行...
              • 10%——绝对。如果您每个块有 200 行并且您正在寻找 0.5% 的行,那么理论上您可能必须访问 100% 的块才能获取所有值,因此它甚至比 10% 还要极端。