InnoDB は、LRU アルゴリズムを厳密に使用するのではなく、バッファープールに読み取られたあと二度とアクセスされないデータの量を最小限に抑えるための手法を使用します。目標は、先読みやフルテーブルスキャンによって、その後アクセスされるかどうかわからない新しいブロックが読み取られた場合でも、頻繁にアクセスされるページ (「ホットページ」) が確実にバッファープール内に残るようにすることです。
新しく読み取られたブロックは、LRU リストの途中に挿入されます。新しく読み取られたページはすべて、デフォルトでは LRU リストの末尾から 3/8
にあたる場所に挿入されます。これらのページは、はじめてバッファープール内でアクセスされたときに、リストの前面 (直近で使用された端) に移動されます。そのため、アクセスされることがないページは決して LRU リストの前面の部分には移動されず、厳密な LRU アプローチの場合より早く「古く」なります。この配置では、LRU リストが 2 つのセグメントに分割されます。つまり、挿入ポイントの下流にあるページは「古い」とみなされ、LRU のエビクションの望ましい対象になります。
InnoDB バッファープールの内部動作や、その LRU の置き換えアルゴリズムの詳細については、セクション8.9.1「InnoDB バッファープール」を参照してください。
LRU リスト内の挿入ポイントを制御したり、InnoDB が同じ最適化をテーブルまたはインデックススキャンによってバッファープールに読み取られたブロックにも適用するかどうかを選択したりできます。構成パラメータ innodb_old_blocks_pct
は、LRU リスト内の「古い」ブロックの割合 (%) を制御します。innodb_old_blocks_pct
のデフォルト値は 37
であり、元の固定された 3/8 の比率に対応します。この値の範囲は、5
(バッファープール内の新しいページが非常に早く古くなります) から 95
(バッファープールの 5% しかホットページとして予約されないため、アルゴリズムがなじみのある LRU の方法に近くなります) までです。
バッファープールを先読みによって混乱した状態にならないように維持する最適化は、テーブルまたはインデックススキャンによる同様の問題も回避できます。これらのスキャンでは通常、データページはすばやく連続して数回アクセスされ、それ以降は二度とアクセスされません。構成パラメータ innodb_old_blocks_time
は、あるページにはじめてアクセスしたあと、そのページが LRU リストの前面 (直近で使用された端) に移動されることなくアクセス可能になっている時間ウィンドウ (ミリ秒単位) を指定します。MySQL 5.6.6 より前は、innodb_old_blocks_time
のデフォルト値は 0
であり、はじめてバッファープール内でアクセスされたときにページをバッファープールのリストの直近で使用された端に移動するという元の動作に対応します。この値を大きくすると、より多くのブロックがバッファープールから早く古くなる可能性があります。MySQL 5.6.6 の時点で、innodb_old_blocks_time
のデフォルト値は、標準でのパフォーマンスを向上させるために 1000
に増やされました。
innodb_old_blocks_pct
と innodb_old_blocks_time
はどちらも動的かつグローバルであり、MySQL オプションファイル (my.cnf
または my.ini
) で指定するか、あるいは SET GLOBAL
コマンドで実行時に変更できます。この設定を変更するには、SUPER
権限が必要です。
これらのパラメータを設定した場合の効果の測定に役立つように、SHOW ENGINE INNODB STATUS
コマンドは追加の統計をレポートします。BUFFER POOL AND MEMORY
セクションは次のようになります。
Total memory allocated 1107296256; in additional pool allocated 0
Dictionary memory allocated 80360
Buffer pool size 65535
Free buffers 0
Database pages 63920
Old database pages 23600
Modified db pages 34969
Pending reads 32
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 414946, not young 2930673
1274.75 youngs/s, 16521.90 non-youngs/s
Pages read 486005, created 3178, written 160585
2132.37 reads/s, 3.40 creates/s, 323.74 writes/s
Buffer pool hit rate 950 / 1000, young-making rate 30 / 1000 not 392 / 1000
Pages read ahead 1510.10/s, evicted without access 0.00/s
LRU len: 63920, unzip_LRU len: 0
I/O sum[43690]:cur[221], unzip sum[0]:cur[0]
Old database pages
は、LRU リストの「古い」セグメント内のページの数です。Pages made young
とnot young
はそれぞれ、新しくなった「古い」ページの総数となっていないページの総数です。youngs/s
とnon-young/s
はそれぞれ、このコマンドの最後の呼び出しのあと、「古い」ページへのページアクセスによってこのようなページが新しくなった割合となっていない割合です。young-making rate
とnot
は、「古い」ページへのアクセスだけでなく、全体的なバッファープールアクセスの点から見た場合、同じ割合を示しています。
InnoDB
モニターの出力で示される 1 秒あたりの平均は、現在の時間と InnoDB
モニターの出力が最後に出力された時間の間の経過時間に基づいています。
これらのパラメータの効果はハードウェア構成、使用しているデータ、およびワークロードの詳細によって大幅に異なる場合があるため、パフォーマンスが重要な環境や本番環境でこれらの設定を変更する前には、常にベンチマークによってその有効性を確認してください。
ほとんどのアクティビティーが、大規模なスキャンにつながる定期的なバッチレポートクエリーを含む OLTP タイプである混在ワークロード環境では、バッチの実行中に innodb_old_blocks_time
の値を設定すると、通常のワークロードのワーキングセットをバッファープール内に維持するのに役立つ場合があります。
バッファープール内に完全には収まらない大きなテーブルをスキャンする場合は、innodb_old_blocks_pct
を小さな値に設定すると、1 回しか読み取られないデータがバッファープールの大きな部分を消費することはなくなります。たとえば、innodb_old_blocks_pct=5
を設定すると、1 回しか読み取られないこのデータがバッファープールの 5% に制限されます。
メモリーに収まる小さなテーブルをスキャンする場合は、バッファープール内でページを移動するためのオーバーヘッドが低いため、innodb_old_blocks_pct
をデフォルト値のままにするか、あるいは場合によっては (innodb_old_blocks_pct=50
などと) 増やすこともできます。
innodb_old_blocks_time
パラメータの効果は、比較的効果の小さい innodb_old_blocks_pct
パラメータに比べて予測が困難であり、ワークロードによる変動も大きくなります。最適な値に到達するには、innodb_old_blocks_pct
の調整によるパフォーマンス向上が不十分な場合は独自のベンチマークを実施してください。
InnoDB バッファープールの詳細は、セクション8.9.1「InnoDB バッファープール」を参照してください。