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 ノードは、対応する計算を実行する必要があり、より多くの CPU リソースを消費します。 TiDB は DDL ステートメントの分散実行をサポートしていないため、このプロセス中に他の TiDB ノードが追加のシステム リソースを消費することはありません。

    ノート:

    通常、物理 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 ステートメントの実行中、同じクラスター内の TiDB ノードは、変更オブジェクトの小さなバージョン間の違いが 2 つのバージョンを超えない限り、異なる小さなバージョンの変更を持つことができます。これが可能なのは、隣接する小さいバージョンが相互に互換性があるためです。

このように、複数の小さなバージョンを進化させることで、複数の 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 クラスターには、論理 DDL と物理 DDL をそれぞれ処理するgeneral job queueadd index job queue 2 つのキューしかありません。
  • 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 操作の再編成ワーカーの数を設定します。

  • 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 所有者の DDL ID とアドレス、実行中の 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 実行を参照してください。

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