我有一张有一堆列的桌子。其中facility_id
和po_date
。我正在编写一个复杂的查询,并且我在这两列上有一个索引。您可以从下面的计划器输出中看到 Postgres 在加入我的facility
表时使用该索引作为索引条件。
我的问题实际上是关于Filter:
下面一行中列举的列的存在。exclude
, verified
, 并且deleted
不在顶部引用的索引中,那么 Postgres 是如何实际获取这些列中的数据的呢?我本来希望明确引用全表扫描,但是在任何地方都看不到。全表扫描可以悄悄地隐藏在一个中Filter
吗?
该表大小为 50M 行,我使用的是 Postgres 10。此外,这部分查询位于 CTE 中。
-> Index Scan using clustered_table_facility_id_po_date_idx on clustered_table cp (cost=0.56..1401.08 rows=31929 width=37) (actual time=0.021..5.331 rows=9572 loops=3640)
Index Cond: (facility_id = af.id)
Filter: ((NOT exclude) AND (verified IS NULL) AND (deleted IS NULL))
Rows Removed by Filter: 2819
当你有一个可用的索引时,为什么要进行全表扫描?
优化器收集所有条件,考虑可用索引(和其他方式)并选择“最佳”计划。在您的情况下,该计划是:
af.id
(facility_id = af.id)
- 这是可能的,因为索引不是独立结构,它基于其表,并且索引中的每个项目都包含指向表的实际行的指针Filter
部分)Index Scan
表示该索引用于定位相关行,但并不意味着该表不会被触及,只是不会被完全扫描。有一种可能性
Index Only Scan
- 当索引包含所有相关列(不仅是 ON/WHERE 中的列,还有选定的列和用于排序的列,查询需要从表中获取的所有列)。在这种情况下,可能不需要实际从表中获取整行 - 但无论如何都会获取一些行,因为事务可见性在所有行的索引级别上不可用,仅适用于整个块(有点复杂的问题)。