当前位置: 首页 > 面试题库 >

分区表查询仍在扫描所有分区

濮丁雷
2023-03-14
问题内容

我的桌子上有十亿多条记录。为了提高性能,我将其划分为30个分区。最频繁的查询包含(id = ...)在where子句中,因此我决定在表上对表进行分区id

基本上,分区是通过以下方式创建的:

CREATE TABLE foo_0 (CHECK (id % 30 = 0)) INHERITS (foo);
CREATE TABLE foo_1 (CHECK (id % 30 = 1)) INHERITS (foo);
CREATE TABLE foo_2 (CHECK (id % 30 = 2)) INHERITS (foo);
CREATE TABLE foo_3 (CHECK (id % 30 = 3)) INHERITS (foo);
.
.
.

我运行ANALYZE了整个数据库,尤其是id通过运行以下命令使它为该表的列收集了额外的统计信息:

ALTER TABLE foo ALTER COLUMN id SET STATISTICS 10000;

但是,当我运行对id列进行筛选的查询时,计划程序会显示它仍在扫描所有分区。constraint_exclusion设置为partition,所以这不是问题。

EXPLAIN ANALYZE SELECT * FROM foo WHERE (id = 2);


                                               QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.00..8106617.40 rows=3620981 width=54) (actual time=30.544..215.540 rows=171477 loops=1)
   ->  Append  (cost=0.00..8106617.40 rows=3620981 width=54) (actual time=30.539..106.446 rows=171477 loops=1)
         ->  Seq Scan on foo  (cost=0.00..0.00 rows=1 width=203) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: (id = 2)
         ->  Bitmap Heap Scan on foo_0 foo  (cost=3293.44..281055.75 rows=122479 width=52) (actual time=0.020..0.020 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_0_idx_1  (cost=0.00..3262.82 rows=122479 width=0) (actual time=0.018..0.018 rows=0 loops=1)
                     Index Cond: (id = 2)
         ->  Bitmap Heap Scan on foo_1 foo  (cost=3312.59..274769.09 rows=122968 width=56) (actual time=0.012..0.012 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_1_idx_1  (cost=0.00..3281.85 rows=122968 width=0) (actual time=0.010..0.010 rows=0 loops=1)
                     Index Cond: (id = 2)
         ->  Bitmap Heap Scan on foo_2 foo  (cost=3280.30..272541.10 rows=121903 width=56) (actual time=30.504..77.033 rows=171477 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_2_idx_1  (cost=0.00..3249.82 rows=121903 width=0) (actual time=29.825..29.825 rows=171477 loops=1)
                     Index Cond: (id = 2)
.
.
.

我怎样做才能使刨床有更好的计划?我是否还需要ALTER TABLE foo ALTER COLUMN id SET STATISTICS 10000;为所有分区运行?

编辑

在使用Erwin建议的查询更改后,计划程序仅扫描正确的分区,但是执行时间实际上比完整扫描(至少对索引)要差。

EXPLAIN ANALYZE select * from foo where (id % 30 = 2) and (id = 2);
                                                                         QUERY PLAN
                                                                             QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.00..8106617.40 rows=3620981 width=54) (actual time=32.611..224.934 rows=171477 loops=1)
   ->  Append  (cost=0.00..8106617.40 rows=3620981 width=54) (actual time=32.606..116.565 rows=171477 loops=1)
         ->  Seq Scan on foo  (cost=0.00..0.00 rows=1 width=203) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: (id = 2)
         ->  Bitmap Heap Scan on foo_0 foo  (cost=3293.44..281055.75 rows=122479 width=52) (actual time=0.046..0.046 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_0_idx_1  (cost=0.00..3262.82 rows=122479 width=0) (actual time=0.044..0.044 rows=0 loops=1)
                     Index Cond: (id = 2)
         ->  Bitmap Heap Scan on foo_1 foo  (cost=3312.59..274769.09 rows=122968 width=56) (actual time=0.021..0.021 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_1_idx_1  (cost=0.00..3281.85 rows=122968 width=0) (actual time=0.020..0.020 rows=0 loops=1)
                     Index Cond: (id = 2)
         ->  Bitmap Heap Scan on foo_2 foo  (cost=3280.30..272541.10 rows=121903 width=56) (actual time=32.536..86.730 rows=171477 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_2_idx_1  (cost=0.00..3249.82 rows=121903 width=0) (actual time=31.842..31.842 rows=171477 loops=1)
                     Index Cond: (id = 2)
         ->  Bitmap Heap Scan on foo_3 foo  (cost=3475.87..285574.05 rows=129032 width=52) (actual time=0.035..0.035 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_3_idx_1  (cost=0.00..3443.61 rows=129032 width=0) (actual time=0.031..0.031 rows=0 loops=1)
.
.
.
         ->  Bitmap Heap Scan on foo_29 foo  (cost=3401.84..276569.90 rows=126245 width=56) (actual time=0.019..0.019 rows=0 loops=1)
               Recheck Cond: (id = 2)
               ->  Bitmap Index Scan on foo_29_idx_1  (cost=0.00..3370.28 rows=126245 width=0) (actual time=0.018..0.018 rows=0 loops=1)
                     Index Cond: (id = 2)
 Total runtime: 238.790 ms

相对:

EXPLAIN ANALYZE select * from foo where (id % 30 = 2) and (id = 2);
                                                                            QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.00..273120.30 rows=611 width=56) (actual time=31.519..257.051 rows=171477 loops=1)
   ->  Append  (cost=0.00..273120.30 rows=611 width=56) (actual time=31.516..153.356 rows=171477 loops=1)
         ->  Seq Scan on foo  (cost=0.00..0.00 rows=1 width=203) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: ((id = 2) AND ((id % 30) = 2))
         ->  Bitmap Heap Scan on foo_2 foo  (cost=3249.97..273120.30 rows=610 width=56) (actual time=31.512..124.177 rows=171477 loops=1)
               Recheck Cond: (id = 2)
               Filter: ((id % 30) = 2)
               ->  Bitmap Index Scan on foo_2_idx_1  (cost=0.00..3249.82 rows=121903 width=0) (actual time=30.816..30.816 rows=171477 loops=1)
                     Index Cond: (id = 2)
 Total runtime: 270.384 ms

问题答案:

对于非平凡的表达式,您必须在查询中重复或多或少的逐字条件,以使Postgres查询计划程序了解其可以依赖CHECK约束。即使显得多余!

每个文档:

启用约束排除后,计划人员将检查每个分区的约束,并尝试证明不需要扫描该分区,因为该分区不能包含满足查询WHERE子句的任何行。
当计划者可以证明这一点时 ,它将从查询计划中排除该分区。

大胆强调我的。计划者不理解复杂的表达式。当然,这也必须满足:

确保未在中禁用constraint_exclusion配置参数postgresql.conf。如果是这样,查询将不会根据需要进行优化。

代替

~~SELECT * FROM foo WHERE (id = 2);~~

尝试:

SELECT * FROM foo WHERE **id % 30 = 2 AND** id = 2;

和:

默认(和推荐)的Constraint_exclusion设置实际上既不是on也不是off,而是称为的中间设置
partition,这导致该技术仅应用于可能在分区表上运行的查询。on设置使计划人员可以检查CHECK所有查询中的约束,即使是那些不太可能受益的简单查询。

您可以尝试使用constraint_exclusion = on来查看计划者是否在没有多余逐字记录条件的情况下继续前进。但是您必须权衡此设置的成本和收益。

替代方法是使用@harmic概述的更简单的分区条件。

不,STATISTICS在这种情况下增加数量将无济于事。仅CHECK约束条件和您WHERE在查询中的条件很重要。



 类似资料:
  • DynamoDb文档中指定的查询操作: 查询操作仅搜索主键属性值,并支持对键属性值的比较运算符子集以优化搜索过程。 和扫描操作: 扫描操作扫描整个表。您可以指定要应用于结果的过滤器,以在完成扫描后优化返回给您的值。 这是基于性能和成本考虑的最佳选择。

  • 我有两个查询,其中一个涉及查询中的分区表,而另一个查询是相同的,只是涉及未分区的等效表。原始(非分区表)查询的性能优于分区的计数器。我不知道如何孤立这个问题。查看执行计划,我发现使用的索引与两个查询的B/W相同,新查询在其执行计划中显示了分区范围子句,这意味着正在进行分区剪枝。查询的形式如下:- 其中partTabA是分区表,partTabA.column1是分区键(范围分区)。在原始查询中,它将

  • 我有一个DynamoDB表,如下所示: 是表的简单主键 是一个属性,它对表中的所有项目都具有相同的值 桌子变得很大了。我希望能够根据日期时间按范围过滤数据。我脑海中有两个快速实施的选项,但我不确定这是否会在成本方面产生很大的影响。 扫描整个表,然后按日期时间过滤(因为dynamodb不允许在扫描之前过滤) 所以,我的问题是,由于我的分区键对每个项目都是相同的,因此是一个大分区,我不确定当使用过滤器

  • 我正在DynamoDB中设计一个表,它将包含大量记录,每个记录都有一个唯一的ID和一个时间戳。我需要检索一组位于两个日期之间的记录,而不管所有其他属性值如何。 为时间戳字段添加全局辅助索引似乎是一个合乎逻辑的解决方案,但这并不简单。 DynamoDB中的Query命令需要一个KeyConditionExpression参数,该参数确定查询返回的结果。从DynamoDB开发人员指南: 要指定搜索条件

  • 但是我得到了这个错误: sparkException:由于阶段失败而中止作业:阶段0.0中的任务236失败4次,最近的失败:阶段0.0中丢失任务236.3(TID 287,server,executor 17):org.apache.hadoop.security.AccessControlException:权限被拒绝:user=user,access=read,inode=“/path-to-