チューニンガソン 2013 参加記

> 第5弾! いろいろチューニングしてパフォーマンスを競うバトルイベント「チューニンガソン」1月19日(土) 開催! #tuningathon on Zusaar
> http://www.zusaar.com/event/467012

イベント参加してました.

## 当日の流れ

遅刻!

歩きながら レギュレーション読む.
MySQL

ついて早速ネットつないで ssh して環境確認.

Server version: 5.5.29 MySQL Community Server (GPL)

5.5 か.なら別にバージョンあげなくてもいいかな(前回とか自前で入れて失敗したような気がする)


最初のベンチ

$ python tgbench_mysql.py 127.0.0.1
0.000352144241333
30.6134359837
40.169380188
77.9782850742
117.878194094
156.010751963
156.010817051

クエリの実行時間らしく,それぞれの値が小さいほど良い.で,最後の値が実際に評価される値らしい.

まあクエリを見てみないことにはなんにもならないので スクリプトを見てクエリ見る.

            RESET QUERY CACHE;

クエリキャッシュ削除してるからとりあえずクエリキャッシュがどーのとか言うアプローとはナシにしとくかな.

クエリ1こめ

            SELECT COUNT(*)
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
               AND rev_user = 0

クエリ2こめ

            SELECT COUNT(*)
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
               AND rev_user = 0
               AND page_touched > DATE_FORMAT(NOW() - INTERVAL 1 YEAR,'%Y0101000000')

クエリ3こめ

            SELECT page_id
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
               AND rev_user = 0
          ORDER BY page_touched DESC
             LIMIT 10

クエリ4こめ

            SELECT rev_user,count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
          GROUP BY rev_user
          ORDER BY c DESC

クエリ5こめ

            SELECT SUBSTRING(rev_timestamp,1,6),count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
               GROUP BY SUBSTRING(rev_timestamp,1,6)
          ORDER BY c DESC


なるほど.
page と revision のテーブルだけなんかな.
とりあえず page と revision の show create table を見ておく.(記録してない)
とりあえず自分が動かしてる DB サーバの設定を見ながら調整してみる.

設定内容

key_buffer = 16M

実行結果

$ python tgbench_mysql.py 127.0.0.1
0.000257015228271
9.65802717209
19.0670251846
48.2355220318
85.3107271194
123.534044027
123.534102201

いろいろ結構早くなった.


ストレージエンジンが innodb だったので.バッファ増やす.

設定内容

innodb_buffer_pool_size=1638M


実行結果

$ python tgbench_mysql.py 127.0.0.1
0.000259876251221
4.83838295937
5.74692988396
10.7054519653
18.0805239677
24.5209450722
24.5210080147


おー結構早くなった.
ここで xlarge のメモリ量 よく見たら 15G あるんじゃね ってことに気づいてガッツリ増やしてみた.(コレあとで気づいたら意味なかったけど)

設定内容

innodb_buffer_pool_size=12000M


実行結果

$ python tgbench_mysql.py 127.0.0.1
0.000226974487305
0.730866193771
1.55102205276
5.34630703926
11.1979050636
17.3137311935
17.3137981892


なるほど? mysql の再起動直後だと 23 になるけど 一回動かした後だと 17.3 になるっぽい.(さっきの innodb_buffer_pool_size 増やした意味ない)
なんで二回目で早くなるかは調査してないけど,今後は二回目の計測を表示する。 


MEMORY ストレージエンジン使うといいんかな.
git いれて $HOME/data 以下 を git 管理に追加して data/tables.sql をいじってみる.
ん?

ERROR 1163 (42000) at line 219: The used table type doesn't support BLOB/TEXT columns

https://dev.mysql.com/doc/refman/5.1/ja/memory-storage-engine.html
> MEMORY テーブルは BLOB や TEXT カラムをサポートしません。

まじかー.諦める.

group by を早くする

sort_buffer_size=4M
$ python tgbench_mysql.py 127.0.0.1
0.000229835510254
0.732585906982
1.54724097252
5.77867388725
11.4459989071
17.6631388664
17.6632049084

かわらんふやす

sort_buffer_size=1024M
$ python tgbench_mysql.py 127.0.0.1
0.000241041183472
0.72815990448
1.53270101547
5.81017899513
11.553994894
17.8257920742
17.8258590698


インデックス削除してみた( len は使ってない)

mysql> alter table page drop index page_redirect_namespace_len;
mysql> alter table revision drop index page_user_timestamp;
mysql> alter table revision drop index usertext_timestamp;


最後2つのクエリがそれぞれ 6 s ぐらい使ってるんだよなー

            SELECT rev_user,count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
          GROUP BY rev_user
          ORDER BY c DESC
            SELECT SUBSTRING(rev_timestamp,1,6),count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
               GROUP BY SUBSTRING(rev_timestamp,1,6)
          ORDER BY c DESC

それぞれ分解して実行してみる.

とりあえず全開で.

            SELECT rev_user,count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
          GROUP BY rev_user
          ORDER BY c DESC
39434 rows in set (5.55 sec)

order by 削除

            SELECT rev_user,count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
          GROUP BY rev_user
39434 rows in set (5.54 sec)

group by 削除

            SELECT rev_user,count(*) AS c
              FROM page
              JOIN revision
                ON page_id = rev_page
             WHERE page_is_redirect = 0
               AND page_namespace = 0
   1 row in set (4.35 sec)

4s かー.これ高速化してみるか. たぶん count(*) で使うインデックスを小さいものにすると早くなりそうな気がする page_is_redirect が一番小さいかな tinyint(4) だからだけどあんまりかわらんかった.

ここでクエリをもう一度よく見ると3こめのクエリが若干遅い.これをみると order by やってる場所あるのでこれのインデックスはる

          ORDER BY page_touched DESC

ここでいろいろインデックス削除したり追加したりしてた(記録してない).
いろいろやってたら終了.

## 結果

順位のページをこっそり見たら 29 位だった.最初 1 時間ぐらいの内容が知識的に限界だったけどいろいろ検証できたのですごく勉強になった.

29 nise_nabe 13.4976408482

## 感想

前回までは Web アプリっぽかったけど,今回は DB (MySQL)ということで,中途半端な知識でのそこそこガッツリ減った感覚があってとても楽しかったです.

最終的な設定

key_buffer = 16M
key_buffer_size = 1024M
innodb_buffer_pool_size=10000M
max_connection=3
innodb_flush_log_at_trx_commit=0
join_buffer_size=0
sort_buffer=16M
sort_buffer_size=1024M