【问题标题】:PostgreSQL Partitioning. Constraint Exclusion not kicking in on SELECTPostgreSQL 分区。约束排除未在 SELECT 上启动
【发布时间】:2013-11-04 00:25:55
【问题描述】:

我的分区表 SELECT 查询包括所有分区表,即使检查到位并且 constraint_exclusion = on。

插入触发器工作正常,新行插入到正确的表中。然而,无论我的 WHERE 子句如何,SELECT 都会运行所有表。

这是我的配置:

constraint_exclusion = on (both in postgresql.conf and also tried with "ALTER DATABASE bigtable SET constraint_exclusion=on;")

主表:

CREATE TABLE bigtable (
    id bigserial NOT NULL,
    userid integer NOT NULL,
    inserttime timestamp with time zone NOT NULL DEFAULT now()
)

子表 1:

CREATE TABLE bigtable_2013_11 (CHECK ( inserttime >= DATE '2013-11-01' AND inserttime < DATE '2013-12-01' )) INHERITS (bigtable);        

子表 2:

CREATE TABLE bigtable_2013_12 (CHECK ( inserttime >= DATE '2013-12-01' AND inserttime < DATE '2014-01-01' )) INHERITS (bigtable);    

存储过程:

CREATE OR REPLACE FUNCTION bigtable_insert_function()
RETURNS TRIGGER AS $$
BEGIN

    IF ( NEW.inserttime >= DATE '2013-11-01' AND NEW.inserttime < DATE '2013-11-01' ) THEN
        INSERT INTO bigtable_2013_11 VALUES (NEW.*);
    ELSEIF (NEW.inserttime >= DATE '2013-12-01' AND NEW.inserttime < DATE '2014-01-01' ) THEN
        INSERT INTO bigtable_2013_12 VALUES (NEW.*);
    ELSE
        RAISE EXCEPTION 'Bigtable insert date is out of range!';
    END IF;

    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

触发器:

CREATE TRIGGER bigtable_insert_trigger BEFORE INSERT ON bigtable FOR EACH ROW EXECUTE PROCEDURE bigtable_insert_function();

这几乎是教科书的设置。插入工作正常:

INSERT INTO bigtable (userid, inserttime) VALUES ('1', now());

以上插入会导致新行仅正确插入到“bigtable_2013_11”中。

但是我不能让 SELECT 排除不相关的表。所有 SELECT 总是在所有表上运行。我希望在使用以下 SELECT 查询时排除 bigtable_2013_12:

SELECT * FROM bigtable WHERE inserttime >= DATE '2013-11-01'::date AND inserttime < '2013-12-01'::date;

SELECT * FROM bigtable WHERE EXTRACT(MONTH FROM inserttime) = 11 AND EXTRACT (YEAR FROM inserttime) = 2013;

但是结果总是这样:

"Result  (cost=0.00..68.90 rows=17 width=20)"
"  ->  Append  (cost=0.00..68.90 rows=17 width=20)"
"        ->  Seq Scan on bigtable  (cost=0.00..0.00 rows=1 width=20)"
"              Filter: ((inserttime >= '2013-11-02'::date) AND (inserttime < '2013-11-30'::date))"
"        ->  Seq Scan on bigtable_2013_11 bigtable  (cost=0.00..34.45 rows=8 width=20)"
"              Filter: ((inserttime >= '2013-11-02'::date) AND (inserttime < '2013-11-30'::date))"
"        ->  Seq Scan on bigtable_2013_12 bigtable  (cost=0.00..34.45 rows=8 width=20)"
"              Filter: ((inserttime >= '2013-11-02'::date) AND (inserttime < '2013-11-30'::date))"

为什么我的支票没有生效?我没主意了。一切似乎都设置正确。我错过了什么吗?任何帮助将不胜感激。

【问题讨论】:

    标签: postgresql constraints partitioning


    【解决方案1】:

    这里有两件事。一是seq扫描。另一个是 union all(即 append 运算符)。据我所知,后者是完全不可避免的。这就是表继承的工作原理——或者我上次使用它时也是这样。 *然而*,这将我们带到前者,您可以在该日期字段上添加一个索引,以消除不需要的 seq 扫描并提前保释。


    或者,可能与日期/时间戳转换有关。

    【讨论】:

    • 丹尼斯!我认为你正在做某事。当我将列类型更改为 DATE 时,它工作正常。显然这里的日期/时间戳转换确实有问题。我将了解如何在支票中使用时间戳而不是日期。非常感谢!
    • 已确认。在检查和过程中使用 TIMESTAMP WITH TIME ZONE 而不是 DATE 可以解决问题。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 2012-09-05
    • 2019-06-15
    • 2013-12-16
    • 2016-06-11
    • 2020-10-23
    • 1970-01-01
    相关资源
    最近更新 更多