约束排除不适用于分区表
Posted
技术标签:
【中文标题】约束排除不适用于分区表【英文标题】:Constraint Exclusion not working on partitioned table 【发布时间】:2018-04-20 10:20:30 【问题描述】:我有以下设置(简化摘录):
CREATE TABLE my_table (
ID VARCHAR(255) NOT NULL,
TENANT_ID CHAR(36) NOT NULL,
PRIMARY KEY (id)
);
-- creates a int hash of a string (> 0)
CREATE OR REPLACE FUNCTION h_int(text) RETURNS int as $$
SELECT @('x'||substr(md5($1),1,8))::bit(32)::int;
$$ language sql;
-- uses a numeric hash value to select a partition
CREATE OR REPLACE FUNCTION select_partition(text, int) RETURNS int as $$
SELECT h_int($1) % $2;
$$ language sql;
CREATE TABLE IF NOT EXISTS part_my_table_00 (
CONSTRAINT pk_part_00 PRIMARY KEY (ID),
CONSTRAINT ck_part_00 CHECK (select_partition(TENANT_ID, 2) = 0)
) INHERITS (my_table);
CREATE INDEX idx_tenant_ids_00 ON my_table (TENANT_ID);
CREATE TABLE IF NOT EXISTS part_my_table_01 (
CONSTRAINT pk_part_01 PRIMARY KEY (ID),
CONSTRAINT ck_part_01 CHECK (select_partition(TENANT_ID, 2) = 1)
) INHERITS (my_table);
CREATE INDEX idx_tenant_ids_01 ON my_table (TENANT_ID);
CREATE OR REPLACE FUNCTION fn_insert() RETURNS TRIGGER AS $$
declare
selectedPartition int;
tableName text := 'part_my_table_0';
queryString text;
BEGIN
selectedPartition := select_partition(NEW.TENANT_ID, 2);
tableName := tableName||selectedPartition;
queryString := 'INSERT INTO '||tableName||' SELECT($1).*';
EXECUTE queryString USING NEW;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_insert BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE fn_insert();
SET constraint_exclusion = on;
现在插入效果很好。我的问题是约束排除似乎不适用于选择:
SELECT * FROM my_table WHERE TENANT_ID='anyVal';
解释此查询返回以下内容:
postgres=# EXPLAIN SELECT * FROM my_table WHERE TENANT_ID='anyVal';
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Append (cost=0.00..81.53 rows=11 width=6401)
-> Seq Scan on my_table (cost=0.00..0.00 rows=1 width=6401)
Filter: (tenant_id = 'bla'::bpchar)
-> Index Scan using idx_tenant_ids_00 on part_my_table_00 (cost=0.14..8.15 rows=1 width=6401)
Index Cond: (tenant_id = 'bla'::bpchar)
-> Index Scan using idx_tenant_ids_01 on part_my_table_01 (cost=0.14..8.15 rows=1 width=6401)
Index Cond: (tenant_id = 'bla'::bpchar)
我原以为只会扫描其中一个分区。有谁能帮帮我吗?
提前致谢!
【问题讨论】:
检查约束中的表达式与 where 子句中的表达式不匹配。 如何通过计算WHERE tenant_id=**
值的哈希来实现约束排除?
【参考方案1】:
您必须添加与分区约束匹配的WHERE
条件:
SELECT * FROM my_table
WHERE TENANT_ID='anyVal'
AND select_partition(TENANT_ID, 2) = select_partition('anyVal', 2);
此外,我认为您应该将h_int
和select_partition
标记为IMMUTABLE
。它们是(并且应该是),告诉数据库是个好主意。但这与您的问题无关。
【讨论】:
谢谢,解释清楚了!以上是关于约束排除不适用于分区表的主要内容,如果未能解决你的问题,请参考以下文章