mbtiles作成の時間計測

今回は、OpenMapTilesのquickstart.shの処理時間を計測します。

時間計測方法

計測の目的は、OpenMapTilesの処理概要の把握とボトルネックの確認です。
計測の条件を整理します。

  • OSMデータは四国(shikoku.osm.pbf、約63MB)を使用
  • quickstart.shの–emptyオプションを指定しpreloadコンテナを使用しない
  • quickstart.shにて発行されるコマンドの前後にdateコマンドの発行を追加し時間を計測
  • 作成するタイルのズームレベルは0〜7まで(.envデフォルトのまま)
  • マシンはさくらVPS。メモリ1GB、CPU2コア、SSD100GB

計測結果

処理は2時間44分で終了しました。計測結果を以下の表にまとめます。

#処理内容開始終了時間
1Stopping running services & removing old containers10:15:3310:15:350:00:02
2Downloading shikoku from any source...10:15:3510:16:090:00:34
3Code generating from the layer definitions ( ./build/mapping.yaml; ./build/sql/* )10:16:0910:16:150:00:06
4Start PostgreSQL service using empty database and importing all the data10:16:1510:16:310:00:16
5NaturalEarthデータのインポート10:16:3110:17:470:01:16
6Start importing OpenStreetMap data: shikoku -> imposm3[./build/mapping.yaml] -> PostgreSQL10:17:4810:18:590:01:11
7Start importing border shikoku data into PostgreSQL using osmborder10:18:5910:19:060:00:07
8Start importing Wikidata: Wikidata Query Service -> PostgreSQL10:19:0610:19:150:00:09
9Start SQL postprocessing: ./build/sql/* ,-> PostgreSQL10:19:1512:59:022:39:47
10Analyze PostgreSQL tables12:59:0212:59:310:00:29
11Testing PostgreSQL tables to match layer definitions metadata12:59:3112:59:340:00:03
12Compute bounding box for tile generation12:59:3412:59:370:00:03
13Start generating MBTiles (containing gzipped MVT PBF) from a TM2Source project.12:59:3712:59:520:00:15
14Stop PostgreSQL service ( but we keep PostgreSQL data volume for debugging )12:59:5212:59:530:00:01
(合計)2:44:19

処理の最初にコンソールに表示される内容を”処理内容”として記載しています。処理時間の97%は、#19のbuild/sql配下のsqlの実行であることがわかります。
今回は、ズームレベル0〜7までの小縮尺地図のみ作成したせいかもしれませんが、#13のMBTilesの作成時間はわずか15秒です(完成したMBTilesのサイズは528KB)。

では、処理時間のほとんどを費やした#19のbuild/sql配下のsqlの実行時間を確認してみます。

#処理内容時間
1Importing /sql/parallel/place.sql0:00:01
2update_osm_park_polygon0:00:07
3psql:/sql/parallel/park.sql0:00:13
4update_osm_island_polygon0:00:19
5psql:/sql/parallel/place.sql0:00:07
6update_osm_island_point0:00:08
7update_osm_state_point0:00:04
8psql:/sql/parallel/building.sql0:01:00
9psql:/sql/parallel/water__waterway.sql0:00:46
10psql:/sql/parallel/water__waterway.sql0:00:15
11psql:/sql/parallel/water__waterway.sql0:00:10
12update_osm_peak_point0:02:28
13update_osm_city_point0:03:51
14psql:/sql/parallel/landuse.sql0:01:44
15psql:/sql/parallel/water_name.sql0:04:11
16update_poi_polygon0:29:46
17update_osm_poi_point0:30:01
18psql:/sql/parallel/poi.sql2:37:27
19psql:/sql/parallel/water__waterway.sql0:00:02
(合計)3:52:42

合計時間が1時間以上合いませんが、#16、#17などが重複しているのだと思います。
#16〜18のpoi(点の地物データ)関連の処理時間が大半であることがわかります。

考察

完成したMBTilesをTileServerGLを使って配信し、レイヤ数を確認すると、以下のように16種類あることがわかります。

作成した四国の地図表示

そして、build/sqlディレクトリ配下のsqlファイル数は14、layersディレクトリ配下のレイヤと思われるディレクトリ数は16あります。
おそらく、build/sqlディレクトリ配下のsqlスクリプトは、NaturalEarthやOSMなどの元データからのデータ取り込み用、layersディレクトリ配下はMBTiles出力用のsqlスクリプトであると思われます。

openmaptiles
|– build
|  |– mapping.yaml
|  |– openmaptiles.tm2source
|  |  |– data.yml
|  |– sql
|     |– parallel
|     |  |– aerodrome_label.sql
|     |  |– aeroway.sql
|     |  |– boundary.sql
|     |  |– building.sql
|     |  |– housenumber.sql
|     |  |– landcover.sql
|     |  |– landuse.sql
|     |  |– mountain_peak.sql
|     |  |– park.sql
|     |  |– place.sql
|     |  |– poi.sql
|     |  |– transportation__transportation_name.sql
|     |  |– water__waterway.sql
|     |  |– water_name.sql
|     |– run_first.sql
|     |– run_last.sql
|– layers
|  |– aerodrome_label
|  |  |– aerodrome_label.yaml
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– update_aerodrome_label_point.sql
|  |– aeroway
|  |  |– aeroway.yaml
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |– boundary
|  |  |– boundary.sql
|  |  |– boundary.yaml
|  |  |– mapping.yaml
|  |– building
|  |  |– building.sql
|  |  |– building.yaml
|  |  |– mapping.yaml
|  |  |– update_building.sql
|  |– housenumber
|  |  |– housenumber.yaml
|  |  |– housenumber_centroid.sql
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |– landcover
|  |  |– landcover.sql
|  |  |– landcover.yaml
|  |  |– mapping.yaml
|  |– landuse
|  |  |– landuse.sql
|  |  |– landuse.yaml
|  |  |– mapping.yaml
|  |– mountain_peak
|  |  |– README.md
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– mountain_peak.yaml
|  |  |– update_peak_point.sql
|  |– park
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– park.yaml
|  |  |– update_park_polygon.sql
|  |– place
|  |  |– capital.sql
|  |  |– city.sql
|  |  |– island_rank.sql
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– place.yaml
|  |  |– types.sql
|  |  |– update_city_point.sql
|  |  |– update_continent_point.sql
|  |  |– update_country_point.sql
|  |  |– update_island_point.sql
|  |  |– update_island_polygon.sql
|  |  |– update_state_point.sql
|  |– poi
|  |  |– class.sql
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– poi.yaml
|  |  |– poi_stop_agg.sql
|  |  |– public_transport_stop_type.sql
|  |  |– update_poi_point.sql
|  |  `– update_poi_polygon.sql
|  |– transportation
|  |  |– class.sql
|  |  |– layer.sql
|  |  |– mapping.yaml
|  |  |– transportation.yaml
|  |  |– update_transportation_merge.sql
|  |– transportation_name
|  |  |– layer.sql
|  |  |– network_type.sql
|  |  |– transportation_name.yaml
|  |  |– update_route_member.sql
|  |  |– update_transportation_name.sql
|  |– water
|  |  |– mapping.yaml
|  |  |– update_water.sql
|  |  |– water.sql
|  |  |– water.yaml
|  |– water_name
|  |  |– mapping.yaml
|  |  |– update_marine_point.sql
|  |  |– update_water_lakeline.sql
|  |  |– update_water_point.sql
|  |  |– water_name.yaml
|  |– waterway
|     |– mapping.yaml
|     |– update_important_waterway.sql
|     |– update_waterway_linestring.sql
|     |– waterway.sql
|     |– waterway.yaml

まとめ

今回は、MBTiles作成のボトルネックを確認するための処理時間計測を行いました。
当初は、MBTilesを作成するために多くの時間を費やしていると想像していましたが、今回の計測でPOIがらみのデータ加工に時間を費やしていることがわかりました。
SQLスクリプトを眺めると、主にストアードファンクションを使って複雑な処理を行っているように見えます。
一般的にRDBMSは、UPDATE文を発行するとディスクIOが多発して性能を落とすので、性能があまり良くないのはPOIデータに対するUPDATE文の発行なのだろうと思っています。今のところ。

次回以降は、buildディレクトリ配下のSQLスクリプトの内容を確認していこうと思います。