簡體   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