スマイルゼミの裏側(db編)
TRANSCRIPT
![Page 1: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/1.jpg)
© 2016 JustSystems Corporation.
スマイルゼミの裏側~データベース編~
(株)ジャストシステムILS 事業部開発部
菅井友之
![Page 2: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/2.jpg)
© 2016 JustSystems Corporation.
• スマイルゼミ中学生コース– サーバー担当
• スマイルゼミ小学生コース、中学生コースの立ち上げ– サーバー主担当として参加
• 主に Tomcat 上で動いて PostgreSQL を使うアプリケーションをやっています。
自己紹介
![Page 3: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/3.jpg)
© 2016 JustSystems Corporation.
スマイルゼミでやらかしてしまった話
( DB 的な意味で)
![Page 4: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/4.jpg)
© 2016 JustSystems Corporation.
スマイルゼミでやらかしてしまった話
( DB 的な意味で)PostgreSQL 9.3
![Page 5: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/5.jpg)
© 2016 JustSystems Corporation.
その前に
![Page 6: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/6.jpg)
© 2016 JustSystems Corporation.
スマイルゼミご存じですか?
![Page 7: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/7.jpg)
© 2016 JustSystems Corporation.
• 小中学生向けの家庭学習サービス• すべての学習がタブレット上で完結できる日本初のサー
ビス• 小中一貫で学べる唯一のタブレット教材
![Page 8: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/8.jpg)
© 2016 JustSystems Corporation.
facebook やってます
https://www.facebook.com/smile.zemi/
![Page 9: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/9.jpg)
© 2016 JustSystems Corporation.
小学生 中学生
ある一週間のアクセス状況
![Page 10: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/10.jpg)
© 2016 JustSystems Corporation.
• 小中学生向けのサービス• ユーザーは、日中学校に行っている
小学生 中学生
ある一週間のアクセス状況
![Page 11: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/11.jpg)
© 2016 JustSystems Corporation.
• 小中学生向けのサービス• ユーザーは、日中学校に行っている
平常時、日中の負荷は低い
小学生 中学生
![Page 12: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/12.jpg)
© 2016 JustSystems Corporation.
_人人人人人人人人人_> 突然の負荷上昇 < ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
![Page 13: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/13.jpg)
© 2016 JustSystems Corporation.
• 中学生 DB の朝の負荷であり、垂直に立ち上がっているので、バッチ処理
• グラフが変わる前の日に、 hotfix がリリースされている。• 調べてみると、 course_results で 1300 万行の seq.scan が大量
に発生している。
![Page 14: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/14.jpg)
© 2016 JustSystems Corporation.
CREATE VIEW AS study_log_memorycard_view ( WITH memorycard_info AS ( SELECT ... FROM course_results cr JOIN course_master cm ON cr.course_id AND cm.memory_card_info IS NOT NULL) (SELECT ... FROM memorycard_set_results msr JOIN memorycard_info ... WHERE ...) UNION ALL (SELECT ... FROM memorycard_set_results msr JOIN ... JOIN memorycard_info ... WHERE ... ))
![Page 15: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/15.jpg)
© 2016 JustSystems Corporation.
• 処理の内容は変えずに、 view を使うようにプログラムを変更していた。
![Page 16: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/16.jpg)
© 2016 JustSystems Corporation.
• 処理の内容は変えずに、 view を使うようにプログラムを変更していた。
• view を使わずに処理する場合には、オプティマイザが後続の WHERE を先に処理してくれていたのだろう
![Page 17: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/17.jpg)
© 2016 JustSystems Corporation.
• 処理の内容は変えずに、 view を使うようにプログラムを変更していた。
• view を使わずに処理する場合には、オプティマイザが後続の WHERE を先に処理してくれていたのだろう
• view を使ってしまったために、 course_results が絞り込まれずに含まれてしまう。
![Page 18: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/18.jpg)
© 2016 JustSystems Corporation.
CREATE VIEW AS study_log_memorycard_view ( WITH memorycard_info AS ( SELECT ... FROM course_results cr JOIN course_master cm ON cr.course_id AND cm.memory_card_info IS NOT NULL) (SELECT ... FROM memorycard_set_results msr JOIN memorycard_info ... WHERE ...) UNION ALL (SELECT ... FROM memorycard_set_results msr JOIN ... JOIN memorycard_info ... WHERE ... ))
![Page 19: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/19.jpg)
© 2016 JustSystems Corporation.
• 処理の内容は変えずに、 view を使うようにプログラムを変更していた。
• view を使わずに処理する場合には、オプティマイザが後続の WHERE を先に処理してくれていたのだろう
• view を使ってしまったために、 course_results が絞り込まれずに含まれてしまう。
• さらに、ユーザーごとに view に対するSELECT をしている。– 長時間の高負荷状態に
![Page 20: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/20.jpg)
© 2016 JustSystems Corporation.
対策
![Page 21: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/21.jpg)
© 2016 JustSystems Corporation.
• 前日の学習結果を集計する処理なので、 view 定義の段階で学習日で絞り込むことにした
• view 定義の各 SELECT 文に以下の絞り込み条件を追加
対策
![Page 22: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/22.jpg)
© 2016 JustSystems Corporation.
• 前日の学習結果を集計する処理なので、 view 定義の段階で学習日で絞り込むことにした
• view 定義の各 SELECT 文に以下の絞り込み条件を追加
対策
study_end > (now() - '2 days'::interval)
![Page 23: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/23.jpg)
© 2016 JustSystems Corporation.
• 前日の学習結果を集計する処理なので、 view 定義の段階で学習日で絞り込むことにした
• view 定義の各 SELECT 文に以下の絞り込み条件を追加
• 幸い、他の処理では使っていない view だったので、同名のまますぐに定義変更できた。
対策
study_end > (now() - '2 days'::interval)
![Page 24: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/24.jpg)
© 2016 JustSystems Corporation.
![Page 25: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/25.jpg)
© 2016 JustSystems Corporation.
他の事例
![Page 26: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/26.jpg)
© 2016 JustSystems Corporation.
2013 年 12 月小学生向けみまもるトーク
拡張され続けるサービス
![Page 27: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/27.jpg)
© 2016 JustSystems Corporation.
2013 年 12 月小学生向けみまもるトーク
拡張され続けるサービス
2014 年 11 月中学生向けみまもるトーク
![Page 28: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/28.jpg)
© 2016 JustSystems Corporation.
小学生向けに作ったトーク機能に、中学生を参加させる
![Page 29: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/29.jpg)
© 2016 JustSystems Corporation.
• あるトークグループに参加しているユーザー( talker )の一覧を取得する SQL 文
• - talker は、親、小学生、中学生、その他(親が招待した人)があり、それぞれ別体系の id で管理されている。
SELECT talkers.* FROM talkers LEFT OUTER JOIN accounts ON talkers.account_id = accounts.idWHERE (((accounts.parent_id = xxxxxxxx OR child_id = xxxxxxxx ) OR jh_child_id = xxxxxxxx ) OR account_id = xxxxxxxx )
![Page 30: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/30.jpg)
© 2016 JustSystems Corporation.
• 中学生が増えたのでこの条件が増えた• OR 条件が追加されたことにより、実行計
画がくるってしまって、 Seq Scan on accounts 、 Seq Scan on talkers が発生
• index はあるのに使ってもらえない。
OR jh_child_id = xxxxxxxx
![Page 31: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/31.jpg)
© 2016 JustSystems Corporation.
対策
![Page 32: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/32.jpg)
© 2016 JustSystems Corporation.
対策SELECT talkers.* FROM talkers LEFT OUTER JOIN accounts ON talkers.account_id = accounts.id WHERE (accounts.parent_id = xxxxxxxx)UNIONSELECT talkers.* FROM talkers WHERE (child_id = xxxxxxxx)UNIONSELECT talkers.* FROM talkers WHERE (jh_child_id = xxxxxxxx )UNIONSELECT talkers.* FROM talkers WHERE (account_id = xxxxxxxx ) ORDER BY id;
![Page 33: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/33.jpg)
© 2016 JustSystems Corporation.
• Index scan ですむ単純 SQL にして結果を UNION すると 1000-10000 倍速になった!
– (というよりは、ロジック変更で 1000 倍遅くなっていた)
対策SELECT talkers.* FROM talkers LEFT OUTER JOIN accounts ON talkers.account_id = accounts.id WHERE (accounts.parent_id = xxxxxxxx)UNIONSELECT talkers.* FROM talkers WHERE (child_id = xxxxxxxx)UNIONSELECT talkers.* FROM talkers WHERE (jh_child_id = xxxxxxxx )UNIONSELECT talkers.* FROM talkers WHERE (account_id = xxxxxxxx ) ORDER BY id;
![Page 34: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/34.jpg)
© 2016 JustSystems Corporation.
• UNION が あるところを変更するときは慎重に– UNION していいのは、中間処理結果が十分
に小さいとわかっている場合のみ。– 特に view の中で UNION するのは危険
• 中間テーブルが十分に小さく、素早く、作れるところでは UNION はとても有効!
まとめ
![Page 35: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/35.jpg)
© 2016 JustSystems Corporation.
スマイルゼミを一緒に育てる人、募集しています。
![Page 36: スマイルゼミの裏側(db編)](https://reader035.vdocuments.pub/reader035/viewer/2022062905/586e8d7b1a28aba0038b88d7/html5/thumbnails/36.jpg)