如何优化在 postgresql 中查询这些数据?

Posted

技术标签:

【中文标题】如何优化在 postgresql 中查询这些数据?【英文标题】:How can I optimize querying this data in postgresql? 【发布时间】:2014-10-09 04:00:50 【问题描述】:

我有一个查询对于特定行来说很慢。 Postgres 选择对某些行使用Seq Scan 而不是使用Index Scan,因为它实际上会比使用索引更快。

以下是针对普通工作负载使用索引的查询计划:http://explain.depesz.com/s/1A2o:

EXPLAIN (ANALYZE, BUFFERS) SELECT "blocks".* FROM "blocks" INNER JOIN "jobs" ON "blocks"."job_id" = "jobs"."id" WHERE "jobs"."project_id" = 1;
                                                                 QUERY PLAN                                                                 
--------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.71..166.27 rows=19 width=130) (actual time=0.092..4.247 rows=2421 loops=1)
   Buffers: shared hit=350
   ->  Index Scan using index_jobs_on_project_id on jobs  (cost=0.29..18.81 rows=4 width=4) (actual time=0.044..0.099 rows=15 loops=1)
         Index Cond: (project_id = 1)
         Buffers: shared hit=17
   ->  Index Scan using index_blocks_on_job_id on blocks  (cost=0.42..36.67 rows=19 width=130) (actual time=0.021..0.133 rows=161 loops=15)
         Index Cond: (job_id = jobs.id)
         Buffers: shared hit=333
 Total runtime: 4.737 ms
(9 rows)

这是选择对不太正常的工作负载进行顺序扫描的查询计划:http://explain.depesz.com/s/cJOd:

EXPLAIN (ANALYZE, BUFFERS) SELECT "blocks".* FROM "blocks" INNER JOIN "jobs" ON "blocks"."job_id" = "jobs"."id" WHERE "jobs"."project_id" = 2;
                                                                 QUERY PLAN                                                                     
----------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join  (cost=1138.64..11236.94 rows=10421 width=130) (actual time=5.212..72.604 rows=2516 loops=1)
 Hash Cond: (blocks.job_id = jobs.id)
 Buffers: shared hit=5671
 ->  Seq Scan on blocks  (cost=0.00..8478.06 rows=303206 width=130) (actual time=0.008..24.573 rows=298084 loops=1)
       Buffers: shared hit=5446
 ->  Hash  (cost=1111.79..1111.79 rows=2148 width=4) (actual time=3.346..3.346 rows=2164 loops=1)
       Buckets: 1024  Batches: 1  Memory Usage: 77kB
       Buffers: shared hit=225
       ->  Bitmap Heap Scan on jobs  (cost=40.94..1111.79 rows=2148 width=4) (actual time=0.595..2.158 rows=2164 loops=1)
             Recheck Cond: (project_id = 2)
             Buffers: shared hit=225
             ->  Bitmap Index Scan on index_jobs_on_project_id  (cost=0.00..40.40 rows=2148 width=0) (actual time=0.516..0.516 rows=2164 loops=1)
                   Index Cond: (project_id = 2)
                   Buffers: shared hit=8
 Total runtime: 72.767 ms
(15 rows)

在第一种情况下,该项目有 15 个工作岗位和 2421 个街区。在第二种情况下,该项目有 2164 个工作和 2516 个区块。

有没有办法查询这些数据以使第二个工作负载不那么慢?还是我只是在处理某种最坏情况下的性能工作负载?

编辑

将 random_page_cost 更新为 1.1 并为慢查询重新运行 EXPLAIN 后:http://explain.depesz.com/s/xKdd

EXPLAIN (ANALYZE, BUFFERS) SELECT "blocks".* FROM "blocks" INNER JOIN "jobs" ON "blocks"."job_id" = "jobs"."id" WHERE "jobs"."project_id" = 2;

                                                              QUERY PLAN                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.71..7634.08 rows=10421 width=130) (actual time=0.025..10.597 rows=2516 loops=1)
   Buffers: shared hit=9206
   ->  Index Scan using index_jobs_on_project_id on jobs  (cost=0.29..1048.99 rows=2148 width=4) (actual time=0.015..1.239 rows=2164 loops=1)
         Index Cond: (project_id = 32357)
         Buffers: shared hit=225
   ->  Index Scan using index_blocks_on_job_id on blocks  (cost=0.42..2.88 rows=19 width=130) (actual time=0.003..0.003 rows=1 loops=2164)
         Index Cond: (job_id = jobs.id)
         Buffers: shared hit=8981
 Total runtime: 10.925 ms
(9 rows)

好多了!看来我需要花一些时间来调整服务器配置。

【问题讨论】:

你有什么索引? jobs.project_idblocks.job_id 列上有索引。 请显示完整的EXPLAIN (ANALYZE, BUFFERS) ... 而不仅仅是EXPLAIN jobs.id 呢? 由于两个索引扫描上的嵌套循环比位图索引扫描上的 hashjoin 快得多,我想说您的 random_page_cost 不能准确反映您的实际性能,至少当数据缓存在RAM 或 shared_buffers。尝试设置 SET random_page_cost = 1.1 并在该会话中重新运行。您可能还想在问题上抛出更多 work_mem 【参考方案1】:

由于两个索引扫描上的嵌套循环比位图索引扫描上的 hashjoin 快得多,我想说您的 random_page_cost 不能准确反映您的实际性能,至少当数据缓存在 RAM 中或 @ 987654323@.

尝试设置SET random_page_cost = 1.1 并在该会话中重新运行。您可能还想在问题上抛出更多 work_mem

如果random_page_cost 调整有效,您可能需要更新postgresql.conf 以反映它。请注意,1.1 是一个非常极端的设置;默认值为 4,seq_page_cost 为 1,因此在配置文件中我会从 2 或 1.5 之类的东西开始,以避免使其他计划变得更糟。

【讨论】:

random_page_cost 对我的一些查询产生了巨大的积极影响。这是一篇很好的文章,扩展了由于 random_page_cost 的性能改进:How a single PostgreSQL config change improved slow query performance by 50x

以上是关于如何优化在 postgresql 中查询这些数据?的主要内容,如果未能解决你的问题,请参考以下文章

针对多个表优化缓慢的 postgresql 查询

优化以下 postgreSQL 代码的可能方法是啥?

在同一查询中选择和更新 PostgreSQL 以进行优化

如何为复杂的 sql 查询获取中间数据。 PostgreSQL

优化 PostgreSQL 中的 JOIN -> GROUP BY 查询:所有索引都已经存在

优化在 pgAdmin 中执行速度比在应用程序中更快的 postgresql 查询以及并发查询