Successfully reported this slideshow.
Your SlideShare is downloading. ×

バス停検索サービスで周辺バス停 を取得する重いSQLの改善

Ad

db tech showcase
ONLINE 2020
バス停検索サービスで周辺バス停
を取得する重いSQLの改善
2020年12⽉10⽇
バス停検索運営 ⻘い森ウェブ⼯房 代表 福⽥匡彦
バス停検索 https://buste.in/ 20...

Ad

・⻘森県⼋⼾市出⾝(45歳 独⾝)
・東京で8年間ほど会社員ウェブプログラマー
・主な職歴
2000年 雑誌「東京ウォー◯ー」のウェブサイト運営会社へ常駐
(PerlのCGI作ってました)
・2004年 ゲーム会社「元気」勤務
(この頃にPHP...

Ad

「バス停検索」は、⻘い森ウェブ⼯房(⻘森県⼋⼾市)が
運営する無料サービス。
※2011年6⽉に公開
URL https://buste.in/
http://バス停検索.jp/ でも可
全国のバス停が探せる
「バス停検索」とは︖
バス停検索 ...

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Check these out next

1 of 24 Ad
1 of 24 Ad

バス停検索サービスで周辺バス停 を取得する重いSQLの改善

Download to read offline

「db tech showcase ONLINE 2020」で2020年12月10日開催のセッション「地球上の位置をデータで表現!位置情報を活用したアプリ開発ユーザー事例 (MySQL)」内での発表資料です。

「db tech showcase ONLINE 2020」で2020年12月10日開催のセッション「地球上の位置をデータで表現!位置情報を活用したアプリ開発ユーザー事例 (MySQL)」内での発表資料です。

More Related Content

バス停検索サービスで周辺バス停 を取得する重いSQLの改善

  1. 1. db tech showcase ONLINE 2020 バス停検索サービスで周辺バス停 を取得する重いSQLの改善 2020年12⽉10⽇ バス停検索運営 ⻘い森ウェブ⼯房 代表 福⽥匡彦 バス停検索 https://buste.in/ 2020/12/101
  2. 2. ・⻘森県⼋⼾市出⾝(45歳 独⾝) ・東京で8年間ほど会社員ウェブプログラマー ・主な職歴 2000年 雑誌「東京ウォー◯ー」のウェブサイト運営会社へ常駐 (PerlのCGI作ってました) ・2004年 ゲーム会社「元気」勤務 (この頃にPHPやMySQLを使い始めた) ・2008年 地元⼋⼾市へUターンし、⻘い森ウェブ⼯房を開業 ・2011年6⽉から全国対応「バス停検索」サービスを運営中 URL https://buste.in/ 〜このあたりからバスが趣味から仕事になり始める〜 ・標準的なバス情報フォーマット広め隊メンバーとなる 福⽥の⾃⼰紹介 バス停検索 https://buste.in/ 2020/12/102
  3. 3. 「バス停検索」は、⻘い森ウェブ⼯房(⻘森県⼋⼾市)が 運営する無料サービス。 ※2011年6⽉に公開 URL https://buste.in/ http://バス停検索.jp/ でも可 全国のバス停が探せる 「バス停検索」とは︖ バス停検索 検索 バス停検索 https://buste.in/ 2020/12/103
  4. 4. * 以前からバス停を探せるサービスを作りたかったが、個⼈で バス停データ収集は困難である。(⼋⼾市内で断念…) * 地図上からバス停を探せれば便利なのにという想い。 * 2011年4⽉に国⼟交通省から国⼟数値情報「バス停留所デー タ」が⼀般公開された事。 * まさに夢のようなデータ、それが国⼟数値情報だった。 * たとえ、情報の正確度が低くとも、無料でバス停を探したい 需要があると確信したため。 ぶっちゃけ、⾃分がこういうサービス欲しかったのです(笑) こうして、趣味から始めたサイトだが、徐々に仕事となってい ます。 当サービスを始めるきっかけ バス停検索 https://buste.in/ 2020/12/104
  5. 5. 完全無料 (広告掲載による収益モデル) * 地図上やGPSで取得した現在位置からバス停を探せる * 公式サイトや有⽤な関連サイト等へリンクを掲載 * 全国の仲間で⽇々データ更新を⾏っている 運営のこだわり * 完全無料サービスの継続 * ブックマークできるURLにする(後ですぐ⾒られる) * データ更新等に協⼒してくれる⽅は、無償ではなく有 償ボランティア的に参加してもらう (趣味に没頭して報酬が稼げるって良いなと思うから) バス停検索の特徴 バス停検索 https://buste.in/ 2020/12/105
  6. 6. ・VPS1台で稼働中 (当初は共有レンタルサーバでアクセス増により乗換) ・Webサーバ Apache 2.x系 ・SSL(https)対応済み ・使⽤データベース MySQL 8.0系 ・主な使⽤⾔語 PHP、JavaScript ・使⽤フレームワーク CakePHP ・地図 OpenStreetMap+leaflet(Google Maps APIから切替え) PHPとMySQLが好きです︕ バス停検索の動作環境 バス停検索 https://buste.in/ 2020/12/106
  7. 7. 全国の有志により、⼀部地域では⽇々データ更新が ⾏われています。 しかし、26万件以上もバス停データ&路線データが あると、それ以外の地域は⼿付かずで正確度の低い データが多くあります。 路線バスのダイヤ改正は、全国いつもどこかで⾏わ れていますから、追いつきません… (皆さん本業もあり、多くの時間をかけるのは難しい もの) バス停データは更新してる︖ バス停検索 https://buste.in/ 2020/12/107
  8. 8. バス停検索のバス停データ件数 ・国⼟数値情報を元に作成した初期データ(2011年) 約25万件 ◯新規追加データ ↑約2万6千件 バス会社、⾃治体等の提供データ、協⼒者による追加 (うち、直近1年間で約2千9百件追加) △廃⽌や重複等のデータ ↓約1万3千件 ◎合計バス停データ数 約26万3千件 ⽇本のどこかで増えるバス停もあれば、消えていくバス停もあるのです。 (データ件数は2020年11⽉現在) バス停データ追加の成果 バス停検索 https://buste.in/ 2020/12/108 0 5000 10000 15000 20000 25000 30000 +新規追加 −廃止等 増減状況 +新規追加 −廃止等
  9. 9. ここ数年で次々と全国各地で公開されているGTFS(標準 的なバス情報フォーマット)形式のオープンデータを活⽤ して、もっと正確なバス停情報を提供できるのではない か︖と考えました。 主な活⽤⽅法 * GTFSと⼀緒に地図表⽰ バス停検索データとGTFSデータをまとめて地図へ⼀緒 に表⽰させる * マッチングして差分を修正 バス停検索データとGTFSデータのマッチングをして、 差分の修正を⾏う 正確度を向上するには︖ バス停検索 https://buste.in/ 2020/12/109
  10. 10. 「GTFS」という名前を聞いたことありますか︖ 「GTFS(General Transit Feed Specification)」は、Googleが 公開して世界標準となった公共交通情報⽤フォーマットです。 ⽇本の路線バス事情へ合わせてアレンジしたものが「標準的なバス情報 フォーマット(通称︓GTFS-JP)」です。 もし、Googleマップへ⾃社のバス情報を掲載してもらうには、この形式で のデータ作成が必要です。 なお、「GTFS」はバス停、時刻表や路線経路などの「静的」な情報が対 象で、運⾏状況などの「動的」な情報は、「GTFSリアルタイム(GTFS- RT)」という別なフォーマットがあります。 標準的なバス情報フォーマット広め隊 https://www.gtfs.jp/ 標準的なバス情報フォーマット (GTFS-JP)とは︖ バス停検索 https://buste.in/ 2020/12/1010
  11. 11. ⽇本国内のGTFS作成&オープンデータ化は、まだ発展途上で、三⼤都市圏で も寂しい状況。 実はGTFS界隈では、群⾺県、⼭梨県、富⼭県、岡⼭県、佐賀県が先進事例で す︕(県内の多くの路線バスへ対応済み) 昨年は東京都交通局、今年は横浜市交通局でも 公開され、ついに⾸都圏でも増えています︕ 2020年11⽉現在では全国「286事業者」 も公開されています︕ (いくつかの定期旅客航路、鉄道データも含む) GTFSデータは全国出てるの︖ バス停検索 https://buste.in/ 2020/12/1011 (参考︓https://home.csis.u-tokyo.ac.jp/~nishizawa/gtfs/ 2020年11⽉作成)
  12. 12. しかし、周辺にあるバス停を探すSQLが結構重いです… 例えば、三⾓関数を使⽤した↓こういうSQLを使っていて、問題はイ ンデックスが効かず、取得レコード数が多い程に重さを実感します。 (WHERE句が無いから︖) 実はSQL実⾏時に「0.数秒」かかったりします… ※「35.685」が緯度、「139.762」が経度を表し、半径2kmのバス停を取得。 SELECT id, name, lat, lng, ( 6371 * acos( cos( radians(35.685) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(139.762) ) + sin( radians(35.685) ) * sin( radians( lat ) ) ) ) AS distance FROM tables HAVING distance < 2 今後オープンデータを活⽤する程に、このSQLの実⾏頻度や取得する レコード数も増えていき、さらなるサーバ負荷が⼼配です。 ↓ 解決⽅法はあるのか︖ DB関連の悩み バス停検索 https://buste.in/ 2020/12/1012
  13. 13. 重いSQLを使う理由 2020/12/10バス停検索 https://buste.in/ 13 広範囲でバス停が表⽰されると、分布状況や地域のバス路線網を把握しやすく 便利と思うから。 (他社サービスでは、地図中⼼から数kmまでのバス停表⽰が多い) 右画像︓⼋⼾市周辺バス停(緑マーカー)の表⽰例→ (バス停が少ない所は⼈⼝密度も低い傾向が⾒える) ★暫定的な解決⽅法 各バス停位置基準で約3kmまでの周辺バス停データを 事前に静的データとしてDBへ保存し、それを毎回 優先的に読み込む。 △デメリット * 計1,500万レコード以上となる(負荷軽減で6テーブルへ分割保存) * 静的データ⽣成には24時間以上かかり、最新データの反映までに 時間がかかる(※⽣成は⾼負荷のため別サーバ上で作成)
  14. 14. ・MySQLでも「GEOMETRY型」を使えば、同様に速くなると 知る MySQLはGIS的な⽤途にまだ不向きだと思いこんでました… ↓ ・しかし、MySQL5.7以降でないと、便利な関数が実装されて おらず微妙みたい 当時はMySQL5.5を使⽤中でバージョンアップが必要 ↓ ・最新版は不安もありMySQL5.7へのバージョンアップを想定 最新バージョンは旧来からの仕様変更や不安定で⼤変そうな印 象を感じる派なのです 良い解決⽅法は︖ バス停検索 https://buste.in/ 2020/12/1014
  15. 15. そんな時、MySQLにとても詳しい坂井⽒(⽇本 MySQLユーザ会の副代表、@sakaik)とちょうどイ ベントで再会した時に相談してみる ↓ 「MySQL8.0で初めて丸い地球上の位置を表現でき るようになった」と聞き、 GIS関数群の充実と共に ⼤きな決め⼿となる ↓ 迷った結果、思い切ってMySQL8.0へ決定する︕ MySQL8.0へ決定 バス停検索 https://buste.in/ 2020/12/1015
  16. 16. カラム名 データ型 照合順序 NULL その他 役割 id int(11) いいえ AUTO_INCREMENT ユニークID bustei_id varchar(10) utf8_general_ci いいえ バス停固有ID name varchar(60) utf8_general_ci いいえ バス停名称 pref_id tinyint(4) はい 都道府県ID lat float(10,6) いいえ 緯度 lng float(10,6) いいえ 経度 created datetime はい データ追加⽇時 2020/12/10バス停検索 https://buste.in/ 16 従来DBテーブル構造 補⾜ 緯度経度は、本来float型では無くdouble型が良い事に後で 気づいた… (float型は⼩数点以下が丸められやすいため) バス停データ保存⽤のテーブル構造を抜粋したもの。
  17. 17. カラム名 データ型 照合順序 NULL その他 役割 id int(11) いいえ AUTO_INCREMENT ユニークID bustei_id varchar(10) utf8_general_ci いいえ バス停固有ID name varchar(60) utf8_general_ci いいえ バス停名称 pref_id tinyint(4) はい 都道府県ID lat float(10,6) いいえ 緯度 lng float(10,6) いいえ 経度 lat_lng point いいえ 緯度経度 created datetime はい データ追加⽇時 2020/12/10バス停検索 https://buste.in/ 17 新DBテーブル構造 補⾜ 結局GEOMETRY型ではなく、地点情報に特化したPOINT型を採⽤ 既存プログラム修正を減らすため、データ更新は「lat」と「lng」、 「lat_lng」の両⽅へ⾏い、 どちらも読み出し可能とする バス停データ保存⽤の新テーブル構造を抜粋したもの。
  18. 18. * POINT型のカラム「lat_lng」を新たに⽤意する 今回は緯度経度のみを⼊れるため、GEOMETRY型よりも地 点情報へ特化したPOINT型が適していると判断 * POINT型のカラムへインデックスを作るには 「NOT NULL」とする必要あり → 「NOT NULL」へ変更して解消 * SPATIALインデックスを作成 ※「SPATIAL」は空間データ⽤のインデックス。 ALTER TABLE tables ADD SPATIAL index_lat_lng (lat_lng); 変更した流れ(1) バス停検索 https://buste.in/ 2020/12/1018
  19. 19. * SELECT⽂を実⾏するが、まだインデックスが効いていない様⼦ →どうやらMySQL8.0よりSPATIALインデックスではSRIDの設定 が必須となった模様 * SRIDを設定する際に、ストレージエンジンがMyISAMではエラー となる →該当テーブルのストレージエンジンをInnoDBへと変える * SRID は「4326」と設定して解決 OSMの地図表⽰をさせる使い⽅にはこの数値が良い模様 例では「NOT NULL」も合わせて実⾏ ALTER TABLE tables MODIFY lat_lng POINT NOT NULL SRID 4326; 変更した流れ(2) バス停検索 https://buste.in/ 2020/12/1019
  20. 20. * まだインデックスが効いていない様⼦ SRIDがうまく設定されていない可能性を疑うが、現在のSRIDを確認する術 が不明 坂井⽒へ再度相談したところ、下記のSQLで確認出来ました。 SHOW CREATE TABLE tables; 実⾏すると、本来なら下記のような結果が得られます。 SRIDが「4326」であることがわかる。 ・該当カラム部分のみを抜粋 `lat_lng` point NOT NULL /*!80003 SRID 4326 */, * 結果、この時はSRIDが設定されておらず、⼀度インデックス削除後、再度 作成を⾏う確認すると、インデックスが適⽤され⾼速化されました︕ 原因はカラム設定変更やインデックスの追加、削除を何度も⾏った事で、ど こかで設定抜けが起きていたと予想しています(汗) 変更した流れ(3) バス停検索 https://buste.in/ 2020/12/1020
  21. 21. 管理画⾯にはフレームワークのCakePHP2.xを使っていますが、標準では 「geometry」型カラムのデータ追加、更新は出来ません。 どうにか、「ST_GeomFromText」関数を組み込んで解決できました。 (UPDATE⽂のSET句に相当する部分を変更) ・従来のカラム⽤ $updatefield = array( ʻlatʼ => $lat, // 緯度 ʻlngʼ => $lng // 経度 ); ・ POINT型カラム対応版 $updatefield = array( ʻlat_lngʼ => “ST_GeomFromText(ʻPOINT(”.$lat.“ ”.$lng.“)ʼ ,4326)” // 緯度経度 ); PHPで困ったこと バス停検索 https://buste.in/ 2020/12/1021
  22. 22. POINT型を使⽤し⾼速化したSQLを坂井⽒から多⼤なアドバイスを頂きつつ 作成しました。(⾃⼒では思うように作れず断念) SELECT id, name, ST_AsText(lat_lng) as p , ST_Latitude(lat_lng) as lat, ST_Longitude(lat_lng) as lng, (ST_Distance_Sphere(ST_GeomFromText('POINT(35.685 139.762)', 4326), lat_lng) / 1000) as distance FROM tables WHERE ST_Within( lat_lng, ST_SRID( ST_Buffer( ST_GeomFromText('POINT(139.762 35.685)'), 1820 * 1.2 * 180.0 / 3.141592653589793 / 6378137.0 ), 4326) ) HAVING distance < 1820 ORDER BY distance; 関数を多数駆使するため、予想よりも複雑なSQLとなりました。 改善の結果は、三⾓関数を使⽤した従来のSQLよりも、実⾏時間が数分の⼀と⾼速化出来 ました。 ※「35.685」が緯度、「139.762」が経度、「1820」(2km前後)が距離を表す。 ⾼速化したSQL バス停検索 https://buste.in/ 2020/12/1022
  23. 23. * GIS関連ならMySQL5.7よりも8.0がオススメ︕ MySQL8.0で初めて丸い地球上の位置を表現でき るようになったから * MySQL8.0でSPATIALインデックスを効かすには、 SRID指定が必須となったが、 8.0向けの情報は少 なく、SRID を使わないMySQL5.7向けの実⾏例が 多く注意が必要 * 同様にSRIDを指定したSELECT⽂のSQL例も少な く苦戦した * POINT型を使⽤したSQLが多くの関数使⽤で複雑 になりがち まとめ バス停検索 https://buste.in/ 2020/12/1023
  24. 24. * ⻘い森ウェブ⼯房 代表 福⽥匡彦 * ご質問やお問い合わせは下記へ URL: https://8nohe.info/work/ Twitter @8nohe * 標準的なバス情報フォーマット広め隊 URL: https://www.gtfs.jp/ 2020年12⽉10⽇ ご清聴ありがとうございました バス停検索 https://buste.in/ 2020/12/1024

×