提高查询速度:大postgres表中的简单SELECT

ale*_*tos 28 sql postgresql performance postgresql-performance

我在Postgres数据库的SELECT查询中遇到速度问题.

我有一个表有两个整数列作为键:(int1,int2)这个表有大约7000万行.

我需要在这种环境中进行两种简单的SELECT查询:

SELECT * FROM table WHERE int1=X;
SELECT * FROM table WHERE int2=X;
Run Code Online (Sandbox Code Playgroud)

这两个选择在这7000万个中返回大约10,000行.为了尽可能快地工作,我考虑使用两个HASH索引,每列一个.不幸的是结果并不那么好:

                                                               QUERY PLAN                                                               
----------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on lec_sim  (cost=232.21..25054.38 rows=6565 width=36) (actual time=14.759..23339.545 rows=7871 loops=1)
   Recheck Cond: (lec2_id = 11782)
   ->  Bitmap Index Scan on lec_sim_lec2_hash_ind  (cost=0.00..230.56 rows=6565 width=0) (actual time=13.495..13.495 rows=7871 loops=1)
         Index Cond: (lec2_id = 11782)
 Total runtime: 23342.534 ms
(5 rows)
Run Code Online (Sandbox Code Playgroud)

这是其中一个查询的EXPLAIN ANALYZE示例.这需要大约23秒.我的期望是在不到一秒的时间内获得这些信息.

这些是postgres db config的一些参数:

work_mem = 128MB
shared_buffers = 2GB
maintenance_work_mem = 512MB
fsync = off
synchronous_commit = off
effective_cache_size = 4GB
Run Code Online (Sandbox Code Playgroud)

任何帮助,评论或想法都会非常感激.

先感谢您.

wil*_*ynn 34

将我的评论提取到答案中:这里的索引查找速度非常快 - 所有时间都花在检索实际行上.23秒/ 7871行=每行2.9毫秒,这对于检索分散在磁盘子系统中的数据是合理的.寻求缓慢; 你可以a)使你的数据集适合RAM,b)购买SSD,或c)提前组织你的数据,以尽量减少搜索.

PostgreSQL 9.2有一个称为仅索引扫描的功能,允许它(通常)在不访问表的情况下回答查询.您可以将此与btree自动维护顺序的索引属性结合使用,以快速进行此查询.你提到int1,int2和两个花车:

CREATE INDEX sometable_int1_floats_key ON sometable (int1, float1, float2);
CREATE INDEX sometable_int2_floats_key ON sometable (int2, float1, float2);

SELECT float1,float2 FROM sometable WHERE int1=<value>; -- uses int1 index
SELECT float1,float2 FROM sometable WHERE int2=<value>; -- uses int2 index
Run Code Online (Sandbox Code Playgroud)

另请注意,这不会神奇地擦除磁盘搜索,只是将它们从查询时间移动到插入时间.它也会占用您的存储空间,因为您正在复制数据.不过,这可能是你想要的权衡.

  • 我对这是多么惊人以及它对性能的影响有多大感到震惊.创建一个简单的索引会在包含大约20mil行的生产数据库上将数据库查询从~8s删除到~20ms. (2认同)

ale*_*tos 20

谢谢你willglyn.正如你所注意到的那样,问题在于通过高清搜索而不是查找索引.您提出了许多解决方案,例如在RAM中加载数据集或购买SSD HD.但是忘记了这两个涉及管理数据库本身之外的事情,你提出了两个想法:

  1. 重新组织数据以减少对数据的搜索.
  2. 使用PostgreSQL 9.2功能"仅索引扫描"

由于我在PostgreSQL 9.1服务器下,我决定选择"1".

我制作了一份表格.所以现在我有两次相同数据的同一个表.我为每一个创建了一个索引,第一个索引由(int1)索引,第二个索引由(int2)索引.然后我将它们(CLUSTER表USING ind_intX)按其各自的索引聚类.

我现在发布了一个相同查询的EXPLAIN ANALYZE,在其中一个聚簇表中完成:

                                                         QUERY PLAN                                                            
---------------------------------------------------------------------------------------------------------------------------------------------  
Index Scan using lec_sim_lec2id_ind on lec_sim_lec2id  (cost=0.00..21626.82 rows=6604 width=36) (actual time=0.051..1.500 rows=8119 loops=1)
Index Cond: (lec2_id = 12300)  Total runtime:
1.822 ms (3 rows)

现在寻求的速度非常快.我从23秒下降到~2毫秒,这是一个令人印象深刻的改进.我认为这个问题已经解决了,我希望这对于遇到同样问题的其他人也有用.

非常感谢willglynn.

  • 如果您有静态数据集,那么您就完成了.如果没有,您将需要使用触发器维护已排序的表(以便有一个事实来源),并且您需要定期重新``CLUSTER`以在数据更改时保持磁盘顺序. (3认同)