Postgresql 理解postgres解释位图堆/索引扫描

Postgresql 理解postgres解释位图堆/索引扫描,postgresql,Postgresql,我有一张450万行的桌子。没有主键。该表有一列p\u id,类型为整数。使用btree方法,此列上有一个索引,idx\u mytable\u p\u id。我有: SELECT * FROM mytable WHERE p_id = 123456; 我对此进行了解释,并看到以下输出: Bitmap Heap Scan on mytable (cost=12.04..1632.35 rows=425 width=321) Recheck Cond: (p_id = 543094) -&

我有一张450万行的桌子。没有主键。该表有一列
p\u id
,类型为整数。使用
btree
方法,此列上有一个索引,
idx\u mytable\u p\u id
。我有:

SELECT * FROM mytable WHERE p_id = 123456;
我对此进行了解释,并看到以下输出:

Bitmap Heap Scan on mytable  (cost=12.04..1632.35 rows=425 width=321)
  Recheck Cond: (p_id = 543094)
  ->  Bitmap Index Scan on idx_mytable_p_id  (cost=0.00..11.93 rows=425 width=0)
        Index Cond: (p_id = 543094)
问题:

  • 为什么该查询先进行堆扫描,然后进行位图索引扫描
  • 为什么要检查425行?为什么操作的宽度是321
  • 12.04..1632.35和0.00..11.93告诉我的成本是多少
对于记录,有773行的
p_id
值为123456。
mytable
上有38列

谢谢

re 1)执行计划必须从最内层节点读取到最外层节点。因此,它首先进行索引扫描(查找行),然后访问实际表以返回索引扫描找到的行

re 2)计划中显示的行数只是基于统计数据的估计,因此425对773听起来相当合理。如果您想查看真实图形,请使用
解释分析

re 3)成本图中的第一个数字是计划员初始化步骤的“启动”成本,第二个成本是该步骤的总成本

这些都记录在手册中:

您可能还需要浏览PostgreSQL Wiki中的以下链接:


为什么该查询先进行堆扫描,然后进行位图索引扫描

事实并非如此。EXPLAIN输出显示了执行节点的结构,处于“更高”级别的节点(不缩进得太远)从它们下面的节点中提取行。因此,当位图堆扫描节点开始提取其第一行时,位图索引扫描将运行以确定要使用的行集,并将第一行上的信息传递给堆扫描。索引扫描传递索引以确定需要读取哪些行,堆扫描实际读取这些行。其思想是,通过从头到尾而不是按索引顺序读取堆,它将减少随机访问——加载给定页面时,将读取该页面中所有匹配的行,并且可以读取足够多的页面,以便使用更便宜的顺序访问,而不是在整个磁盘上来回搜索

为什么要检查425行

不是。您运行了EXPLAIN,它只显示了估计值和所选计划,它根本没有检查行。这使得EXPLAIN的值与运行EXPLAIN ANALYZE相比相当有限,EXPLAIN ANALYZE实际运行查询并向您显示估计值和实际数字

为什么操作的宽度是321

显然,这是
mytable
中元组的大小(以字节为单位)

12.04..1632.35和0.00..11.93告诉我的成本是多少

第一个数字是从该节点返回第一行的成本;第二个数字是返回该节点所有行的成本。记住,这些都是估计。该单位为抽象成本单位。绝对数没有任何意义;规划中最重要的是哪个计划的成本最低。如果使用光标,第一个数字很重要;否则它通常是第二个数字。(我认为这是对限制条款的补充。)


通常需要调整可配置的成本因素,例如
随机页面成本
cpu元组成本
,以便在您的环境中准确地建模成本。如果没有这样的调整,比较成本可能与相应的运行时间不匹配,因此可能会选择一个不太理想的计划。

内部操作的总成本将始终包含在外部操作的启动成本中。@vyegorov是对的,需要注意的是,对于EXPLAIN ANALYZE中的实际数据,您应该理解节点花费的总时间除以循环以显示每次迭代的时间。正如您所期望的,它是包含在封闭节点中的节点的总时间。