MySQL的解释输出非常简单.PostgreSQL有点复杂.我无法找到解释它的好资源.
你能描述一下究竟解释的是什么,或者至少指出一个好资源的方向吗?
我总是觉得困惑的部分是启动成本与总成本.我每次忘记它都会谷歌,这让我回到这里,这并没有解释其中的差异,这就是我写这个答案的原因.这是我从Postgres EXPLAIN
文档中收集到的内容,据我所知解释.
以下是管理论坛的应用程序示例:
EXPLAIN SELECT * FROM post LIMIT 50; Limit (cost=0.00..3.39 rows=50 width=422) -> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
以下是PgAdmin的图解说明:
(当您使用PgAdmin时,您可以将鼠标指向某个组件以阅读费用明细.)
成本被表示为元组,例如,费用LIMIT
就是cost=0.00..3.39
并且顺序扫描的成本post
是cost=0.00..15629.12
.元组中的第一个数字是启动成本,第二个数字是总成本.因为我使用EXPLAIN
而不是EXPLAIN ANALYZE
,这些成本是估计,而不是实际的措施.
启动成本是一个棘手的概念.它不仅仅代表该组件启动之前的时间量.它表示组件开始执行(读入数据)和组件输出第一行之间的时间量.
总成本是组件的整个执行时间,从开始读取数据到完成写入输出的时间.
作为一个复杂因素,每个"父"节点的成本包括其子节点的成本.在文本表示中,树由缩进表示,例如LIMIT
是父节点并且Seq Scan
是其子节点.在PgAdmin表示中,箭头指向从子到父 - 数据流的方向 - 如果您熟悉图论,这可能是违反直觉的.
文档说成本包含所有子节点,但请注意,父节点的总成本3.39
远小于其子节点的总成本15629.12
.总成本不包括在内,因为像LIMIT
这样的组件不需要处理其整个输入.请参阅Postgres 文档中的EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;
示例.EXPLAIN
在上面的示例中,两个组件的启动时间均为零,因为在开始写入行之前,两个组件都不需要执行任何处理:顺序扫描会读取表的第一行并发出它.在LIMIT
读取它的第一行,然后发射它.
组件何时需要在开始输出任何行之前进行大量处理?有很多可能的原因,但让我们看一个明显的例子.这是前面的相同查询,但现在包含一个ORDER BY
子句:
EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50; Limit (cost=23283.24..23283.37 rows=50 width=422) -> Sort (cost=23283.24..23859.27 rows=230412 width=422) Sort Key: body -> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
并以图形方式:
再次,顺序扫描post
没有启动成本:它立即开始输出行.但是这种排序具有很大的启动成本,23283.24
因为它必须在整个表排序之后才能输出一行.排序的总成本23859.27
仅略高于启动成本,这反映了这样一个事实,即整个数据集一旦排序,排序的数据就可以非常快速地发出.
请注意,启动时间LIMIT
23283.24
恰好等于排序的启动时间.这不是因为LIMIT
它本身具有很高的启动时间.它本身实际上没有启动时间,但会EXPLAIN
为每个父项汇总所有子成本,因此LIMIT
启动时间包括其子项的总启动时间.
这种成本汇总使得难以理解每个单独组件的执行成本.例如,我们的LIMIT
启动时间为零,但乍一看并不明显.出于这个原因,其他几个人挂explain.depesz.com,由休伯特Lubaczewski(又名depesz),有助于理解创建的工具EXPLAIN
的-除其他事项外-减去从父成本孩子的费用.他在一篇关于他的工具的短篇博文中提到了其他一些复杂问题.
Explaining_EXPLAIN.pdf也可以提供帮助.
它从大多数缩进到最小缩进执行,我相信从计划的底部到顶部.(因此,如果有两个缩进的部分,页面下方的一个首先执行,那么当它们遇到另一个执行时,则执行连接它们的规则.)
我们的想法是,每个步骤都有1个或2个数据集到达并由某个规则处理.如果只有一个数据集,则对该数据集执行该操作.(例如,扫描索引以确定所需的行,过滤数据集或对其进行排序.)如果是两个,则两个数据集是进一步缩进的两个数据集,并且它们由您看到的规则连接.大多数规则的含义可以合理地容易猜到(特别是如果你之前已经阅读过一堆解释计划),但是你可以尝试通过查看文档来验证单个项目,或者(更容易)通过将短语投入到谷歌以及一些关键词EXPLAIN
.
这显然不是一个完整的解释,但它提供了足够的上下文,你通常可以找到你想要的任何东西.例如,从实际数据库中考虑此计划:
explain analyze select a.attributeid, a.attributevalue, b.productid from orderitemattribute a, orderitem b where a.orderid = b.orderid and a.attributeid = 'display-album' and b.productid = 'ModernBook'; ------------------------------------------------------------------------------------------------------------------------------------------------------------ Merge Join (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1) Merge Cond: (a.orderid = b.orderid) -> Sort (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1) Sort Key: a.orderid Sort Method: quicksort Memory: 1695kB -> Bitmap Heap Scan on orderitemattribute a (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1) Recheck Cond: ((attributeid)::text = 'display-album'::text) -> Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1) Index Cond: ((attributeid)::text = 'display-album'::text) -> Sort (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1) Sort Key: b.orderid Sort Method: quicksort Memory: 76kB -> Bitmap Heap Scan on orderitem b (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1) Recheck Cond: ((productid)::text = 'ModernBook'::text) -> Bitmap Index Scan on id_orderitem_productid (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1) Index Cond: ((productid)::text = 'ModernBook'::text) Total runtime: 842.134 ms (17 rows)
尝试自己阅读,看看它是否有意义.
我读到的是数据库首先扫描id_orderitem_productid
索引,使用它来查找它想要的行orderitem
,然后使用快速排序对该数据集进行排序(如果数据不适合RAM,则使用的排序会发生变化),然后将其放在一边.
接下来,它会扫描orditematt_attributeid_idx
以找到它想要的行orderitemattribute
,然后使用快速排序对该数据集进行排序.
然后它获取两个数据集并合并它们.(合并连接是一种"压缩"操作,它会并行处理两个已排序的数据集,在匹配时发出连接的行.)
正如我所说,你通过计划内部部分到外部部分,从下到上.
还有一个在线帮助工具,Depesz,它将突出显示分析结果中昂贵部分的位置.
也有一个,这里有相同的结果,这让我更清楚问题出在哪里.
PgAdmin将向您显示解释计划的图形表示.在两者之间来回切换可以真正帮助您理解文本表示的含义.但是,如果您只是想知道它会发生什么,您可以始终使用GUI.
PostgreSQL的官方文档提供了有关如何理解解释输出的有趣,彻底的解释.