SQL のパフォーマンスを改善する方法

kisyaman 74views 更新:2017年8月23日

たぶん今できるのはクエリの最適化。 explain をよむ。

パフォーマンスを良くしたい いくつか方法がある。 スキーマを変える? クエリを変える? クエリを変えるのはお手軽。(比較的)影響がないし。

そのためには、explainを理解する必要がある。(なぜ?) クエリを最適化するには、まずEXPLAINで実行計画をチェックする必要があるからさ。

クエリを最適化するということは、 * 書き換える前と後でクエリの実行結果が同じになる * EXPLAINがよりよい実行計画を表示する であるらしい。

そのためには、explainを理解する必要がある(重要なことなので2回)。 以下のような出力が得られる。

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,PRIMARY,t1,ALL,"room_id,eip_t_message_room_member_target_user_id,eip_t_message_room_member_user_id_target_user_id",NULL,NULL,NULL,6,"Using where; Using temporary; Using filesort"
1,PRIMARY,t2,ALL,PRIMARY,NULL,NULL,NULL,4,"Using where; Using join buffer (Block Nested Loop)"
1,PRIMARY,t4,eq_ref,PRIMARY,PRIMARY,4,org0000009.t1.target_user_id,1,NULL
2,"DEPENDENT SUBQUERY",t3,ref,"eip_t_message_read_index1,eip_t_message_read_index2",eip_t_message_read_index1,14,"org0000009.t2.room_id,const,const",1,"Using where; Using index"

実行計画は内部的にはツリーで表現されているらしい。どうみてもテーブルなんですがそれは…。どういうことなんでしょう。(ツリーと聞いて紙とペンを用意する)しかも、そのツリーは「見ると各テーブルへのアクセスが理解できるようになるもの」らしい。

ちなみに、ちゃんと「execution plan」というのが表示されている。ただ、下のクエリだと表示できなかった。

explain select t2.room_id, t2.name, t2.has_photo, t2.photo_modified, t4.user_id, t4.last_name, t4.first_name, t4.has_photo as user_has_photo, t4.photo_modified as user_photo_modified, t2.auto_name, t2.room_type, t2.last_message, last_update_date, (select count(*) from eip_t_message_read t3 where t3.room_id = t2.room_id and t3.user_id = 4 and t3.is_read =’F’) as unread from eip_t_message_room_member t1, eip_t_message_room t2, turbine_user t4 where t1.user_id = 4 and t1.room_id = t2.room_id and t1.target_user_id = t4.user_id order by t2.last_update_date desc;

このクエリだと表示された。 SELECT t0.USER_ID, t0.GROUP_ID, t0.ROLE_ID, t0.ID FROM turbine_user_group_role t0 WHERE t0.USER_ID = 4;

これもしっかり表示される。 確かに木だ。

image

select t1.message_id, t1.room_id, t1.user_id, t1.message, t1.create_date, t1.member_count, t2.last_name, t2.first_name, t2.has_photo, t2.photo_modified, (select count(*) from eip_t_message_read t3 where t3.message_id = t1.message_id and t3.room_id = t1.room_id and t3.is_read = ‘F’) as unread from eip_t_message t1, turbine_user t2 where t1.user_id = t2.user_id and t1.room_id IN(3) order by t1.create_date desc limit 50

SQL のパフォーマンスを改善する方法

SQL のパフォーマンスを改善したいとなると、index を作成することで実現できる場合があるようなのですが、色々と問題もあるようです(闇雲インデックス)。 取りうる手段としては、今回のチケットで行われていたように、測定(Measure)、解析(Explain)、指名(Nomiante)、テスト(Test)、最適化(Optimize)、再構築(Rebuild)、の手順を踏むと良いそうです。頭文字で MENTOR で覚えると良いとか。

測定(Measure)

まずチケットで改善されているかを確かめるために、master でのパフォーマンスを調べて、対応していただいたチケットとのパフォーマンスと比較しようと思いました。ORMを使っていて直接はクエリが見えないので、実行されたsql文を監視する特定の箇所のSQLログを確認するためにやったこと(訂正)Aipoのログ出力レベルを変えるを参考に Cayenne で作成されたクエリを見えるようにして、RDBMS に入れて確かめてみます。

次回以降、更新していきます。 (コメントアウトしたらレイアウトが崩れてしまいました。)

メモ

ハックノートのロゴの書体かわいい

こちらもお役に立つかもしれません