2013-12-23 31 views
1

我有一个大表:所有请求的优化性能上最近的大型表的行

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

90%是来自过去的2-3天的订单由person_id,如:

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

我该如何提高性能?

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

+2

你知道[索引](http://www.postgresql.org/docs/9.3/static/indexes-intro.html)? –

+0

是的,当然,我已经有索引(person_id,创建) – user2024300

+0

刚刚创建'创建'索引有什么错?我看不出分区如何对此有所帮助。这将成为一个低效率的指数。所以只需要首先创建索引。 – usr

回答

1

我建议在(person_id, created)一个partial multicolumn index用伪IMMUTABLE条件,这需要从不时被重建,以保持性能最高。

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

甲原始函数提供在时间恒定的点,3个或更多天回(由UNIX划时代你的情况表示):

CREATE OR REPLACE FUNCTION f_orders_idx_start() 
    RETURNS integer AS 
'SELECT 1387497600' 
    LANGUAGE sql IMMUTABLE COST 1; 

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

A 函数重新创建函数和索引不时。可能有一个cron作业每天晚上:

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的9.2或更高版本,如果你的表只有几个,小列,如果表没有被大量写的,它可能会有好一个covering index

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

谢谢!很有帮助 – user2024300

0

宝贵意见: -

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

+0

是的,谢谢。我考虑过这个选项,但它需要做很多修改,因为10%的请求必须进入备份表。 – user2024300

+0

我认为有一种比拆分表malualy更简单的方法,然后每2-5天维护它manualy或脚本。 – user2024300

+0

如果你不依赖于旧的记录,相当你可以有相同的结构备份表,并使用db_link轻松迁移数据。然后使其作为批处理进程迁移(自动化) – Pavunkumar