DDL ステートメントの実行原則とベスト プラクティス

このドキュメントでは、TiDB での DDL ステートメントに関連する実行原則とベスト プラクティスの概要を説明します。この原則には、DDL 所有者モジュールとオンライン DDL 変更プロセスが含まれます。

DDL の実行原則

TiDB は、オンラインおよび非同期アプローチを使用して DDL ステートメントを実行します。これは、DDL ステートメントの実行中に、他のセッションの DML ステートメントがブロックされないことを意味します。つまり、アプリケーションの実行中に、オンラインおよび非同期の DDL ステートメントを使用してデータベース オブジェクトの定義を変更できます。

DDL ステートメントの種類

DDL ステートメントが実行中にユーザー アプリケーションをブロックするかどうかに基づいて、DDL ステートメントは次のタイプに分類できます。

  • オフライン DDL ステートメント: データベースはユーザーから DDL ステートメントを受け取ると、まず変更するデータベース オブジェクトをロックし、次にメタデータを変更します。 DDL の実行中、データベースはユーザー アプリケーションによるデータの変更をブロックします。

  • オンライン DDL ステートメント: DDL ステートメントがデータベースで実行されるとき、ステートメントがユーザー アプリケーションをブロックしないようにするために、特定の方法が使用されます。これにより、ユーザーは DDL の実行中に変更を送信できるようになります。この方法では、実行プロセス中に対応するデータベース オブジェクトの正確性と一貫性も保証されます。

対象の DDL オブジェクトに含まれるデータを操作するかどうかに基づいて、DDL ステートメントは次の種類に分類できます。

  • 論理 DDL ステートメント: 論理 DDL ステートメントは通常、データベース オブジェクトのメタデータのみを変更し、オブジェクトに格納されているデータ (テーブル名や列名の変更など) を処理しません。

    TiDB では、論理 DDL ステートメントは「一般 DDL」とも呼ばれます。通常、これらのステートメントの実行時間は短く、完了までに数十ミリ秒または数秒しかかからないことがよくあります。その結果、システム リソースをあまり消費せず、アプリケーションのワークロードに影響を与えません。

  • 物理 DDL ステートメント: 物理 DDL ステートメントは、変更されるオブジェクトのメタデータを変更するだけでなく、オブジェクトに格納されているユーザー データも変更します。たとえば、TiDB がテーブルのインデックスを作成するとき、テーブルの定義を変更するだけでなく、テーブル全体のスキャンを実行して、新しく追加されたインデックスを構築します。

    TiDB では、物理 DDL ステートメントは、再編成を表す「reorg DDL」とも呼ばれます。現在、物理 DDL ステートメントには、 ADD INDEXおよび非可逆列タイプの変更 ( INTタイプからCHARタイプへの変更など) のみが含まれます。これらのステートメントの実行には長い時間がかかり、実行時間はテーブル内のデータ量、マシン構成、アプリケーションのワークロードの影響を受けます。

    物理 DDL ステートメントを実行すると、2 つの理由からアプリケーションのワークロードに影響を与える可能性があります。一方で、データの読み取りと新しいデータの書き込みのために TiKV からの CPU および I/O リソースを消費します。一方、 DDL オーナーとして機能する TiDB ノード、またはADD INDEXタスクを実行するために TiDB 分散実行フレームワーク (DXF) によってスケジュールされた TiDB ノードは、対応する計算を実行するために TiDB からの CPU リソースを消費します。

    注記:

    通常、物理 DDL タスクの実行は、ユーザー アプリケーションに最大の影響を与えます。したがって、この影響を最小限に抑えるためには、実行時の物理 DDL ステートメントの設計を最適化することが重要です。これは、ユーザー アプリケーションへの影響を軽減するのに役立ちます。

TiDB DDL モジュール

TiDB DDL モジュールは、TiDB クラスター内のすべての DDL ステートメントを実行するプロキシとして機能する DDL オーナー (またはオーナー) の役割を導入します。現在の実装では、いつでもクラスター全体で 1 つの TiDB ノードのみが所有者として選出されます。 TiDB ノードが所有者として選出されると、その TiDB ノードで開始されたワーカーはクラスター内の DDL タスクを処理できるようになります。

TiDB は etcd の選出メカニズムを使用して、複数の TiDB ノードから所有者をホストするノードを選出します。デフォルトでは、各 TiDB ノードが所有者として選出される可能性があります (選出へのノードの参加を管理するためにrun-ddlを構成できます)。選出されたオーナー ノードには期間があり、更新することでその期間を積極的に維持します。所有者ノードがダウンしている場合、etcd を通じて別のノードが新しい所有者として選出され、クラスター内で DDL タスクの実行を続行できます。

DDL 所有者の簡単な図は次のとおりです。

DDL Owner

ADMIN SHOW DDLステートメントを使用すると、現在の DDL 所有者を表示できます。

ADMIN SHOW DDL;
+------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ | SCHEMA_VER | OWNER_ID | OWNER_ADDRESS | RUNNING_JOBS | SELF_ID | QUERY | +------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ | 26 | 2d1982af-fa63-43ad-a3d5-73710683cc63 | 0.0.0.0:4000 | | 2d1982af-fa63-43ad-a3d5-73710683cc63 | | +------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ 1 row in set (0.00 sec)

TiDB でのオンライン DDL 非同期変更の仕組み

TiDB DDL モジュールは、設計の最初からオンライン非同期変更モードを選択しており、これにより、ダウンタイムを発生させることなくアプリケーションを変更できます。

DDL の変更には、ある状態から別の状態への遷移、通常は「変更前」状態から「変更後」状態への遷移が含まれます。オンライン DDL 変更では、この移行は、相互互換性のある複数の小さいバージョン状態を導入することによって行われます。 DDL ステートメントの実行中、変更オブジェクトの小さいバージョン間の違いが 2 バージョンを超えない限り、同じクラスター内の TiDB ノードは異なる小さいバージョン変更を持つことができます。これが可能なのは、隣接する小さいバージョンが相互に互換性があるためです。

このようにして、複数の小さなバージョンを経て進化することで、複数の TiDB ノード間でメタデータを正しく同期できるようになります。これは、プロセス中のデータ変更を伴うユーザー トランザクションの正確性と一貫性を維持するのに役立ちます。

ADD INDEX例に挙げると、状態変化の全体的なプロセスは次のようになります。

absent -> delete only -> write only -> write reorg -> public

ユーザーにとって、新しく作成されたインデックスはpublic状態になるまでは利用できません。

  • Online DDL asychronous change before TiDB v6.2.0
  • Parallel DDL framework starting from v6.2.0

v6.2.0 より前では、 TiDB SQLレイヤーで非同期スキーマ変更を処理するプロセスは次のとおりです。

  1. MySQL クライアントは DDL リクエストを TiDBサーバーに送信します。

  2. リクエストを受信した後、TiDBサーバーはMySQL プロトコルレイヤーでリクエストを解析して最適化し、それを実行のためにTiDB SQLレイヤーに送信します。

    TiDB の SQLレイヤーが DDL リクエストを受信すると、 start jobモジュールを開始してリクエストを特定の DDL ジョブ (つまり、DDL タスク) にカプセル化し、このジョブを KVレイヤーベースの対応する DDL ジョブ キューに保存します。ステートメントの種類について。対応するワーカーに、処理が必要なジョブが通知されます。

  3. ジョブを処理するための通知を受け取ると、ワーカーは自分が DDL 所有者の役割を持っているかどうかを判断します。存在する場合、ジョブは直接処理されます。それ以外の場合は、何も処理せずに終了します。

    TiDBサーバーが所有者の役割ではない場合は、別のノードが所有者になる必要があります。所有者ロールのノードのワーカーは、実行可能なジョブがあるかどうかを定期的に確認します。そのようなジョブが識別された場合、ワーカーはそのジョブを処理します。

  4. ワーカーはジョブを処理した後、KVレイヤーのジョブ キューからジョブを削除し、 job history queueに配置します。ジョブをカプセル化されたstart jobモジュールは、 job history queueのジョブの ID を定期的にチェックして、ジョブが処理されたかどうかを確認します。そうであれば、ジョブに対応する DDL 操作全体が終了します。

  5. TiDBサーバーはDDL 処理結果を MySQL クライアントに返します。

TiDB v6.2.0 より前は、DDL 実行フレームワークには次の制限がありました。

  • TiKV クラスターにはgeneral job queueadd index job queueの 2 つのキューしかなく、それぞれ論理 DDL と物理 DDL を処理します。
  • DDL 所有者は常に DDL ジョブを先入れ先出し方式で処理します。
  • DDL 所有者は、一度に同じタイプ (論理または物理) の DDL タスクを 1 つだけ実行できます。これは比較的厳密であり、ユーザー エクスペリエンスに影響します。

これらの制限により、「意図しない」DDL ブロック動作が発生する可能性があります。詳細については、 SQL FAQ - DDL の実行を参照してください。

TiDB v6.2.0 より前は、所有者が一度に同じタイプ (論理または物理) の DDL タスクを 1 つしか実行できないため、これは比較的厳密であり、ユーザー エクスペリエンスに影響します。

DDL タスク間に依存関係がない場合、並列実行はデータの正確性と一貫性に影響を与えません。たとえば、ユーザー A がT1テーブルにインデックスを追加し、ユーザー B がT2テーブルから列を削除するとします。これら 2 つの DDL ステートメントは並行して実行できます。

DDL 実行のユーザー エクスペリエンスを向上させるために、v6.2.0 以降、TiDB では所有者が DDL タスクの関連性を判断できるようになりました。ロジックは次のとおりです。

  • 同じテーブルに対して実行される DDL ステートメントは相互にブロックされます。
  • データベース内のすべてのオブジェクトに影響を与えるDROP DATABASEと DDL ステートメントは相互にブロックされます。
  • 異なるテーブルに対するインデックスの追加と列の型の変更を同時に実行できます。
  • 論理 DDL ステートメントは、前の論理 DDL ステートメントが実行されるまで待機してから実行する必要があります。
  • 他の場合には、DDL の同時実行の可用性レベルに基づいて DDL を実行できます。

具体的には、TiDB は v6.2.0 の DDL 実行フレームワークを次の点でアップグレードしました。

  • DDL 所有者は、前述のロジックに基づいて DDL タスクを並行して実行できます。

  • DDL ジョブ キューの先入れ先出しの問題は解決されました。 DDL 所有者はキュー内の最初のジョブを選択するのではなく、現時点で実行できるジョブを選択するようになりました。

  • 物理 DDL ステートメントを処理するワーカーの数が増加し、複数の物理 DDL ステートメントを並行して実行できるようになりました。

    TiDB のすべての DDL タスクはオンライン変更アプローチを使用して実装されるため、TiDB は所有者を通じて新しい DDL ジョブの関連性を判断し、この情報に基づいて DDL タスクをスケジュールできます。このアプローチにより、分散データベースは従来のデータベースと同じレベルの DDL 同時実行性を達成できます。

同時 DDL フレームワークは、TiDB での DDL ステートメントの実行機能を強化し、商用データベースの使用パターンとの互換性を高めます。

ベストプラクティス

システム変数を通じて、物理 DDL 実行速度とアプリケーション負荷への影響のバランスをとります。

物理 DDL ステートメント (インデックスの追加や列タイプの変更を含む) を実行する場合、次のシステム変数の値を調整して、DDL 実行速度とアプリケーション負荷への影響のバランスをとることができます。

  • tidb_ddl_reorg_worker_cnt : この変数は、バックフィルの同時実行性を制御する DDL 操作の reorg ワーカーの数を設定します。

  • tidb_ddl_reorg_batch_size : この変数は、 re-organizeフェーズでの DDL 操作のバッチ サイズを設定し、バックフィルされるデータの量を制御します。

    推奨値:

    • 他に負荷がない場合は、 tidb_ddl_reorg_worker_cnttidb_ddl_reorg_batch_sizeの値を大きくしてADD INDEX動作を高速化できます。たとえば、2 つの変数の値をそれぞれ202048に設定できます。
    • 他の負荷がある場合は、 tidb_ddl_reorg_worker_cnttidb_ddl_reorg_batch_sizeの値を減らして、他のアプリケーションへの影響を最小限に抑えることができます。たとえば、これらの変数の値をそれぞれ4256に設定できます。

ヒント:

  • 前述の 2 つの変数は、DDL タスクの実行中に動的に調整でき、次のトランザクション バッチで有効になります。
  • 操作のタイプとアプリケーションの負荷圧力に基づいて、DDL 操作を実行する適切な時間を選択します。たとえば、アプリケーションの負荷が低いときにADD INDEX操作を実行することをお勧めします。
  • インデックスの追加には比較的時間がかかるため、TiDB はコマンドの送信後にバックグラウンドでタスクを実行します。 TiDBサーバーがダウンしても、実行には影響しません。

DDL リクエストを同時に送信することで、多数のテーブルを迅速に作成します

テーブル作成操作には約 50 ミリ秒かかります。フレームワークの制限により、テーブルの作成に実際にかかる時間はさらに長くなる可能性があります。

テーブルをより速く作成するには、複数の DDL リクエストを同時に送信して、テーブル作成速度を最速にすることをお勧めします。 DDL リクエストをシリアルに送信し、オーナー ノードに送信しない場合、テーブルの作成速度は非常に遅くなります。

1 つのALTERステートメントで複数の変更を行う

v6.2.0 以降、TiDB は、ステートメント全体のアトミック性を確保しながら、単一のALTERステートメントでのテーブルの複数のスキーマ オブジェクト (列やインデックスなど) の変更をサポートします。したがって、単一のALTERステートメントで複数の変更を行うことをお勧めします。

読み取りおよび書き込みパフォーマンスを確認する

TiDB がインデックスを追加しているとき、データのバックフィルのフェーズにより、クラスターに読み取りおよび書き込みの負荷がかかります。 ADD INDEXコマンドが送信され、 write reorgフェーズが開始したら、Grafana ダッシュボードで TiDB および TiKV の読み取りおよび書き込みパフォーマンス メトリクスとアプリケーションの応答時間を確認し、 ADD INDEX操作がクラスターに影響を与えるかどうかを判断することをお勧めします。

  • ADMIN SHOW DDL : 現在のスキーマのバージョン番号、DDL ID と DDL 所有者のアドレス、DDL タスクと実行中の SQL、現在の TiDB インスタンスの DDL ID など、TiDB DDL 操作のステータスを表示するために使用されます。詳細はADMIN SHOW DDLを参照してください。

  • ADMIN SHOW DDL JOBS : クラスター環境で実行されている DDL タスクの詳細なステータスを表示するために使用されます。詳細はADMIN SHOW DDL JOBSを参照してください。

  • ADMIN SHOW DDL JOB QUERIES job_id [, job_id] : job_idに対応する DDL タスクの元の SQL ステートメントを表示するために使用されます。詳細はADMIN SHOW DDL JOB QUERIESを参照してください。

  • ADMIN CANCEL DDL JOBS job_id, [, job_id] : 送信されたが完了していない DDL タスクをキャンセルするために使用されます。キャンセルが完了すると、DDL タスクを実行する SQL ステートメントはERROR 8214 (HY000): Cancelled DDL jobエラーを返します。

    完了した DDL タスクがキャンセルされた場合、 RESULT列にDDL Job:90 not foundエラーが表示されます。これは、タスクが DDL 待機キューから削除されたことを意味します。

よくある質問

DDL の実行に関するよくある質問については、 SQL FAQ - DDL の実行を参照してください。

このページは役に立ちましたか?