为什么Postgres闲置95%,没有文件I / O?


8

我在OpenStack云的8核Ubuntu 12.04 VM上运行了TileMill / PostGIS堆栈。这是对非常相似的系统的重建,该系统上周在非常相似的硬件(相同的云,但我认为是不同的物理硬件)上很好地运行。我试图完全按照原来的方式重建堆栈(使用我构建的一些脚本)。

一切都在运行,但是数据库执行查询的速度非常慢,最终以非常缓慢的切片生成来体现自己。一个示例查询(计算澳大利亚每个城镇半径内的酒吧数量),以前花费了大约10到20秒,现在却超过了10分钟:

explain (analyze, buffers) update places set pubs = 
(select count(*) from planet_osm_point p where p.amenity = 'pub' and st_dwithin(p.way,places.way,scope)) +
(select count(*) from planet_osm_polygon p where p.amenity = 'pub' and st_dwithin(p.way,places.way,scope)) ;
 Update on places  (cost=0.00..948254806.93 rows=9037 width=160) (actual time=623321.558..623321.558 rows=0 loops=1)
   Buffers: shared hit=132126300
   ->  Seq Scan on places  (cost=0.00..948254806.93 rows=9037 width=160) (actual time=68.130..622931.130 rows=9037 loops=1)
         Buffers: shared hit=132107781
         SubPlan 1
           ->  Aggregate  (cost=12.95..12.96 rows=1 width=0) (actual time=0.187..0.188 rows=1 loops=9037)
                 Buffers: shared hit=158171
                 ->  Index Scan using planet_osm_point_index on planet_osm_point p  (cost=0.00..12.94 rows=1 width=0) (actual time=0.163..0.179 rows=0 loops=9037)
                       Index Cond: (way && st_expand(places.way, (places.scope)::double precision))
                       Filter: ((amenity = 'pub'::text) AND (places.way && st_expand(way, (places.scope)::double precision)) AND _st_dwithin(way, places.way, (places.scope)::double precision))
                       Buffers: shared hit=158171
         SubPlan 2
           ->  Aggregate  (cost=104917.24..104917.25 rows=1 width=0) (actual time=68.727..68.728 rows=1 loops=9037)
                 Buffers: shared hit=131949237
                 ->  Seq Scan on planet_osm_polygon p  (cost=0.00..104917.24 rows=1 width=0) (actual time=68.138..68.716 rows=0 loops=9037)
                       Filter: ((amenity = 'pub'::text) AND (way && st_expand(places.way, (places.scope)::double precision)) AND (places.way && st_expand(way, (places.scope)::double precision)) AND _st_dwithin(way, places.way, (places.scope)::double precision))
                       Buffers: shared hit=131949237
 Total runtime: 623321.801 ms

(我将这个查询作为一种症状,而不是直接解决要解决的问题。这个特定的查询大约一周才运行一次。)

该服务器具有32 GB的RAM,并且我已按以下方式配置Postgres(遵循在网上找到的建议):

shared_buffers = 8GB
autovacuum = on
effective_cache_size = 8GB
work_mem = 128MB
maintenance_work_mem = 64MB
wal_buffers = 1MB
checkpoint_segments = 10

iostat 显示未读取任何内容,写入了一点数据(不知道在哪里或为什么)以及95%的空闲CPU:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.40    0.00    0.00    0.11    0.00   94.49

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda               0.20         0.00         0.80          0          8
vdb               2.30         0.00        17.58          0        176

来自的样本输出vmstat

  procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
...
 1  0      0 18329748 126108 12600436    0    0     0    18  148  140  5  0 95  0
 2  0      0 18329400 126124 12600436    0    0     0     9  173  228  5  0 95  0

抱着稻草,我将Postgres数据目录从vda移到了vdb,但是当然没有什么区别。

所以我很茫然。为什么在不等待任何I / O时,Postgres只使用5%的可用CPU?我欢迎任何进一步调查的建议,其他工具,随机尝试。

更新资料

我对服务器进行了快照,并在同一云的不同部分(不同的可用性区域)启动了它。结果有点奇怪。vmstat尽管实际的查询执行时间实际上是相同的(630秒与623),但该服务器上的CPU使用率却报告了12%的CPU使用率(我现在将其理解为8核VM上单个Postgres查询的期望值)。

我现在意识到,由于这个原因,这个特定的查询可能不是一个很好的示例:它只能使用一个核心,并且是一个update(而tile渲染只是selects)。

我也没有注意到explain,显然planet_osm_polygon没有使用索引。那很可能是原因,所以我接下来将继续探讨。

更新2

显然,问题似乎是/没有使用planet_osm_polygon索引。有两种(一种是由osm2pgsql创建的,一种是由我根据一些随机指南创建的):

CREATE INDEX idx_planet_osm_polygon_tags
  ON planet_osm_polygon
  USING gist
  (tags);


CREATE INDEX planet_osm_polygon_pkey
  ON planet_osm_polygon
  USING btree
  (osm_id);

我认为planet_osm_polygon和planet_osm_point的统计数据非常具有启发性:

planet_osm_polygon:

Sequential Scans    194204  
Sequential Tuples Read  60981018608 
Index Scans 1574    
Index Tuples Fetched    0

planet_osm_point:

Sequential Scans    1142    
Sequential Tuples Read  12960604    
Index Scans 183454  
Index Tuples Fetched    43427685

如果我没看错的话,Postgres已经搜索了planet_osm_polygon 1574次,但是却从未真正找到任何东西,因此进行了大量的蛮力搜索。

新问题:为什么?

谜团已揭开

多亏Frederik Ramm的回答,答案才变得非常简单:由于某种原因,没有空间索引。再生它们很简单:

create index planet_osm_polygon_polygon on planet_osm_polygon using gist(way);
create index planet_osm_polygon_point on planet_osm_point using gist(way);

现在运行该查询需要4.6秒。空间索引很重要!:)


我意识到该条目已经很老了,但是我遇到了类似的问题。因为索引已经存在,所以我不能两次创建planet_osm_polygon_point。但是,所谓的索引并不重要,对吧?
塞巴斯蒂安·博格格雷

如果索引存在,那么为什么还要创建另一个索引呢?但是无论如何,您都可以删除旧的或重命名新的。
史蒂夫·本内特

我只是问,因为这两个索引:使用gist(way)在planet_osm_polygon上创建索引planet_osm_polygon_point;使用gist(way)在planet_osm_point上创建索引planet_osm_polygon_point;被命名为planet_osm_polygon_point,除非我丢失了某些东西,否则这似乎是一个错误。
塞巴斯蒂安·博格格雷

哦! 我不明白 是的,我的回答有错字。
史蒂夫·贝内特

感谢史蒂夫,您是否也可以更正答案中的错字,以备将来参考。谢谢。
塞巴斯蒂安·博格格雷

Answers:


4

通过explain.depesz.com运行您的Explain Anlayze输出会突出显示,大部分的迟缓都来自此操作:

Seq Scan on planet_osm_polygon p 

那之前被索引过吗?您现在可以索引它吗?

通过搜索该问题区域,我还在“开放街道地图”站点上找到了相关的问答:


感谢您指出这一点-我错过了。实际上,此表上有两个索引。使用更多信息更新我的问题。
史蒂夫·贝内特

哦-该链接提供了答案。是的,尽管有一个“索引”,但它只是在ID字段上,而不是在实际的几何字段(“ way”)上-因此对于空间索引没有用。弗雷德里克的评论包含了答案。
史蒂夫·本内特

4

PostgreSQL只能对任何给定查询使用一个内核。它可以通过许多并发查询获得良好的并行性能,但对于仅几个非常大的查询的工作负载而言,却无法从大量核心中受益。因此,如果您只运行一个查询,那么5%并不奇怪,尽管我希望在8核系统上为5%。

缺少iowait意味着它可能不会受到磁盘I / O的影响。

因此-在CPU或I / O上似乎没有瓶颈。

是否有可能仅通过锁定将查询阻止一段时间?检查pg_stat_activity查询,然后加入pg_locks以查看是否存在任何未授予的锁。(存在有关Pg锁定监视的固定查询)。

接下来要做的是运行一些较低级别的系统测试。运行pg_test_fsync,使用sysbench的CPU和I / O测试等。如果这些测试效果也很差,请与您的托管服务提供商联系。

您还应该收集一点perf top -a输出,看看它的实际作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.