sql - 约束排除不适用于分区表

标签 sql postgresql postgresql-9.2 database-partitioning

我有以下设置(简化摘录):

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 条件:

SELECT * FROM my_table
   WHERE TENANT_ID='anyVal'
     AND select_partition(TENANT_ID, 2) = select_partition('anyVal', 2);

此外,我认为您应该将h_intselect_partition 标记为IMMUTABLE。它们是(而且应该是),告诉数据库是个好主意。但这与您的问题无关。

关于sql - 约束排除不适用于分区表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49939412/

相关文章:

postgresql - 功能获取一年中正确的周数

database - initlocation 在 postgresql 中不起作用

sql - 在 PostgreSQL 中故意引发异常是一件好事吗?

c# - 在这种情况下更正 SQL 语法

sql - 检索包含列组合的所有表名

sql - 更新包含换行符 '\n' 的文本列

sql - 从多个表中选择,消除重复值

sql - 如何在 SQL Server 中连接字符串和逗号?

mysql - SQL 从案例列中排除零

java - Hibernate 在 session 期间不更新 ManyToMany 关联