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
.
正如您在查询计划中看到的,只有test
和test_20150812
被扫描,而不是test_20150811
。Ergo:约束排除工作正常,尽管您有所有偏差。那只是另一个错误的轨道。
清理完所有这些之后,我看到了子表的位图索引扫描,而不是您的 seq 扫描。仍然比仅在子表上查询慢。这显然是因为父表本身也可以有匹配的行,这些行必须与其余行一起排序,因此不能仅从索引中读取结果。