繁体   English   中英

Postgresql - 附加新分区时 CHECK 约束不阻止 ACCESS EXCLUSIVE 锁和表扫描

[英]Postgresql - CHECK constraint not preventing ACCESS EXCLUSIVE lock and table scan when attaching new partition

我正在运行 postgresql 13。

postgres doc文档的以下部分说我应该能够避免扫描和 ACCESS EXCLUSIVE 锁来验证分区约束。

在运行 ATTACH PARTITION 命令之前,建议在要附加的表上创建一个 CHECK 约束,该约束与预期的分区约束相匹配,如上所示。 这样,系统将能够跳过验证隐式分区约束所需的扫描。 如果没有 CHECK 约束,将扫描表以验证分区约束,同时对该分区持有 ACCESS EXCLUSIVE 锁。

但是,当我创建一个带有检查约束的新分区,将数据插入其中,然后附加它时,在扫描表时会持有一个 ACCESS EXCLUSIVE 锁。

分区表:

CREATE TABLE IF NOT EXISTS tasks
(
    task_time timestamp(6) with time zone not null,
    task_sp_time timestamp(6) with time zone,
    task_org_id text not null,
    build_id text,
    unit_id  text,
    unit_req numeric(12,2),
    ... 30 columns truncated ...,
    constraint tasks_pkey1
        primary key (task_org_id, task_time)
)
partition by RANGE(task_time);

task_time not null并且类型为timestamp (6) with timezone

-- create new empty partition table
CREATE TABLE tasks_partitions.tasks_20230111
(LIKE tasks INCLUDING DEFAULTS INCLUDING CONSTRAINTS);

-- add CHECK constraint on new partition 
ALTER TABLE tasks_partitions.tasks_20230111 ADD CONSTRAINT tmp_20230111
CHECK (task_time >= '2023-01-11 00:00:00+00' AND task_time <= '2023-01-11 23:59:59.999999+00');

-- select around 100 million rows into the new partition from an old default partition that has been detached.
INSERT INTO tasks_partitions.tasks_20230111
SELECT * FROM tasks_partitions.tasks_default_old where (task_time >= '2023-01-11 00:00:00+00' AND task_time <= '2023-01-11 23:59:59.999999+00');

-- attach partition
ALTER TABLE tasks ATTACH PARTITION tasks_partitions_tasks_20230111
FOR VALUES FROM ('2023-01-11 00:00:00+00') TO ('2023-01-11 23:59:59.999999+00')

附加分区仍然持有ACCESS EXLUSIVE锁,并且扫描整个表。

tasks表曾经有一个默认分区,但我将其分离并重命名以解决另一个问题。 我目前没有附加到tasks的默认分区。

当我附加上例中的分区时,我看到新分区上有一个ACCESS EXCLUSIVE锁和一个看似随机的关系468140 在附加分区并且锁定到位时,我无法将任何记录插入到tasks表中。

如果有帮助,我运行以查看锁的查询是:

SELECT a.datname,
       l.relation::regclass,
       l.transactionid,
       l.mode,
       l.GRANTED,
       l.usename,
       a.query,
       a.query_start,
       age(now(), a.query_start) AS "age",
       a.pid
FROM pg_stat_activity a
JOIN pg_locks l ON l.pid = a.pid
ORDER BY a.query_start;

您正在创建的检查约束与分区边界不匹配。 您错过了文档中的此声明:

创建范围分区时, FROM指定的下限是包含边界,而TO指定的上限是排他边界。

所以你应该将约束定义为

ALTER TABLE tasks_partitions.tasks_20230111 ADD
CHECK (task_time >= '2023-01-11 00:00:00+00' AND
       task_time <  '2023-01-12 00:00:00+00');

并附加分区

ALTER TABLE tasks ATTACH PARTITION tasks_partitions_tasks_20230111
FOR VALUES FROM ('2023-01-11 00:00:00+00')
             TO ('2023-01-12 00:00:00+00');

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM