代码之家  ›  专栏  ›  技术社区  ›  Jim Rush

为什么postgresql查询性能会随时间下降,但在重建索引时会恢复

  •  18
  • Jim Rush  · 技术社区  · 15 年前

    根据这个 page 在手册中, indexes don't need to be maintained . 但是,我们运行的postgresql表的连续速率为 updates , deletes inserts 随着时间的推移(几天),查询性能会显著下降。如果删除并重新创建索引,查询性能将恢复。

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

    我们是 searching based of an index, not the primary key (我已经确认索引正在使用,至少在正常情况下)

    表被用作单个进程的持久存储。 在带有Java客户端的Windows上使用PostgreSQL。

    我愿意放弃 insert and update performance 以保持查询性能。

    我们正在考虑重新调整应用程序的结构,以便数据能够以一种允许我们定期删除和重建索引而不影响应用程序的方式分布在各种动态表中。然而,和往常一样,要让它工作需要时间,我怀疑我们在配置或使用中缺少了一些基本的东西。

    我们考虑过 forcing vacuuming rebuild 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 回复  |  直到 9 年前
        1
  •  13
  •   Timothy    15 年前

    自动吸尘器应该可以做到这一点,只要你配置它达到你想要的性能。

    笔记: 真空已满:这将重建表统计信息并回收磁盘空间负载。它锁住了整张桌子。

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

    分析:这将重建查询计划器统计信息。这是由真空触发的,但可以自己运行。

    更多 detailed notes found here

        2
  •  2
  •   Ákos Kiss    13 年前

    至于性能,使用字符串存储时间和状态信息是一个相当大的瓶颈。首先,文本索引是非常低效的,同一天比较两次至少需要11次比较(以您使用的格式),但是,使用时间类型可以简化为一次比较。这也会影响索引的大小,大索引很难搜索,数据库也不会将其保存在内存中。同样的注意事项也适用于state列。如果它表示一个小的状态集,则应使用映射到状态的整数,这将相应地减少索引的节点和索引大小。此外,如果不在查询中指定实际时间,即使使用se内置类型,此索引也将毫无用处。

        3
  •  2
  •   Chris Curvey    13 年前

    这闻起来像是索引膨胀。我让你看看这一页

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

    下面写着:

    另外,对于b树索引a 新构建的索引有点 比那些 多次更新,因为 逻辑上相邻的页通常是 在新的 建立索引。(这种考虑确实 当前不适用于非B树 索引)。 定期重新编制索引以改进 访问速度。

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

    你试过“同时创建索引”吗?

        4
  •  1
  •   Stephen Denne    15 年前

    与xmlscheduledtime进行比较的“2010-05-20t13:00:00.000”值是sql的一部分,还是作为参数提供的?

    在计划如何运行查询时,如果一个字段必须小于一个提供的参数,并且该参数的值还未知,那么postgresql就没什么可继续的了。它不知道这是否能匹配几乎所有的行,或者几乎不匹配任何行。

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

    通过更改该复杂索引中字段的顺序,或创建一个新索引(按字段顺序排列)(campaign fq name、current state、xmlscheduledtime),您可能会获得更好的选择性能,因为从那时起,该索引将直接指向您感兴趣的活动fq名称和当前状态。ted in,xmlscheduledtime范围内的索引扫描都是您要查找的行。

        5
  •  0
  •   bobflux    13 年前

    那是一个教科书案例。你应该把自动吸尘器设置得更有侵略性。