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

时间:2013-12-23 06:17:28

标签: sql performance postgresql indexing postgresql-performance

我有一张大桌子:

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

所有请求的90%是关于person_id过去2-3天的订单,例如:

select * from orders
where person_id = 1
and created >= extract(epoch from current_timestamp)::int - 60 * 60 * 24 * 3;

如何改善表现?

我知道Partitioning,但现有行怎么样?看起来我需要每2-3天手动创建INHERITS个表。

2 个答案:

答案 0 :(得分:3)

我建议在(person_id, created) IMMUTABLE上使用伪CREATE OR REPLACE FUNCTION f_orders_idx_start() RETURNS integer AS 'SELECT 1387497600' LANGUAGE sql IMMUTABLE COST 1; 条件,需要不时重新创建以保持效果。

注意,如果你的表不是很大,你可以在很大程度上简化和使用普通的多列索引。

原始函数提供一个恒定的时间点,3天或更长时间(在您的情况下由unix时期表示):

1387497600

SELECT extract(epoch from now())::integer - 259200;IMMUTABLE的结果。

部分索引基于此伪CREATE INDEX orders_created_recent_idx ON orders (person_id, created) WHERE created >= f_orders_idx_start(); 条件:

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;
-- 259200 being the result of 60 * 60 * 24 * 3

查询基于相同的“常量”:

AND created >= f_orders_idx_start()

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; 似乎是多余的,但有助于说服Postgres使用部分索引。

功能,可以不时重新创建功能和索引。可能每晚都有一份cron-job:

SELECT f_orders_reindex_partial();  -- that's all

呼叫:

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

即使您从未调用此函数,所有查询仍可继续工作。随着部分指数的增长,业绩会逐渐恶化。

我正在成功使用这个政权,有几个大表和类似的要求。 非常快。

对于Postgres 9.2或更高版本,并且如果您的表只有很少的小列,并且如果表格没有大量编写,则可能需要支付partial multicolumn index

{{1}}

答案 1 :(得分:0)

建议: -

它可能对你有所帮助。 由于表大小不断增长,您的查询性能将逐渐降低。更好地维护3-5天(如果您非常确定只能访问2-3天)记录并定期将旧记录迁移到备份表。