Tôi có một ngăn xếp TileMill / PostGIS chạy trên máy ảo Ubuntu 12.04 lõi 8 trên đám mây OpenStack. Đó là bản dựng lại của một hệ thống rất giống nhau đang chạy tốt trên phần cứng rất giống nhau (cùng một đám mây, nhưng phần cứng vật lý khác nhau, tôi tin) vào tuần trước. Tôi đã cố gắng xây dựng lại ngăn xếp chính xác như cũ (sử dụng một số tập lệnh tôi đã xây dựng).
Mọi thứ đều chạy, nhưng cơ sở dữ liệu đang thực hiện các truy vấn cực kỳ chậm, biểu hiện cuối cùng với việc tạo ra các ô rất chậm. Một truy vấn mẫu (đếm số lượng quán rượu trong bán kính của mỗi thị trấn ở Úc), trước đây mất khoảng 10-20 giây, giờ mất hơn 10 phút:
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
(Tôi bao gồm truy vấn này như một triệu chứng, không trực tiếp giải quyết vấn đề. Truy vấn cụ thể này chỉ được chạy một lần một tuần hoặc lâu hơn.)
Máy chủ có 32 GB RAM và tôi đã định cấu hình Postgres như sau (theo lời khuyên tìm thấy trên web):
shared_buffers = 8GB
autovacuum = on
effective_cache_size = 8GB
work_mem = 128MB
maintenance_work_mem = 64MB
wal_buffers = 1MB
checkpoint_segments = 10
iostat
cho thấy không có gì được đọc, một chút dữ liệu được ghi (không biết ở đâu hoặc tại sao) và CPU nhàn rỗi 95%:
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
Đầu ra mẫu từ 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
Nắm chặt ống hút, tôi chuyển thư mục dữ liệu Postgres từ vda sang vdb nhưng tất nhiên điều đó không có gì khác biệt.
Vì vậy, tôi đang thua lỗ. Tại sao Postgres chỉ sử dụng 5% CPU có sẵn khi nó không chờ đợi bất kỳ I / O nào? Tôi hoan nghênh mọi đề xuất để điều tra thêm, các công cụ khác, những điều ngẫu nhiên để thử.
Cập nhật
Tôi đã chụp nhanh máy chủ và khởi chạy nó trên một phần khác của cùng một đám mây (một vùng khả dụng khác nhau). Kết quả hơi kỳ lạ. vmstat
trên máy chủ này báo cáo mức sử dụng CPU 12% (mà bây giờ tôi hiểu là giá trị mong đợi cho một truy vấn Postgres duy nhất trên máy ảo 8 lõi) - mặc dù thời gian thực hiện truy vấn thực tế gần như giống hệt nhau (630 giây so với 623).
Bây giờ tôi nhận ra rằng truy vấn cụ thể này có thể không phải là một mẫu tốt vì lý do này: nó chỉ có thể sử dụng một lõi và đó là một update
(trong khi kết xuất gạch chỉ là select
s).
Tôi cũng không nhận thấy explain
rằng dường như planet_osm_polygon
không sử dụng một chỉ mục. Đó cũng có thể là nguyên nhân, vì vậy tôi sẽ theo đuổi điều đó tiếp theo.
Cập nhật2
Vấn đề dường như chắc chắn là chỉ số hành tinh_osm_polygon không được sử dụng. Có hai (một được tạo bởi osm2pgsql, một được tạo bởi tôi theo một số hướng dẫn ngẫu nhiên):
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);
Các số liệu thống kê về hành tinh_osm_polygon và hành tinh_osm_point khá lộ liễu, tôi nghĩ:
hành tinh_osm_polygon:
Sequential Scans 194204
Sequential Tuples Read 60981018608
Index Scans 1574
Index Tuples Fetched 0
hành tinh_osm_point:
Sequential Scans 1142
Sequential Tuples Read 12960604
Index Scans 183454
Index Tuples Fetched 43427685
Nếu tôi đọc đúng, Postgres đã tìm kiếm hành tinh_osm_polygon 1574 lần, nhưng thực sự không bao giờ tìm thấy bất cứ điều gì, vì vậy đã thực hiện một số lượng lớn các tìm kiếm vũ phu.
Câu hỏi mới: tại sao?
Giải đáp bí ẩn
Nhờ câu trả lời của Frederik Ramm , câu trả lời hóa ra khá đơn giản: vì một số lý do không có chỉ số không gian. Thật là tầm thường khi tái tạo chúng:
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);
Chạy truy vấn đó bây giờ mất 4,6 giây. Chỉ số không gian quan trọng! :)