为什么PostgresQL查询性能会随着时间的推移而下降,但在重建索引时会恢复

时间:2010-03-06 15:30:52

标签: performance postgresql indexing sql-tuning

根据手册中的page indexes don't need to be maintained。但是,我们运行的PostgresQL表的连续速率为updatesdeletesinserts,随着时间的推移(几天)会出现严重的查询质量下降。如果我们删除并重新创建索引,则会恢复查询性能。

我们正在使用开箱即用的设置 我们测试中的表目前是空的,并且增长到50万行。 它有一个相当大的行(很多文本字段)。

我们是searching based of an index, not the primary key(我已经确认该指数正在使用,至少在正常条件下)

该表用作单个进程的持久存储。 在Windows上使用PostgresQL和Java客户端。

我愿意放弃insert and update performance以保持查询效果。

我们正在考虑重新架构应用程序,以便数据分布在各种动态表中,使我们能够定期删除和重建索引而不会影响应用程序。然而,和往常一样,有一个时间紧迫让这个工作,我怀疑我们缺少一些基本的配置或使用。

我们考虑了forcing vacuumingrebuild to run at certain times,但我怀疑是locking period for such an action would cause our query to block。这可能是一个选项,但有一些实时(3-5秒的窗口)含义需要我们的代码中的其他更改。

其他信息: 表和索引

CREATE TABLE icl_contacts
(
  id bigint NOT NULL,
  campaignfqname character varying(255) NOT NULL,
  currentstate character(16) NOT NULL,
  xmlscheduledtime character(23) NOT NULL,
...
25 or so other fields.  Most of them fixed or varying character fiel  
...
  CONSTRAINT icl_contacts_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
ALTER TABLE icl_contacts OWNER TO postgres;

CREATE INDEX icl_contacts_idx
  ON icl_contacts
  USING btree
  (xmlscheduledtime, currentstate, campaignfqname);

分析:

Limit  (cost=0.00..3792.10 rows=750 width=32) (actual time=48.922..59.601 rows=750 loops=1)
  ->  Index Scan using icl_contacts_idx on icl_contacts  (cost=0.00..934580.47 rows=184841 width=32) (actual time=48.909..55.961 rows=750 loops=1)
        Index Cond: ((xmlscheduledtime < '2010-05-20T13:00:00.000'::bpchar) AND (currentstate = 'SCHEDULED'::bpchar) AND ((campaignfqname)::text = '.main.ee45692a-6113-43cb-9257-7b6bf65f0c3e'::text))

而且,是的,我知道有很多事情we could do to normalize and improve the design of this table。其中一些选项可供我们使用。

我对这个问题的关注关于理解how PostgresQL is managing the index and query over time (understand why, not just fix)。如果要完成或重新进行重构,那么会有很多变化。

5 个答案:

答案 0 :(得分:14)

如果您根据所需的性能进行配置,自动吸尘应该可以解决问题。

注意: VACUUM FULL:这将重建表统计信息并回收磁盘空间负载。它锁定整个桌子。

VACUUM:这将重建表统计信息并回收一些磁盘空间。它可以与生产系统并行运行,但会产生大量可能影响性能的IO。

ANALYZE:这将重建查询计划程序统计信息。这是由VACUUM触发的,但可以单独运行。

更多detailed notes found here

答案 1 :(得分:2)

至于性能,使用字符串存储时间和状态信息是一个很大的瓶颈。首先,文本索引效率极低,在同一天比较两次需要至少11次比较(使用您使用的格式),但是,使用时间类型可以简化为一次比较。这也会影响索引的大小,并且很难搜索大索引,并且db不会将其保留在内存中。同样的考虑因素适用于州列。如果它代表一小组状态,则应使用映射到状态的整数,这将减少索引的节点 - 以及相应的索引大小。此外,如果您没有在查询中指定实际时间,即使使用theese内置类型,此索引也将无用。

答案 2 :(得分:2)

这对我来说闻起来像指数臃肿。我推荐你到这个页面

http://www.postgresql.org/docs/8.3/static/routine-reindex.html

在底部说:

  

另外,对于B树索引a   新建的指数有点   访问速度比访问速度快   已多次更新,因为   逻辑上相邻的页面通常是   在新的物理相邻   建成指数。 (这个考虑确实如此   目前不适用于非B树   索引。)这可能是值得的   定期重新索引以改善   访问速度。

这似乎与您引用的页面冲突,说索引“不需要维护或调整”。

您是否尝试过“同时创建索引”?

答案 3 :(得分:1)

是否将xmlscheduledtime与之比较的“2010-05-20T13:00:00.000”值,SQL的一部分或作为参数提供?

在规划如何运行查询时,如果某个字段必须小于一个具有尚未知值的提供参数,则不会给PostgreSQL带来太大的影响。它不知道这是否几乎匹配所有行,或几乎没有任何行。

在试图找出数据库使用计划的原因时,阅读how the planner uses statistics会有很大帮助。

您可以通过更改该复杂索引中的字段顺序或创建新索引来获得更好的选择性能,其中包含已排序的字段(campaignfqname,currentstate,xmlscheduledtime),从那时起索引将直接转到广告系列fq名称和你感兴趣的当前状态,xmlscheduledtime范围内的索引扫描都将是你所追求的行。

答案 4 :(得分:0)

这是一本教科书案例。你应该设置autovacuum更积极。