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
(私はこのクエリを症状として含めています。直接解決すべき問題ではありません。この特定のクエリは、週に1回程度しか実行されません。)
サーバーには32 GBのRAMが搭載されており、Postgresを次のように構成しました(Webで見つかったアドバイスに従います)。
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が使用可能なCPUの5%しか使用しないのはなぜですか?さらなる調査のための提案、他のツール、試してみるランダムなことを歓迎します。
更新
サーバーのスナップショットを作成し、同じクラウドの別の部分(別のアベイラビリティーゾーン)でサーバーを起動しました。結果は少し変でした。vmstat
このサーバーでは、12%のCPU使用率(8コアVMでの単一のPostgresクエリの期待値として理解しています)を報告します-実際のクエリ実行時間は実質的に同じです(630秒vs 623)。
この特定のクエリは、この理由からおそらく良いサンプルではないことに気づきました。1つのコアしか使用できず、それはupdate
(タイルレンダリングがselect
sであるのに対して)
私はまたに気づかなかったexplain
どうやらそのplanet_osm_polygon
インデックスを使用していません。それが原因である可能性もあるので、次に追跡します。
Update2
問題は、間違いなく、planet_osm_polygonインデックスが使用されていることです。2つあります(1つはosm2pgsqlによって作成され、1つは私がいくつかのランダムガイドに従って作成したものです)。
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は1574回planet_osm_polygonを検索しましたが、実際には何も見つからなかったため、途方もなく多数のブルートフォース検索を実行しました。
新しい質問:なぜですか?
謎解き
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秒かかります。空間インデックスは重要です!:)