如何解释查询的执行计划?

92

当试图理解SQL语句的执行方式时,有时建议查看执行计划。解释(理解)执行计划的过程应该如何进行?哪些因素应该引起我们注意,并认为"噢,这很棒!",哪些因素则表明出现了问题,让我们感到"不对劲"呢?

11个回答

83
每当我看到评论说全表扫描是不好的,索引访问是好的时候,我就感到恐惧。全表扫描、索引范围扫描、快速完整索引扫描、嵌套循环、合并连接、哈希连接等仅仅是必须被分析人员理解的访问机制,并且结合对数据库结构和查询目的的了解,才能得出任何有意义的结论。
全扫描只是读取数据段(表或表子分区)中大部分块的最有效方式,虽然它通常可以表示性能问题,但这仅仅是在上下文中是否为实现查询目标的有效机制方面。作为数据仓库和BI的人,我对性能的第一项警告标志是基于索引的访问方法和嵌套循环。
因此,关于如何阅读Oracle文档中的执行计划机制,可以参考:http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/ex_plan.htm#PFGRF009 同时也要好好阅读《性能调整指南》。
还可以搜索“基数反馈”(cardinality feedback),这是一种技术,可以使用执行计划来比较查询中各个阶段的基数估计值与执行过程中实际经验的基数。我相信 Wolfgang Breitling 是该方法的作者。
总之,了解访问机制、了解数据库、了解查询意图,避免使用经验法则。

5
在前九个单词后我就知道是你了,这就像“猜曲名”一样......我能在不到n个单词中识别出Dave A的帖子... - Mark Brady
我会对您使用“大”的方式提出一些质疑……有时候数据在索引列周围的聚类非常差,以至于全文本搜索(FTS)甚至可以比索引扫描更快地处理10%的行…… - Mark Brady
1
在10%的情况下 - 绝对没问题。如果每个块有200行,你要找到0.5%的行,那么理论上你可能需要访问100%的块才能获取所有的值,所以这比10%更极端。 - David Aldridge

13

1
链接已经失效。这里是更新版本(适用于11.2)的链接:http://download.oracle.com/docs/cd/E11882_01/server.112/e16638/toc.htm - Alexander Malakhov

5
以下两个例子展示了使用索引进行FULL和FAST扫描。
最好关注成本和基数。从这些例子中可以看出,使用索引可以减少运行查询的成本。
虽然有点复杂(我并不完全掌握),但基本上成本是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

正如已经建议的那样,请注意表扫描。通常可以避免这些情况。


嗯,规则模式没有成本...所以我猜你的说法在某种绝对的方式上是正确的,但我会说它在根本上是不准确的。如果你使用CHOOSE,你可能会得到RBO或CBO。CBO是唯一计算成本的选项。 - Mark Brady

4
寻找像顺序扫描这样的东西可能有些有用,但现实在于数字...除非这些数字只是估计值!比查看查询计划更有用的通常是查看实际执行。在Postgres中,这就是EXPLAIN和EXPLAIN ANALYZE之间的区别。EXPLAIN ANALYZE实际上执行查询,并获取每个节点的实时时间信息。这让你看到了实际发生的事情,而不是规划者认为会发生的事情。很多时候,你会发现顺序扫描根本不是问题,而是查询中的其他东西。
另一个关键是确定实际昂贵的步骤是什么。许多图形化工具将使用不同大小的箭头来指示计划的不同部分的成本。在这种情况下,只需要寻找进入细箭头和离开厚箭头的步骤。如果您没有使用GUI,则需要观察数字并寻找突然变得更大的地方。通过一点练习,很容易找出问题所在的区域。

3
针对这类问题,最好的做法是去 ASKTOM。他在回答该问题时提供了指向在线Oracle文档的链接,其中很多这些规则都有解释。
需要记住的一件事是,执行计划只是最好的猜测。
学习使用sqlplus并尝试AUTOTRACE命令是个不错的主意。通过一些确定的数字,您通常可以做出更好的决策。
但是你应该去问ASKTOM。他知道所有相关信息 :)

2

“Oh no,那不对”通常是由表扫描引起的。表扫描不利用任何特殊索引,可能导致内存缓存中的所有有用信息被清除。例如,在PostgreSQL中,你会发现它长成这样。

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

有时候,全表扫描比使用索引查询行更加理想。然而,这是你似乎在寻找的那些红旗模式之一。

2
(完整的)表扫描不一定会清除内存缓存。 - user330315

2

解释的输出会告诉您每个步骤所花费的时间。首先要找出花费时间较长的步骤并了解它们的含义。像顺序扫描这样的东西告诉您需要更好的索引-这主要是对您特定数据库的研究和经验的问题。


2

基本上,您需要查看每个操作并确定它们是否“合理”,根据您对其应该如何工作的了解。

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


1

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

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

If you see any of the following in an execution plan, you should consider them warning signs and investigate them for potential performance problems. Each of them are less than ideal from a performance perspective.

* 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? 

It is not always possible to avoid these, but the more you can avoid them, the faster query performance will be.


1
表扫描并非全都不好 - 取决于从表返回/处理的记录数量,全表扫描可能比索引扫描更快(如果您无论如何都要返回记录,则需要进行索引扫描和对表的完整读取 - 2个步骤而不是1个)。 - ScottCher

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接