我想更好地理解Postgres查询执行器将条件推入连接组件的情况。我将特别感谢对此负责的源代码部分的引用。
假设您有一个视图,其中的主体是日期字段上两个表之间的连接,如下所示(这是一个简单的虚构示例,没有真实的解释):
create table measures (mdate date, measurement numeric);
create index measures_mdate on measures(mdate);
create view name_matches_surname as
select m1.*, m2.measurement as the_other_measurement
from measures m1 left join measures m2 on (m1.mdate = m2.mdate);
insert into measures values ('2021-05-11',1.0), ('2021-05-11',2.0);如果我在此视图中选择日期字段中的相等条件,则该条件将向下推到联接的两边,如下所示:
explain select * from name_matches_surname where mdate='now'::date;| QUERY PLAN |
| --------------------------------------------------------------------------------------- |
| Nested Loop Left Join (cost=8.40..27.89 rows=36 width=68) |
| Join Filter: (m1.mdate = m2.mdate) |
| -> Bitmap Heap Scan on measures m1 (cost=4.20..13.67 rows=6 width=36) |
| Recheck Cond: (mdate = '2021-05-12'::date) |
| -> Bitmap Index Scan on measures_mdate (cost=0.00..4.20 rows=6 width=0) |
| Index Cond: (mdate = '2021-05-12'::date) |
| -> Materialize (cost=4.20..13.70 rows=6 width=36) |
| -> Bitmap Heap Scan on measures m2 (cost=4.20..13.67 rows=6 width=36) |
| Recheck Cond: (mdate = '2021-05-12'::date) |
| -> Bitmap Index Scan on measures_mdate (cost=0.00..4.20 rows=6 width=0) |
| Index Cond: (mdate = '2021-05-12'::date) |如您所见,连接的两边都是索引扫描,使用条件(='now')访问索引。到目前一切尚好。让我们尝试范围条件(介于),而不是:
explain select * from name_matches_surname
where mdate between 'now'::date-5 and 'now'::date;| QUERY PLAN |
| ------------------------------------------------------------------------------------------------- |
| Hash Right Join (cost=13.77..41.61 rows=38 width=68) |
| Hash Cond: (m2.mdate = m1.mdate) |
| -> Seq Scan on measures m2 (cost=0.00..22.70 rows=1270 width=36) |
| -> Hash (cost=13.70..13.70 rows=6 width=36) |
| -> Bitmap Heap Scan on measures m1 (cost=4.21..13.70 rows=6 width=36) |
| Recheck Cond: ((mdate >= '2021-05-07'::date) AND (mdate <= '2021-05-12'::date)) |
| -> Bitmap Index Scan on measures_mdate (cost=0.00..4.21 rows=6 width=0) |
| Index Cond: ((mdate >= '2021-05-07'::date) AND (mdate <= '2021-05-12'::date)) |正如您所看到的,中间被推倒到连接的左侧,而对于右侧,我们进行了Seq扫描。您可以很容易地验证连接类型(内或左)或表的大小对下推结果没有影响-条件不会向下推到连接的右侧。
据我所见,这种行为在Postgres 9.5和13之间的所有版本中都是一致的。
原因是什么?是否有可能以一种不同的方式重写视图,以便“同样好”地推倒视图之间的关系,比如()?是否有对文档或源代码的引用,以深入解释下推策略?
发布于 2021-05-12 16:33:06
使用=,优化器可以推断,如果m1.mdate = m2.mdate和m1.mdate = 'constant',则对于m2.mdate也必须保持相同的条件。对于不等式运算符则不存在这样的推论。
https://dba.stackexchange.com/questions/291421
复制相似问题