【发布时间】:2023-02-22 15:24:24
【问题描述】:
我有一张表 T1(未分区)。 T1 的大小约为 4TB。我创建了另一个表 T2(分区表)。现在我想将 T1 附加为 T2 的子表。所以我在查询下面运行以实现相同的目的。
ALTER TABLE T1
ADD CONSTRAINT partition_check_skip
CHECK ( "created_at" BETWEEN ( '-infinity' )
AND ( DATE_TRUNC('week', CURRENT_DATE::timestamp) + '7 days'::interval )) NOT VALID;
ALTER TABLE public.T2
ATTACH PARTITION T1 FOR VALUES FROM
('-infinity') TO (DATE_TRUNC('week', CURRENT_DATE::timestamp) + '7 days'::interval);
即使我提到了NOT VALID,Postgres 仍然花费太长时间将 T1 附加为 T2 的分区。
T1 架构
CREATE TABLE T1
(
uuid uuid DEFAULT gen_random_uuid() NOT NULL,
created_at timestamp WITHOUT TIME ZONE NOT NULL,
updated_at timestamp WITHOUT TIME ZONE NOT NULL
);
T2 架构
CREATE TABLE T2
(
uuid uuid DEFAULT gen_random_uuid() NOT NULL,
created_at timestamp WITHOUT TIME ZONE NOT NULL,
updated_at timestamp WITHOUT TIME ZONE NOT NULL
) PARTITION BY RANGE (created_at);
尝试添加NOT VALID,但仍然花费太长时间。
以下是实际的 SQL 语句:
非分区表
CREATE TABLE public.random_txn_old (
id int8 NOT NULL DEFAULT id_generator(),
ref_id text NULL,
txn_ref_id text NULL,
msg_id text NULL,
api text NULL,
request_payload jsonb NULL,
response_payload jsonb NULL,
biller_request jsonb NULL,
biller_response jsonb NULL,
status text NULL,
created_at timestamp NOT NULL DEFAULT current_timestamp_utc(),
modified_at timestamp NOT NULL DEFAULT current_timestamp_utc(),
is_deleted bool NULL DEFAULT false,
CONSTRAINT t2_check CHECK (((created_at >= '2021-02-23 00:00:00') AND (created_at <= '2023-02-24 00:00:00'))),
CONSTRAINT transaction_old_pkey PRIMARY KEY (id, created_at)
);
CREATE INDEX transaction_ref_id ON public.random_txn_old (ref_id);
CREATE INDEX txn_ref_api_idx ON public.random_txn_old (txn_ref_id, api);
表触发器:
create trigger set_timestamp_txn before
update
on
public.random_txn_old for each row execute function trigger_set_timestamp_modify();
分区表:
CREATE TABLE public.random_table (
id int8 NOT NULL DEFAULT id_generator(),
ref_id text NULL,
txn_ref_id text NULL,
msg_id text NULL,
api text NULL,
request_payload jsonb NULL,
response_payload jsonb NULL,
biller_request jsonb NULL,
biller_response jsonb NULL,
status text NULL,
created_at timestamp NOT NULL DEFAULT current_timestamp_utc(),
modified_at timestamp NOT NULL DEFAULT current_timestamp_utc(),
is_deleted bool NULL DEFAULT false,
CONSTRAINT transaction_part_pkey PRIMARY KEY (id, created_at)
)
PARTITION BY RANGE (created_at);
CREATE INDEX transaction_part_ref_id ON ONLY public.random_table (ref_id);
CREATE INDEX txn_part_ref_api_idx ON ONLY public.random_table (txn_ref_id, api);
我想做什么?
尝试使用此查询将 random_txn_old 附加到 random_table:
ALTER TABLE random_table
ATTACH PARTITION random_txn_old FOR VALUES FROM ('2021-02-23 00:00:00.000')
TO ('2023-02-24 00:00:00.000');
【问题讨论】:
-
您必须先验证约束。此外,预期分区是否具有所有必需的索引?您确定
created_at是NOT NULL了吗? -
我想跳过冗长的验证检查,这就是我指定
NOT VALID的原因。是的,created_at是NOT NULL。我没有添加 T1 中存在的所有索引。目前 T1 和 T2 只有索引t_index(uuid, created_at)。 -
为了避免在将分区附加到父表时进行验证检查,您需要一个有效的检查约束。 NOT VALID 不是你想要的,让它有效。
-
但是添加有效支票需要一些时间,对吧?为此,我们必须在生产数据库中执行此操作时停机。还要查看此文档 postgresql.org/docs/13/sql-altertable.html 提到 NOT VALID 可以跳过冗长的扫描
-
“为此,我们必须在生产数据库中执行此操作时停机”为什么?验证约束不会对表进行强锁定。这就是执行两步过程的重点。