FAT47の底辺インフラ議事録

学んだことのメモ帳です

【今更】MySQLのInnoDB利用時のウォームアップ方法


Webサービスを運用していると、メンテナンス時にDBサーバの再起動が必要になるケースがいつか出てきます。
その際、再起動後そのままの状態でDBサーバをサービスインしてしまうと障害が起きてしまうことがあるので、
その対処法をメモしておきます。(InnoDB利用時編)


InnoDB buffer pool
MySQLのストレージエンジンであるInnoDBinnodb buffer poolに書込/読込データを一時的に保管していて、
定期的にibdataに書き込みを行うことでI/O性能を向上させています。
my.cnfのinnodb_buffer_pool_sizeでバッファサイズの指定ができるので、搭載メモリの50%〜70%ぐらいを指定します。


■ウォームアップ対象の洗い出し
buffer poolのサイズは有限なので、できるだけ多い回数呼び出されてるテーブルやINDEXをバッファに乗せておくと良いです。
洗い出す方法はなんでもいいのですが、今回はslow logを使って一定時間に呼ばれたクエリから集計します。

※クエリ記録中は負荷が増大するので、DBへの参照頻度を下げたりするなどしましょう。
また記録が終わったら忘れずにすぐ元の設定に戻しましょう。

全クエリの記録(MySQL5.1以上のみ)
my.cnfでslow logが有効になっているか確認

slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1

閾値を0秒にする(全クエリ記録)

mysql > set global long_query_time = 0;

適当な時間記録し続ける(1時間とか)

記録が終わったら戻す

mysql > set global long_query_time = 1;

mysqldumpslowを使って、呼び出し回数が多い順にソートする

mysqldumpslow -s c /var/lib/mysql/mysql-slow.log  | less

Count: 3034  Time=2.25s (6839s)  Lock=0.00s (0s)  Rows=70.2 (213050), hoge_user[hoge_user]@[10.*.*.*]
  select sum_c, total_sum_c from contest where c_id = N and user_id = N order by contest_id desc

Count: 1338  Time=2.46s (3287s)  Lock=0.00s (0s)  Rows=0.8 (1016), hoge_user[hoge_user]@[10.*.*.*]
  select gift_datetime from gift_history where user_id = N and type = N and i_id = N and a_type = N

■ウォームアップ用クエリの作成
呼び出し回数が多くてデータ件数が多いものを優先的にバッファの載せるようにしましょう。

テーブルデータ確認

show table status LIKE 'i_hogeuser' \G;
rowsとかを確認する。

テーブル構成確認

SHOW CREATE TABLE i_hogeuser \G;
→PRIMARY KEYとINDEX確認
 PRIMARY KEY (`user_id`,`p_type_id`),
  KEY `Index_i_hogeuser_request1` (`p_id`,`f_type`)

PRIMARY KEYつかって全データ読み込み

select count('user_id'),count('p_type_id') from i_hogeuser;

設定されたINDEX使って全読み込み

select count(p_id),count(f_type) from (select p_id,f_type from i_hogeuser order by p_id,f_type) as t1;

EXPLAINでINDEXが利用されているかチェック

mysql> explain select count(p_id),count(f_type) from (select p_id,f_type from i_hogeuser order by p_id,f_type) as t1;
+----+-------------+---------------------+-------+---------------+----------------------------+---------+------+-------+------------------------------+
| id | select_type | table               | type  | possible_keys | key                        | key_len | ref  | rows  | Extra                        |
+----+-------------+---------------------+-------+---------------+----------------------------+---------+------+-------+------------------------------+
|  1 | PRIMARY     | NULL                | NULL  | NULL          | NULL                       | NULL    | NULL |  NULL | Select tables optimized away |
|  2 | DERIVED     | i_hogeuser | index  | NULL  | Index_i_hogeuser_request1 | 16             | NULL    |      |  37527| Using index    
+----+-------------+---------------------+-------+---------------+----------------------------+---------+------+-------+------------------------------+
2 rows in set (0.02 sec)

といった手順でどんどんウォームアップクエリを作っていきます。



でも本当はめんどうくさいので、
PRIMARY KEYだけでクエリ生成してぶん投げます (ゝω・)

select concat('select ','SUM(',column_name,') from ', table_name,';') from information_schema.statistics where TABLE_SCHEMA = 'スキーマ名';
+------------------------------------------------------------------------------------------------+
| select SUM(collect_id) from t_user;                                                     |
| select SUM(history_id) from t_user_history;                                 |
| select SUM(vcomment_id) from t_comment;                                                        |
| select SUM(v_id) from t_visit;                                                                 |
| select SUM(touch_id) from touch;                                                               |
+------------------------------------------------------------------------------------------------+