我在Postgres中有一个查询,该查询连接了2个表,其中一个已分区。执行计划表明,即使我在查询中包括分区键,查询也会击中表的所有分区。
我终于意识到问题是我遇到的LEFT JOIN
。如果我将A LEFT JOIN B
替换为A, B
,则Postgres将仅针对1个分区而不是所有分区。
有人知道这是否是Postgres执行计划程序中的错误吗?
这里是简化的查询:
EXPLAIN SELECT in_memory_table.my_col
FROM (SELECT '2019-08-09 19:00:00+00:00') in_memory_table(my_col)
LEFT JOIN partitioned_table
ON (partitioned_table.id = '1111111111111111122222222222222'
AND partitioned_table.my_col = in_memory_table.my_col);
这产生了这个执行计划:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Nested Loop Left Join (cost=0.56..58.28 rows=1 width=8)
Join Filter: (partitioned_table_201908_partition.my_col = ('2019-08-09 19:00:00+00'::timestamp with time zone))
-> Result (cost=0.00..0.01 rows=1 width=8)
-> Append (cost=0.56..58.17 rows=7 width=8)
-> Index Scan using partitioned_table_201908_partition_pkey on partitioned_table_201908_partition (cost=0.56..8.58 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_201909_partition_pkey on partitioned_table_201909_partition (cost=0.15..8.17 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_201910_partition_pkey on partitioned_table_201910_partition (cost=0.15..8.17 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_201911_partition_pkey on partitioned_table_201911_partition (cost=0.15..8.17 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_201912_partition_pkey on partitioned_table_201912_partition (cost=0.15..8.17 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_202001_partition_pkey on partitioned_table_202001_partition (cost=0.15..8.17 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
-> Index Scan using partitioned_table_pkey on partitioned_table_000000_partition (cost=0.70..8.72 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
(18 rows)
如果我改为这样做:
EXPLAIN SELECT in_memory_table.my_col
FROM (SELECT '2019-08-09 19:00:00+00:00') in_memory_table(my_col),
partitioned_table
WHERE (partitioned_table.id = '1111111111111111122222222222222'
AND partitioned_table.my_col = in_memory_table.my_col);
然后执行计划看起来像我期望的样子:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Append (cost=0.56..8.59 rows=1 width=8)
-> Index Scan using partitioned_table_201908_partition_pkey on partitioned_table_201908_partition (cost=0.56..8.58 rows=1 width=8)
Index Cond: (id = '1111111111111111122222222222222'::uuid)
Filter: (result_timestamp = '2019-08-09 19:00:00+00'::timestamp with time zone)
为什么LEFT JOIN
版本会影响所有分区?
my_col
是分区键(按范围分区)LEFT JOIN
?这是一个简化的版本,真正的版本使用的是LEFT OUTER JOIN
,但是很难问到(我无法在其中将ON
转换为WHERE
)。