简体   繁体   English

约束排除不适用于分区表

[英]Constraint Exclusion not working on partitioned table

I have following setup (simplified excerpt): 我有以下设置(简化摘录):

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;

Now inserts do work well. 现在插入效果很好。 My issue is that constraint exclusion does not seem to work for selects: 我的问题是约束排除似乎不适用于选择:

SELECT * FROM my_table WHERE TENANT_ID='anyVal';

Explaining this query returns following: 解释此查询将返回以下内容:

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)

I would have expected that only one of the partitions would have been scanned. 我曾希望只有一个分区会被扫描。 Anybody able to help me? 有人可以帮助我吗?

Thanks in advance! 提前致谢!

You have to add a WHERE condition that matches the partitioning constraint: 您必须添加与分区约束匹配的WHERE条件:

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

Moreover, I think that you should mark h_int and select_partition as IMMUTABLE . 此外,我认为您应该将h_intselect_partition标记为IMMUTABLE They are (and should be), and it is a good idea to tell the database. 它们是(并且应该是),并且告诉数据库是一个好主意。 But that is unrelated to your problem. 但这与您的问题无关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM