继承表和索引的性能问题

umu*_*mut 7 postgresql performance index partitioning inheritance postgresql-performance

我有一个带有主表和 2 个子表的 PostgreSQL 数据库。我的主表:

CREATE TABLE test (
    id serial PRIMARY KEY, 
    date timestamp without time zone
);
CREATE INDEX ON test(date);
Run Code Online (Sandbox Code Playgroud)

我的子表:

CREATE TABLE test_20150812 (
    CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )
) INHERITS (test);

CREATE TABLE test_20150811 (
    CHECK ( date >= DATE '2015-08-11' AND date < DATE '2015-08-12' )
) INHERITS (test);

CREATE INDEX ON test_20150812(date);
CREATE INDEX ON test_20150811(date);
Run Code Online (Sandbox Code Playgroud)

当我执行查询时:

select * from test_20150812 where date > '2015-08-12' order by date desc;
Run Code Online (Sandbox Code Playgroud)

它返回得非常快(20-30 毫秒)。EXPLAIN输出:

 Limit  (cost=0.00..2.69 rows=50 width=212)
   ->  Index Scan Backward using test_20150812_date_idx on test_20150812  (cost=0.00..149538.92 rows=2782286 width=212)
         Index Cond: (date > '2015-08-12 00:00:00'::timestamp without time zone)
Run Code Online (Sandbox Code Playgroud)

但是,如果我执行如下查询:

select * from test where date > '2015-08-12' order by date desc;
Run Code Online (Sandbox Code Playgroud)

这需要很长时间(10-15 秒)。EXPLAIN输出:

 Limit  (cost=196687.06..196687.19 rows=50 width=212)
   ->  Sort  (cost=196687.06..203617.51 rows=2772180 width=212)
         Sort Key: public.test.date
         ->  Result  (cost=0.00..104597.24 rows=2772180 width=212)
               ->  Append  (cost=0.00..104597.24 rows=2772180 width=212)
                     ->  Seq Scan on test  (cost=0.00..0.00 rows=1 width=1857)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)
                     ->  Seq Scan on test_20150812 test  (cost=0.00..104597.24 rows=2772179 width=212)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)
Run Code Online (Sandbox Code Playgroud)

constraint_exclusion设置为ON在我的postgresql.conf. 因此它应该只在test_20150812.

我看到,如果在主表上执行查询,则永远不会使用索引。我该如何改进?我想在我的主表上进行所有查询。查询特定日期时,我希望在主表或子表上查询之间没有性能差异。

Erw*_*ter 12

“日期”

不要将您的timestamp专栏称为“日期”,这是非常具有误导性的。更好的是,根本不要使用基本类型名称“date”作为标识符,这很容易出错,导致错误消息混淆,并且它是标准 SQL 中保留字。应该是这样的:

CREATE TABLE test (
  id serial PRIMARY KEY
, ts timestamp NOT NULL  -- also adding NOT NULL constraint
);
CREATE INDEX ON test(ts);
Run Code Online (Sandbox Code Playgroud)

注意事项

请注意约束排除这个警告

约束排除仅在查询的WHERE子句包含 常量(或外部提供的参数)时有效。例如,CURRENT_TIMESTAMP 无法优化与非不可变函数的比较,因为规划器无法知道函数值在运行时可能属于哪个分区。

大胆的epmhasis我的。你躲过了这个,但由于你的混乱设置,你可能很快就会被它绊倒。

另外,由于您有每日分区:

在约束排除期间检查主表所有分区上的所有约束,因此大量分区可能会显着增加查询计划时间。使用这些技术进行分区可以很好地处理多达一百个分区;不要尝试使用成千上万个分区。

大胆强调我的。如果您跨越几个月以上,请尝试每周或每月分区。

谓词不匹配

您的检查条件:

CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )
Run Code Online (Sandbox Code Playgroud)

但是您的查询具有以下条件:

where date > '2015-08-12' order by date desc;  -- should be: >=
Run Code Online (Sandbox Code Playgroud)

这会留下轻微的不匹配(可能不正确!)并强制 Postgres 重新检查条件。不好,但也不能回答你的问题。

使用>=, 并创建列NOT NULL或附加NULLS LAST到语句:

WHERE ts >= '2015-08-12' ORDER BY ts DESC;
Run Code Online (Sandbox Code Playgroud)

...并使索引匹配。

不洁CHECK约束

CHECK限制被保存date常量,而不是timestamp常量。应该是这样的:

CHECK (ts >= timestamp '2015-08-11' AND ts < timestamp '2015-08-12');
Run Code Online (Sandbox Code Playgroud)

约束排除

你写:

constraint_exclusion设置为ON在我的postgresql.conf. 因此它应该只在test_20150812.

正如您在查询计划中看到的,只有testtest_20150812被扫描,而不是test_20150811。Ergo:约束排除工作正常,尽管所有偏差。那只是另一个错误的轨道。

赢得了许多战斗,但没有赢得战争

清理完所有这些之后,我看到了子表的位图索引扫描,而不是您的 seq 扫描。仍然比仅在子表上查询慢。这显然是因为父表本身也可以有匹配的行,这些行必须与其余行一起排序,因此不能仅从索引中读取结果。