为大表的最近行优化查询性能

问题描述 投票:3回答:2

我有一张大桌子:

CREATE TABLE "orders" (
"id" serial NOT NULL,
"person_id" int4,
"created" int4,
CONSTRAINT "orders_pkey" PRIMARY KEY ("id")
);

所有请求中的90%是关于[2-3]的最近2-3天的订单,例如:

person_id

我如何提高性能?

我知道select * from orders where person_id = 1 and created >= extract(epoch from current_timestamp)::int - 60 * 60 * 24 * 3; ,但是现有行呢?看来我需要每2-3天手动创建Partitioning表。

sql performance postgresql indexing postgresql-performance
2个回答
3
投票

具有伪INHERITS条件的partial, multicolumn index上的(person_id, created)将有帮助(很多)。需要不时地重新创建以保持性能。

注意,如果表不是很大,则可以在很大程度上简化并使用普通的多列索引。或考虑使用Postgres 12或更高版本中的IMMUTABLE(功能最终成熟)。

原始功能提供了一个固定的时间点,即3天或更多天后的时间(在您的情况下以unix纪元表示):

table partitioning

CREATE OR REPLACE FUNCTION f_orders_idx_start() RETURNS integer LANGUAGE sql IMMUTABLE COST 1 PARALLEL SAFE AS 'SELECT 1387497600'; 仅对于Postgres 10或更高版本。PARALLEL SAFE是以下结果:

1387497600

根据您的部分索引在此伪SELECT extract(epoch from now())::integer - 259200; -- 259200 being the result of 60 * 60 * 24 * 3 条件下:

IMMUTABLE

基于相同条件的query

CREATE INDEX orders_created_recent_idx ON orders (person_id, created)
WHERE created >= f_orders_idx_start();

[C0行似乎是多余的,但有助于说服Postgres使用部分索引。

A 重新创建函数和索引的函数。可能每天晚上都有cron-job:

SELECT *
FROM   orders
WHERE  person_id = 1
AND    created >= f_orders_idx_start()  -- match partial idx condition
AND    created >= extract(epoch from now())::integer - 259200;  -- actual condition

要重新建立索引,请调用(最好是很少或没有并发负载:]

AND created >= f_orders_idx_start()

即使您从未调用过此函数,所有查询也会继续起作用。随着部分索引的增加,性能会随着时间的推移而缓慢下降。

我正在成功地使用这种机制,并具有几个大型表和类似的要求。 非常快。

对于Postgres 9.2或更高版本,并且如果您的表只有很少的一小列,并且该表没有被大量写入,则可能需要将其设为CREATE OR REPLACE FUNCTION f_orders_reindex_partial() RETURNS void AS $func$ DECLARE -- 3 days back, starting at 00:00 _start int := extract(epoch from now()::date -3)::int; BEGIN IF _start = f_orders_idx_start() THEN -- do nothing, nothing changes. ELSE DROP INDEX IF EXISTS orders_created_recent_idx; -- Recreate IMMUTABLE function EXECUTE ' CREATE OR REPLACE FUNCTION f_orders_idx_start() RETURNS integer AS $$SELECT ' || _start || '$$ LANGUAGE sql IMMUTABLE COST 1'; -- Recreate partial index CREATE INDEX orders_created_recent_idx ON orders (person_id, created) WHERE created >= f_orders_idx_start(); END IF; END $func$ LANGUAGE plpgsql;

SELECT f_orders_reindex_partial();  -- that's all

在Postgres 11或更高版本中,您可能想改用covering index

CREATE INDEX orders_created_recent_idx ON orders (person_id, created, id)
WHERE created >= f_orders_idx_start();

0
投票

建议:-

可能会帮助您。由于表的大小在增加,因此查询性能将逐渐降低。最好保留3-5天的记录(如果您非常确定仅要访问2-3天,请确保>),并定期将旧记录迁移到备份表。

© www.soinside.com 2019 - 2024. All rights reserved.