数十億行のテーブルの列を変更する必要がある場合、パフォーマンスをどのように処理するのですか?
2 に答える
pt-online-schema-change
はそのためのツールです。
大きなテーブルでのDML操作は、操作の実行中に適切な分析と優れた移行戦略を必要とする非常に退屈な作業です。MYSQLデータベースに 6 億行の巨大なテーブルがあり、一意のキーの追加、列の変更、さらにもう 1 つの列の追加などのスキーマ操作が非常に面倒なプロセスであり、処理に数時間かかるとします。サーバーのタイムアウトが発生することがあります。それを克服するためには、非常に優れた移行計画を考え出す必要があります。そのうちの 1 つを以下に記します。
1) デフォルト値が 0 の新しい列 colNew を追加する必要があるテーブル Orig_X があるとします。
2) 新しい列 colNew を除いて Orig_X のレプリカであるダミー テーブル Dummy_X が作成されます。
3) Orig_X から Dummy_X に以下の設定でデータを挿入します。
4) 自動コミットがゼロに設定されているため、各挿入ステートメントの後にデータがコミットされず、パフォーマンスが低下します。
5) バイナリ ログはゼロに設定されるため、これらのログにはデータが書き込まれません。
6) データ ボットの挿入後、機能は 1 に設定されます。
SET AUTOCOMMIT = 0;
SET sql_log_bin = 0;
Insert into Dummy_X(col1, col2, col3, colNew)
Select col1, col2, col3, from Orig_X;
SET sql_log_bin = 1;
SET AUTOCOMMIT = 1;
7) 新しく挿入された列を使用して主キーを作成できるようになりました。これは主キーの一部になりました。
8) すべての一意のキーを作成できるようになりました。9) 次のコマンドを発行して、サーバーのステータスを確認できます。
SHOW MASTER STATUS
10) MySQL が古いログをクリアするように FLUSH LOGS を発行することも役立ちます。
11) 上記の挿入ステートメントなどの同様のタイプのクエリを実行するパフォーマンスを向上させるには、クエリ キャッシュ変数をオンにする必要があります。
SHOW VARIABLES LIKE 'have_query_cache';
query_cache_type = 1
上記は大きなテーブルの移行戦略の手順であり、以下はデータベース/クエリのパフォーマンスを向上させるための手順です。1) テーブルの不要なインデックスを削除します。変更バッファリングを無効にする場合は、UNIQUE インデックスに特に注意してください。その制約の理由がない場合は、UNIQUE インデックスを使用しないでください。通常の INDEX を使用してください。
2) 新しいテーブルを一括ロードする場合は、PRIMARY KEY 以外のインデックスの作成を遅らせます。データがロードされた後にそれらを一度作成すると、InnoDB は事前ソートおよび一括ロード プロセスを適用できます。これは高速であり、通常はよりコンパクトなインデックスになります。
3) メモリを増やすと、実際にはパフォーマンスの最適化に役立ちます。SHOW ENGINE INNODB STATUS が BUFFER POOL AND MEMORY の下に読み取り/秒を示し、空きバッファーの数 (同じく BUFFER POOL AND MEMORY の下) がゼロの場合、より多くの恩恵を受けることができます (サーバーで innodb_buffer_pool_size を正しくサイズ設定したと仮定します。
4)通常、データベーステーブルは挿入ごとに再インデックスされます。これはデータベースにとっては大変な作業ですが、クエリがトランザクション内にラップされている場合、このバルク全体が処理されるまでテーブルのインデックスが再作成されません。多くの作業を節約します。
5) ほとんどの MySQL サーバーでは、クエリ キャッシュが有効になっています。これは、データベース エンジンによって静かに処理される、パフォーマンスを向上させる最も効果的な方法の 1 つです。同じクエリが複数回実行されると、結果はキャッシュからフェッチされます。これは非常に高速です。
6) EXPLAIN キーワードを使用すると、クエリを実行するために MySQL が何を行っているかを把握できます。これは、クエリまたはテーブル構造のボトルネックやその他の問題を特定するのに役立ちます。EXPLAIN クエリの結果は、どのインデックスが使用されているか、テーブルがどのようにスキャンおよびソートされているかなどを示します...
7) アプリケーションに多くの JOIN クエリが含まれている場合は、結合する列が両方のテーブルでインデックス化されていることを確認する必要があります。これは、MySQL が結合操作を内部的に最適化する方法に影響します。
8) すべてのテーブルには、PRIMARY KEY、AUTO_INCREMENT、および INT のフレーバーの 1 つである id 列があります。また、値を負にすることはできないため、UNSIGNED を使用することをお勧めします。
9) 一意のユーザー名フィールドを持つユーザーのテーブルがある場合でも、それを主キーにしないでください。主キーとしての VARCHAR フィールドは低速です。また、ID を持つすべてのユーザーを内部的に参照することで、コードの構造が改善されます。
10) 通常、スクリプトからクエリを実行すると、そのクエリの実行が終了するまで待機してから続行します。これは、バッファリングされていないクエリを使用して変更できます。これにより、大きな結果セットを生成する SQL クエリでかなりの量のメモリが節約され、完全な SQL クエリが実行されるまで待つ必要がないため、最初の行が取得された直後に結果セットの作業を開始できます。
11) データベース エンジンでは、ディスクがおそらく最も重大なボトルネックです。物事をより小さく、よりコンパクトに保つことは、通常、ディスク転送の量を減らすために、パフォーマンスの面で役に立ちます。
12) MySQL の 2 つの主要なストレージ エンジンは、MyISAM と InnoDB です。それぞれに長所と短所があります。MyISAM は読み取り負荷の高いアプリケーションには適していますが、書き込みが多い場合はうまくスケーリングしません。1 つの行の 1 つのフィールドを更新している場合でも、テーブル全体がロックされ、そのクエリが終了するまで他のプロセスはテーブルから読み取ることさえできません。MyISAM は、SELECT COUNT(*) タイプのクエリの計算において非常に高速です。InnoDB はより複雑なストレージ エンジンになる傾向があり、ほとんどの小さなアプリケーションでは MyISAM よりも遅くなる可能性があります。ただし、行ベースのロックがサポートされているため、スケーラビリティが向上します。また、トランザクションなどのより高度な機能もサポートしています。