【发布时间】:2020-04-22 04:50:57
【问题描述】:
我正在 postgres 数据库上处理一个超过 1 TB 并且有大约 20 亿条记录的数据库表。因此,我决定根据“时间戳”列对表进行分区。
-- Step 1. 创建分区表
CREATE TABLE bigtable_y2019 (
CHECK (timestamp >= '2019-01-01' AND timestamp < '2020-01-01')
) INHERITS (bigtable);
CREATE TABLE bigtable_y2020 (
CHECK (timestamp >= '2020-01-01' AND timestamp < '2021-01-01')
) INHERITS (bigtable);
-- Step 2. 在键列上创建索引(时间戳)
CREATE UNIQUE INDEX bigtable_y2019_pkey ON bigtable_y2019 USING btree (id);
CREATE INDEX bigtable_y2019_timestamp ON bigtable_y2019 (timestamp);
CREATE UNIQUE INDEX bigtable_y2020_pkey ON bigtable_y2020 USING btree (id);
CREATE INDEX bigtable_y2020_timestamp ON bigtable_y2020 (timestamp);
-- Step 3. 创建函数
CREATE OR REPLACE FUNCTION bigtable_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.timestamp >= '2020-01-01' AND NEW.timestamp < '2021-01-01') THEN
INSERT INTO bigtable_y2020 VALUES (NEW.*);
ELSIF (NEW.timestamp >= '2019-01-01' AND NEW.timestamp < '2020-01-01') THEN
INSERT INTO bigtable_y2019 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the bigtable_insert_trigger() function!';
END IF;
-- My understanding was this should have prevented inserting data into master table
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
-- Step 4. Enable Trigger ON BEFORE INSERT EVENT 并执行函数
CREATE TRIGGER insert_bigtable_trigger BEFORE INSERT ON bigtable FOR EACH ROW EXECUTE FUNCTION bigtable_insert_trigger();
-- Step 5. 设置 enable_partition_pruning 和 constraint_exclusion 为 ON
SET enable_partition_pruning = ON;
SET constraint_exclusion = ON;
上述这些步骤不仅在子表上插入记录,而且在父表上也插入记录,这是我试图避免的。
因此,我尝试为 AFTER INSERT 事件创建另一个触发器以删除父表。这不是最好的方法,但我想看看它是如何工作的。
--因为,tripdetail_insert_trigger 中的 RETURN NULL 并不能避免插入主表,所以我创建了一个解决方法来从主表中删除该记录。
CREATE OR REPLACE FUNCTION bigtable_mastertable_record_delete_trigger()
RETURNS TRIGGER AS $$
BEGIN
DELETE FROM ONLY bigtable WHERE id = NEW.id;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER delete_bigtable_mastertable_record_trigger AFTER INSERT ON bigtable FOR EACH ROW EXECUTE FUNCTION bigtable_mastertable_record_delete_trigger();
父表和子表之间存在同步。如果记录被插入到子表中,那么在父表中也是如此,如果记录在其中任何一个中被删除,那么记录也会在另一个中被删除。
但是,我正在尝试根据时间戳将新记录插入到相应的子表中,并最终使父表为空,这应该基于表分区的工作原理。
【问题讨论】:
-
您使用的是哪个 Postgres 版本?如果你真的需要分区,你应该至少使用 11 个(最好是 12 个)并使用新的声明式分区。忘记基于继承的分区。使用 12 对基表的任何插入都将自动重定向到正确的分区
-
你原来的设置适合我。您做了什么来得出该行被插入到这两个地方的结论?我敢打赌你误解了一些东西。
-
@a_horse_with_no_name 我正在使用 postgres 11。目前还没有升级到 12 的计划,所以我正在尝试在版本 11 上进行这项工作。
-
@jjanes 我为 2020 年的一条记录执行了插入语句,我看到两个表中都存在相同的记录(它们具有相同的 id)。我很乐意清除更多内容。
-
Postgres 11 也会将该行路由到正确的分区。您绝对应该使用声明性分区,而不是(有些过时的)基于继承的分区。
标签: postgresql