【问题标题】:PostgreSQL query & table optimizationPostgreSQL 查询和表优化
【发布时间】:2010-08-12 18:31:25
【问题描述】:

我正在处理一张包含大约 300 万个元组的表。它不会经常更改(每周更新或插入一些内容)并且被大量阅读。 (请不要评论长度为 1 的 varchar。我知道,我知道)。

   Column    |         Type          |                      Modifiers                       
-------------+-----------------------+------------------------------------------------------
 id          | integer               | not null default nextval('mytable_id_seq'::regclass)
 A           | character varying(5)  | not null
 B           | character varying(16) | not null
 C           | character varying(3)  | not null
 D           | character varying(1)  | not null
 otherdata   | character varying(99) | not null
Indexes:
    "mytable_pkey" PRIMARY KEY, btree (id)
    "mytable_unique_key" UNIQUE, btree (A, B, C, D)
    "mytable_B_idx" btree (B)
Foreign-key constraints:
    "$1" FOREIGN KEY (A, B) REFERENCES anothertable1(A, B)
    "$2" FOREIGN KEY (C) REFERENCES anothertable2(C)
    "$3" FOREIGN KEY (D) REFERENCES anothertable3(D)
Referenced by:
    TABLE "anothertable4" CONSTRAINT "$1" FOREIGN KEY (id) REFERENCES mytable(id)
    TABLE "anothertable5" CONSTRAINT "fkey_id" FOREIGN KEY (id) REFERENCES mytable(id) ON UPDATE CASCADE ON DELETE CASCADE

id 是我的主键。 A,B,C,D 是候选键。两者显然都是唯一标识一个元组。

最常见的查询是:

SELECT * FROM mytable WHERE B='foo'; - 将返回一些元组

SELECT * FROM mytable WHERE A='foo' AND B='bar' AND C='baz' AND D='f'; - 将返回一个元组。

因此为什么在BA,B,C,D 上有索引。

现在,无论出于何种原因,我正在执行以下查询(并且更类似):

SELECT * FROM mytable WHERE ((A='foo' AND B='bar') OR (B='foo' AND C='bar'));

一个机器正在运行 PostgreSQL 8.4.4。如果我 EXPLAIN ANALYZE 第一个查询,我会得到以下查询计划:

                                                                          QUERY PLAN                                                                           
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on mytable  (cost=9.74..174.30 rows=1 width=14) (actual time=0.000..0.000 rows=5 loops=1)
   Recheck Cond: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR ((B)::text = 'foo'::text))
   Filter: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text)))
   ->  BitmapOr  (cost=9.74..9.74 rows=42 width=0) (actual time=0.000..0.000 rows=0 loops=1)
         ->  Bitmap Index Scan on mytable_unique_key(cost=0.00..4.80 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=1)
               Index Cond: (((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text))
         ->  Bitmap Index Scan on mytable_B_idx(cost=0.00..4.94 rows=42 width=0) (actual time=0.000..0.000 rows=316 loops=1)
               Index Cond: ((B)::text = 'foo'::text)
 Total runtime: 0.000 ms
(9 rows)

9.74 的最低成本和几乎即时的回报(是的,它被缓存了)。现在,如果我在另一台类似机器上的 PostgreSQL 8.1.5 上运行相同的查询——表中的内容完全相同——我会得到以下信息:

                                                                         QUERY PLAN                                                                      
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on mytable (cost=110156.34..110168.36 rows=3 width=26) (actual time=147200.984..147221.480 rows=5 loops=1)
   Recheck Cond: ((((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text)) OR (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text)))
   ->  BitmapOr  (cost=110156.34..110156.34 rows=3 width=0) (actual time=147185.513..147185.513 rows=0 loops=1)
         ->  Bitmap Index Scan on mytable_unique_key(cost=0.00..2.01 rows=1 width=0) (actual time=83.275..83.275 rows=0 loops=1)
               Index Cond: (((A)::text = 'foo'::text) AND ((B)::text = 'bar'::text))
         ->  Bitmap Index Scan on mytable_unique_key(cost=0.00..110154.34 rows=2 width=0) (actual time=147102.230..147102.230 rows=5 loops=1)
               Index Cond: (((B)::text = 'foo'::text) AND ((C)::text = 'bar'::text))
 Total runtime: 147221.663 ms
(8 rows)

两个表格和两个盒子都被 VACUUM 处理。因此,令人难以置信的差异是由于 8.1.5 和 8.4.4 之间引入了不同的版本和性能提升。大到开发者!

好的,这个问题的重点不是对不同版本的PostgreSQL进行基准测试,而是要问这个问题:如何提高上述查询的性能?我有以下解决方案(或问题):

  1. 升级到最新的稳定版 PostgreSQL。我们在许多服务器上都在生产 8.1.5。 缺点:升级任务会很长。我不介意太多,因为它会是操作员做的。数据将需要完整转储和导入。 专业人士:我们受益于最新版本带来的惊人性能改进和附加功能。
  2. 优化查询以帮助规划者。我不知道如何为上述查询执行此操作。
  3. 添加索引。 这将有助于计划者并加快执行速度。但是,它增加了一些开销。我需要添加哪些索引? A,BB,CABC?前者将有助于上述查询。但是,我还有其他类似的查询过滤其他列。查询将在这些列集上完成:BB,CA,BA,B,CB,C,DA,B,C,D。这是否意味着我需要为每个列集建立一个索引?还是只是最贵的?在上面的查询中,扫描B,C 是最昂贵的。

提前谢谢你。

【问题讨论】:

    标签: postgresql query-optimization


    【解决方案1】:

    看起来 mytable_unique_key-index 在您的 8.1-box 上显得臃肿。先尝试解决这个问题:

    REINDEX TABLE tablename;
    

    重建索引后,你能做一个新的解释吗?

    您也应该开始迁移到较新的版本,对 8.1 的支持将于今年结束。

    【讨论】:

      猜你喜欢
      • 2014-06-13
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-12
      • 2018-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多