MySQL 8.0 リファレンスマニュアル


8.12.3.1 MySQL のメモリーの使用方法

MySQL はバッファおよびキャッシュを割り当てて、データベース操作のパフォーマンスを向上させます。 デフォルトの構成は、RAM が約 512MB の仮想マシンで MySQL サーバーを起動できるように設計されています。 特定のキャッシュおよびバッファ関連のシステム変数の値を増やすことで、MySQL のパフォーマンスを向上できます。 メモリーが制限されたシステムで MySQL を実行するように、デフォルトの構成を変更することもできます。

次のリストでは、MySQL がメモリーを使用する方法をいくつか説明します。 該当する場合は、関連するシステム変数が参照されます。 ストレージエンジンまたは機能固有の項目もあります。

  • InnoDB バッファプールは、テーブル、インデックスおよびその他の補助バッファのキャッシュされた InnoDB データを保持するメモリー領域です。 大容量読み取り操作の効率を高めるため、バッファープールは複数行を保持できるページに分割されます。 キャッシュ管理の効率のために、バッファープールはページのリンクリストとして実装されます。まれにしか使用されないデータは、LRU アルゴリズムのバリエーションを使用してキャッシュからエージアウトされます。 詳細は、セクション15.5.1「バッファプール」を参照してください。

    バッファプールのサイズは、システムパフォーマンスのために重要です:

    • InnoDB は、malloc() 操作を使用して、サーバー起動時にバッファプール全体にメモリーを割り当てます。 innodb_buffer_pool_size システム変数は、バッファープールサイズを定義します。 通常、推奨される innodb_buffer_pool_size 値は、システムメモリーの 50 から 75% です。innodb_buffer_pool_size は、サーバーの実行中に動的に構成できます。 詳細は、セクション15.8.3.1「InnoDB バッファプールサイズの構成」を参照してください。

    • メモリーが大量にあるシステムでは、バッファプールを複数の buffer pool instances に分割することで同時実行性を向上させることができます。 innodb_buffer_pool_instances システム変数は、バッファープールインスタンスの数を定義します。

    • バッファプールが小さすぎると、ページがバッファプールからフラッシュされるときに、後で再度必要になるだけであるため、過剰なチャーニングが発生する可能性があります。

    • バッファプールが大きすぎると、メモリーの競合が原因でスワッピングが発生する場合があります。

  • ストレージエンジンインタフェースを使用すると、オプティマイザは、オプティマイザが複数の行を読み取る可能性が高いスキャンに使用されるレコードバッファーのサイズに関する情報を提供できます。 バッファサイズは、見積りのサイズによって異なる場合があります。 InnoDB では、この可変サイズのバッファリング機能を使用して、行プリフェッチを利用し、ラッチおよび B ツリーナビゲーションのオーバーヘッドを削減します。

  • すべてのスレッドが MyISAM キーバッファを共有します。 key_buffer_size システム変数によってサイズが決まります。

    サーバーが開く MyISAM テーブルごとに、インデックスファイルが一度開かれます。テーブルにアクセスする同時に実行されているスレッドごとに、データファイルが一度開かれます。 同時スレッドごとに、テーブル構造、各カラムのカラム構造、およびサイズ 3 * N のバッファーが割り当てられます (ここで N は最大行長で、BLOB カラムをカウントしていません)。 BLOB カラムには、5 から 8 バイト+ BLOB データの長さが必要です。 MyISAM ストレージエンジンは、内部使用のため 1 つ余分な行バッファーを保持します。

  • myisam_use_mmap システム変数を 1 に設定して、すべての MyISAM テーブルのメモリーマッピングを有効にできます。

  • 内部インメモリー一時テーブルが大きすぎる場合 (tmp_table_size および max_heap_table_size システム変数を使用して決定)、MySQL はテーブルをインメモリーからディスク上の形式に自動的に変換します。 MySQL 8.0.16 の時点では、ディスク上の一時テーブルは常に InnoDB ストレージエンジンを使用します。 (以前は、この目的に使用されていたストレージエンジンは、サポートされなくなった internal_tmp_disk_storage_engine システム変数によって決定されていました。) セクション8.4.4「MySQL での内部一時テーブルの使用」に説明するように、許可される一時テーブルのサイズを増やすことができます。

    CREATE TABLE を使用して明示的に作成された MEMORY テーブルの場合、max_heap_table_size システム変数のみがテーブルの大きさを決定し、ディスク上の形式への変換はありません。

  • MySQL Performance Schema は、MySQL サーバーの実行を低レベルで監視するための機能です。 パフォーマンススキーマは、サーバーの起動時に必要なメモリーを割り当てるのではなく、メモリー使用量を実際のサーバー負荷に合わせて増分的に割り当てます。 割り当てられたメモリーは、サーバーが再起動されるまで解放されません。 詳細は、セクション27.17「パフォーマンススキーマのメモリー割り当てモデル」を参照してください。

  • サーバーがクライアント接続の管理に使用する各スレッドには、スレッド固有の領域が必要です。 次のリストは、これらの変数とそのサイズを制御するシステム変数を示しています:

    • スタック (thread_stack)

    • 接続バッファ (net_buffer_length)

    • 結果バッファ (net_buffer_length)

    接続バッファーと結果バッファーはそれぞれ net_buffer_length バイトに等しいサイズから開始されますが、必要に応じて max_allowed_packet バイトまで動的に拡大されます。 結果バッファーは各 SQL ステートメントのあとに net_buffer_length バイトに縮小されます。 ステートメントの実行中は現在のステートメント文字列のコピーも割り当てられます。

    各接続スレッドは、ステートメントダイジェストの計算にメモリーを使用します。 サーバーは、セッションごとに max_digest_length バイトを割り当てます。 セクション27.10「パフォーマンススキーマのステートメントダイジェストとサンプリング」を参照してください。

  • すべてのスレッドで同じベースメモリーを共有します。

  • スレッドが必要ない場合、それに割り当てられたメモリーが解放され、スレッドがスレッドキャッシュに戻らないかぎり、システムに返されます。 その場合、メモリーは割り当てられた状態のままになります。

  • テーブルの順次スキャンを実行する各リクエストによって、read buffer が割り当てられます。 read_buffer_size システム変数によってバッファサイズが決まります。

  • 任意の順序 (ソート後など) で行を読み取る場合、ディスクシークを回避するためにランダム読取りバッファを割り当てることができます。 read_rnd_buffer_size システム変数によってバッファサイズが決まります。

  • すべての結合は単一のパスで実行され、ほとんどの結合は一時テーブルも使用せずに実行できます。 ほとんどの一時テーブルはメモリーベースのハッシュテーブルです。 大きな行長 (すべてのカラム長の合計として算出される) を持つか BLOB カラムを含む一時テーブルはディスク上に格納されます。

  • ソートを実行するほとんどのリクエストは、ソートバッファーおよび結果セットサイズに応じた 0 から 2 つの一時ファイルを割り当てます。 セクションB.3.3.5「MySQL が一時ファイルを格納する場所」を参照してください。

  • ほとんどすべての解析と計算は、スレッドローカルの再利用可能なメモリープールで実行されます。 小さい項目にはメモリーオーバーヘッドは必要ないため、通常の低速メモリー割当ておよび解放が回避されます。 メモリーは、予測外に大きな文字列にのみ割り当てられます。

  • BLOB カラムがあるテーブルごとに、大きな BLOB 値を読み取るためにバッファーが動的に拡大されます。 テーブルをスキャンすると、バッファは最大の BLOB 値と同じ大きさになります。

  • MySQL には、テーブルキャッシュ用のメモリーおよびディスクリプタが必要です。 使用中のすべてのテーブルのハンドラ構造はテーブルキャッシュに保存され、「先入れ先出し」 (FIFO) として管理されます。 table_open_cache システム変数は、初期テーブルキャッシュサイズを定義します。セクション8.4.3.1「MySQL でのテーブルのオープンとクローズの方法」 を参照してください。

    MySQL には、テーブル定義キャッシュ用のメモリーも必要です。 table_definition_cache システム変数は、テーブル定義キャッシュに格納できるテーブル定義の数を定義します。 多数のテーブルを使用する場合は、大規模なテーブル定義キャッシュを作成してテーブルのオープンを高速化できます。 テーブル定義キャッシュは、テーブルキャッシュとは異なり、使用する領域が少なく、ファイル記述子を使用しません。

  • FLUSH TABLES ステートメントまたは mysqladmin flush-tables コマンドは、使用中でないすべてのテーブルを一度に閉じ、現在実行中のスレッドの終了時に閉じられるように使用中のすべてのテーブルをマークします。 これにより、事実上ほとんどの使用中のメモリーが解放されます。 FLUSH TABLES はすべてのテーブルが閉じられるまで戻りません。

  • GRANTCREATE USERCREATE SERVER、および INSTALL PLUGIN ステートメントの結果として、サーバーは情報をメモリーにキャッシュします。 このメモリーは、対応する REVOKE, DROP USER, DROP SERVER ステートメントおよび UNINSTALL PLUGIN ステートメントによって解放されないため、キャッシュを引き起こすステートメントの多くのインスタンスを実行するサーバーでは、FLUSH PRIVILEGES で解放されないかぎり、キャッシュされたメモリーの使用量が増加します。

  • レプリケーショントポロジでは、次の設定はメモリー使用量に影響し、必要に応じて調整できます:

    • レプリケーションソースの max_allowed_packet システム変数は、ソースが処理のためにレプリカに送信する最大メッセージサイズを制限します。 この設定のデフォルトは 64M です。

    • マルチスレッドレプリカ上の slave_pending_jobs_size_max システム変数は、処理待ちのメッセージを保持するために使用できるメモリーの最大量を設定します。 この設定のデフォルトは 128M です。 メモリーは必要な場合にのみ割り当てられますが、レプリケーショントポロジが大規模なトランザクションを処理する場合に使用されることがあります。 これは弱い制限であり、より大きなトランザクションを処理できます。

    • レプリケーションソースまたはレプリカ上の rpl_read_size システム変数は、バイナリログファイルおよびリレーログファイルから読み取られるデータの最小量をバイト単位で制御します。 デフォルトは 8192 バイトです。 バイナリログおよびリレーログファイルから読み取るスレッドごとに、この値のバッファーが割り当てられます。これには、ソース上のダンプスレッドやレプリカ上のコーディネータスレッドも含まれます。

    • binlog_transaction_dependency_history_size システム変数は、インメモリー履歴として保持される行ハッシュの数を制限します。

    • max_binlog_cache_size システム変数は、個々のトランザクションによるメモリー使用量の上限を指定します。

    • max_binlog_stmt_cache_size システム変数は、ステートメントキャッシュによるメモリー使用量の上限を指定します。

ps およびその他のステータスプログラムが、mysqld が大量のメモリーを使用していることをレポートすることがあります。 これは、さまざまなメモリーアドレス上のスレッドスタックによって発生する可能性があります。 たとえば、Solaris バージョンの ps はスタック間の未使用のメモリーが使用されているメモリーとしてカウントされます。 これを確認するには、swap -s で使用可能なスワップをチェックします。 いくつかのメモリーリーク検出ツール (市販とオープンソースの両方の) で mysqld をテストしているため、メモリーリークはないはずです。

MySQL メモリー使用量の監視

次の例は、Performance Schema および sys schema を使用して MySQL メモリー使用量を監視する方法を示しています。

ほとんどのパフォーマンススキーマメモリーインストゥルメンテーションはデフォルトで無効になっています。 インストゥルメントを有効にするには、パフォーマンススキーマ setup_instruments テーブルの ENABLED カラムを更新します。 メモリーインストゥルメントには memory/code_area/instrument_name という形式の名前が付けられます。ここで、code_areasqlinnodb などの値で、instrument_name はインストゥルメントの詳細です。

  1. 使用可能な MySQL メモリーインストゥルメントを表示するには、パフォーマンススキーマの setup_instruments テーブルをクエリーします。 次のクエリーは、すべてのコード領域に対して何百ものメモリーインストゥルメントを返します。

    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory%';

    コード領域を指定して結果を絞り込むことができます。 たとえば、コード領域として innodb を指定することで、結果を InnoDB メモリーインストゥルメントに制限できます。

    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory/innodb%';
    +-------------------------------------------+---------+-------+
    | NAME                                      | ENABLED | TIMED |
    +-------------------------------------------+---------+-------+
    | memory/innodb/adaptive hash index         | NO      | NO    |
    | memory/innodb/buf_buf_pool                | NO      | NO    |
    | memory/innodb/dict_stats_bg_recalc_pool_t | NO      | NO    |
    | memory/innodb/dict_stats_index_map_t      | NO      | NO    |
    | memory/innodb/dict_stats_n_diff_on_level  | NO      | NO    |
    | memory/innodb/other                       | NO      | NO    |
    | memory/innodb/row_log_buf                 | NO      | NO    |
    | memory/innodb/row_merge_sort              | NO      | NO    |
    | memory/innodb/std                         | NO      | NO    |
    | memory/innodb/trx_sys_t::rw_trx_ids       | NO      | NO    |
    ...

    MySQL のインストールによっては、コード領域に performance_schema, sql, client, innodb, myisam, csv, memory, blackhole, archive, partition などが含まれる場合があります。

  2. メモリーインストゥルメントを有効にするには、MySQL 構成ファイルに performance-schema-instrument ルールを追加します。 たとえば、すべてのメモリーインストゥルメントを有効にするには、このルールを構成ファイルに追加し、サーバーを再起動します:

    performance-schema-instrument='memory/%=COUNTED'
    注記

    起動時にメモリーインストゥルメントを有効にすると、起動時に発生するメモリー割り当てが確実にカウントされます。

    サーバーを再起動したあと、パフォーマンススキーマ setup_instruments テーブルの ENABLED カラムに、有効にしたメモリーインストゥルメントの YES が報告されます。 メモリー操作が時間指定されていないため、setup_instruments テーブルの TIMED カラムはメモリーインストルメントで無視されます。

    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory/innodb%';
    +-------------------------------------------+---------+-------+
    | NAME                                      | ENABLED | TIMED |
    +-------------------------------------------+---------+-------+
    | memory/innodb/adaptive hash index         | NO      | NO    |
    | memory/innodb/buf_buf_pool                | NO      | NO    |
    | memory/innodb/dict_stats_bg_recalc_pool_t | NO      | NO    |
    | memory/innodb/dict_stats_index_map_t      | NO      | NO    |
    | memory/innodb/dict_stats_n_diff_on_level  | NO      | NO    |
    | memory/innodb/other                       | NO      | NO    |
    | memory/innodb/row_log_buf                 | NO      | NO    |
    | memory/innodb/row_merge_sort              | NO      | NO    |
    | memory/innodb/std                         | NO      | NO    |
    | memory/innodb/trx_sys_t::rw_trx_ids       | NO      | NO    |
    ...
  3. メモリーインストゥルメントデータをクエリーします。 この例では、メモリーインスツルメントデータがパフォーマンススキーマ memory_summary_global_by_event_name テーブルでクエリーされ、EVENT_NAME によってデータが要約されます。 EVENT_NAME はインストゥルメントの名前です。

    次のクエリーは、InnoDB バッファプールのメモリーデータを返します。 カラムの説明は、セクション27.12.18.10「メモリーサマリーテーブル」 を参照してください。

    mysql> SELECT * FROM performance_schema.memory_summary_global_by_event_name
           WHERE EVENT_NAME LIKE 'memory/innodb/buf_buf_pool'\G
                      EVENT_NAME: memory/innodb/buf_buf_pool
                     COUNT_ALLOC: 1
                      COUNT_FREE: 0
       SUM_NUMBER_OF_BYTES_ALLOC: 137428992
        SUM_NUMBER_OF_BYTES_FREE: 0
                  LOW_COUNT_USED: 0
              CURRENT_COUNT_USED: 1
                 HIGH_COUNT_USED: 1
        LOW_NUMBER_OF_BYTES_USED: 0
    CURRENT_NUMBER_OF_BYTES_USED: 137428992
       HIGH_NUMBER_OF_BYTES_USED: 137428992

    同じ基礎となるデータを sys スキーマ memory_global_by_current_bytes テーブルを使用してクエリーすることができます。このテーブルには、グローバルにサーバー内の現在のメモリー使用量が割当てタイプ別に分類されて表示されます。

    mysql> SELECT * FROM sys.memory_global_by_current_bytes
           WHERE event_name LIKE 'memory/innodb/buf_buf_pool'\G
    *************************** 1. row ***************************
           event_name: memory/innodb/buf_buf_pool
        current_count: 1
        current_alloc: 131.06 MiB
    current_avg_alloc: 131.06 MiB
           high_count: 1
           high_alloc: 131.06 MiB
       high_avg_alloc: 131.06 MiB

    この sys スキーマクエリーは、現在割り当てられているメモリー (current_alloc) をコード領域別に集計します:

    mysql> SELECT SUBSTRING_INDEX(event_name,'/',2) AS
           code_area, FORMAT_BYTES(SUM(current_alloc))
           AS current_alloc
           FROM sys.x$memory_global_by_current_bytes
           GROUP BY SUBSTRING_INDEX(event_name,'/',2)
           ORDER BY SUM(current_alloc) DESC;
    +---------------------------+---------------+
    | code_area                 | current_alloc |
    +---------------------------+---------------+
    | memory/innodb             | 843.24 MiB    |
    | memory/performance_schema | 81.29 MiB     |
    | memory/mysys              | 8.20 MiB      |
    | memory/sql                | 2.47 MiB      |
    | memory/memory             | 174.01 KiB    |
    | memory/myisam             | 46.53 KiB     |
    | memory/blackhole          | 512 bytes     |
    | memory/federated          | 512 bytes     |
    | memory/csv                | 512 bytes     |
    | memory/vio                | 496 bytes     |
    +---------------------------+---------------+
    注記

    MySQL 8.0.16 より前は、sys.format_bytes()FORMAT_BYTES() に使用されていました。

    sys スキーマの詳細は、第28章「MySQL sys スキーマ を参照してください。


関連キーワード:  テーブル, メモリー, memory, NO, InnoDB, 変数, キャッシュ, バッファ, ステートメント, サーバー