前提
Linux + MySQL
本文
アプリの初回アクセスが遅い、といった事象を社内/手元で再現テストする場合、DBのキャッシュ (特にバッファプール/バッファキャッシュ) を回避したいケースがあります
MySQLでは手動キャッシュクリア方法がありませんが、以下パラメータを指定してMySQL再起動後、常時キャッシュミス状態にできました
- innodb_buffer_pool_size=10M
- innodb_flush_method=O_DIRECT
docker-compose.ymlの場合
command:
- --innodb_buffer_pool_size=10M
- --innodb_flush_method=O_DIRECT
innodb_buffer_pool_size
バッファプールのサイズを指定するパラメータです
上記では10MBとしていますが、テスト対象のテーブルサイズの10%を切るような値で設定すると良いのではと思います
innodb_flush_method
↓生成AIでの説明です
innodb_flush_method は、MySQL(InnoDB)が「データファイル」と「ログファイル」をメモリ(バッファプール)から物理ディスクへどのように書き出すかという「経路」を定義する設定です。
この設定一つで、OSのキャッシュをどう扱うかが決まり、パフォーマンスとデータの安全性に直結します。
1. 主な設定値と動作の違い
Linux環境で主に使用される3つの設定値の違いをまとめます。
fdatasync(デフォルト)
-
動作: 書き込み時に
write()システムコールを使い、最後にfsync()(またはfdatasync())を呼んでディスクへの同期を保証します。 - 特徴: 「二重キャッシュ」が発生します。データが「InnoDBバッファプール」と「OSのページキャッシュ」の両方に載るため、メモリが非効率です。
O_DIRECT(推奨)
-
動作: ファイルを開く際に
O_DIRECTフラグを使用します。 - 特徴: OSのページキャッシュを完全にバイパスし、MySQLが直接ディスクとやり取りします。
- メリット: 二重キャッシュを回避でき、本番環境のデータベースサーバーでは最も一般的で安定した設定です。
O_DSYNC
- 動作: 書き込みのたびに、データとメタデータが物理ディスクに書き込まれるまで待機(同期)します。
- 特徴: 非常に厳格ですが、通常のディスク環境では書き込みのたびに待機が発生するため、パフォーマンスが大幅に低下することが多いです。
備考
innodb_buffer_pool_sizeのみ指定した場合、SELECT実行時の2~3回目まではディスクIOが発生しましたが(=キャッシュミス、iostatで確認)、4回目以降はバッファプールにキャッシュが載ってないにも関わらずディスクIOが発生しなくなりました
※バッファプールに特定テーブルのキャッシュがどのくらいあるか確認するSQL
SELECT
TABLE_NAME,
COUNT(*) AS total_pages,
ROUND(COUNT(*) * 16 / 1024, 2) AS cached_size_mb
FROM
information_schema.INNODB_BUFFER_PAGE
WHERE
TABLE_NAME = '`DB名`.`テーブル名`'
GROUP BY
TABLE_NAME;
出力例
+------------+-------------+----------------+
| TABLE_NAME | total_pages | cached_size_mb |
+------------+-------------+----------------+
| `db1`.`t1` | 6833 | 106.77 |
+------------+-------------+----------------+
そのためOSキャッシュを疑い調べたところ、innodb_flush_methodでの制御を発見し、O_DIRECTを設定すると、繰り返しSELECT文を実行してもディスクIOが発生 (=キャッシュミス) するようになりました
LinuxにインストールしたMySQLやdockerでは上記方法が使えますが、DBaaS (クラウドのMySQLマネージドサービス等) では各パラメータをユーザー側で設定可能かに依存しそうです