SQL 計画管理 (SPM)

SQL Plan Management は、SQL バインディングを実行して手動で SQL 実行計画に干渉する関数のセットです。これらの関数には、SQL バインディング、ベースライン キャプチャ、およびベースライン展開が含まれます。

SQL バインディング

SQL バインディングは SPM の基礎です。 オプティマイザーのヒントドキュメントでは、ヒントを使用して特定の実行プランを選択する方法を紹介します。ただし、SQL ステートメントを変更せずに実行の選択に干渉する必要がある場合があります。 SQL バインディングを使用すると、SQL ステートメントを変更せずに、指定された実行計画を選択できます。

バインディングを作成する

CREATE [GLOBAL | SESSION] BINDING FOR BindableStmt USING BindableStmt

このステートメントは、SQL 実行計画を GLOBAL または SESSION レベルでバインドします。現在、TiDB でサポートされているバインド可能な SQL ステートメント (BindableStmt) には、 SELECTのサブクエリを持つSELECTDELETEUPDATE 、およびINSERT / REPLACEが含まれます。

ノート:

バインディングは、手動で追加されたヒントよりも優先されます。したがって、対応するバインディングが存在するときにヒントを含むステートメントを実行すると、オプティマイザーの動作を制御するヒントは有効になりません。ただし、他のタイプのヒントは引き続き有効です。

具体的には、これらの 2 つのタイプのステートメントは、構文の競合のために実行プランにバインドできません。次の例を参照してください。

-- Type one: Statements that get the Cartesian product by using the `JOIN` keyword and not specifying the associated columns with the `USING` keyword.
CREATE GLOBAL BINDING for
    SELECT * FROM t t1 JOIN t t2
USING
    SELECT * FROM t t1 JOIN t t2;

-- Type two: `DELETE` statements that contain the `USING` keyword.
CREATE GLOBAL BINDING for
    DELETE FROM t1 USING t1 JOIN t2 ON t1.a = t2.a
USING
    DELETE FROM t1 USING t1 JOIN t2 ON t1.a = t2.a;

同等のステートメントを使用して、構文の競合を回避できます。たとえば、上記のステートメントを次のように書き換えることができます。

-- First rewrite of type one statements: Add a `USING` clause for the `JOIN` keyword.
CREATE GLOBAL BINDING for
    SELECT * FROM t t1 JOIN t t2 USING (a)
USING
    SELECT * FROM t t1 JOIN t t2 USING (a);

-- Second rewrite of type one statements: Delete the `JOIN` keyword.
CREATE GLOBAL BINDING for
    SELECT * FROM t t1, t t2
USING
    SELECT * FROM t t1, t t2;

-- Rewrite of type two statements: Remove the `USING` keyword from the `delete` statement.
CREATE GLOBAL BINDING for
    DELETE t1 FROM t1 JOIN t2 ON t1.a = t2.a
using
    DELETE t1 FROM t1 JOIN t2 ON t1.a = t2.a;

ノート:

SELECTのサブクエリを持つINSERT / REPLACEステートメントの実行プラン バインディングを作成する場合、 INSERT / REPLACEキーワードの後ではなく、 SELECTのサブクエリでバインドするオプティマイザ ヒントを指定する必要があります。そうしないと、オプティマイザーのヒントが意図したとおりに機能しません。

以下に 2 つの例を示します。

-- The hint takes effect in the following statement.
CREATE GLOBAL BINDING for
    INSERT INTO t1 SELECT * FROM t2 WHERE a > 1 AND b = 1
using
    INSERT INTO t1 SELECT /*+ use_index(@sel_1 t2, a) */ * FROM t2 WHERE a > 1 AND b = 1;

-- The hint cannot take effect in the following statement.
CREATE GLOBAL BINDING for
    INSERT INTO t1 SELECT * FROM t2 WHERE a > 1 AND b = 1
using
    INSERT /*+ use_index(@sel_1 t2, a) */ INTO t1 SELECT * FROM t2 WHERE a > 1 AND b = 1;

実行計画バインディングの作成時にスコープを指定しない場合、デフォルトのスコープは SESSION です。 TiDB オプティマイザーは、バインドされた SQL ステートメントを正規化し、システム テーブルに格納します。 SQL クエリを処理するときに、正規化されたステートメントがシステム テーブル内のバインドされた SQL ステートメントの 1 つと一致し、システム変数tidb_use_plan_baselineson (デフォルト値はon ) に設定されている場合、TiDB はこのステートメントに対応するオプティマイザー ヒントを使用します。一致する実行計画が複数ある場合、オプティマイザは最もコストの低い実行計画を選択してバインドします。

Normalizationは、SQL ステートメント内の定数を変数パラメーターに変換し、SQL ステートメント内のスペースと改行に関する標準化された処理を使用して、クエリで参照されるテーブルのデータベースを明示的に指定するプロセスです。次の例を参照してください。

SELECT * FROM t WHERE a >    1
-- After normalization, the above statement is as follows:
SELECT * FROM test . t WHERE a > ?

ノート:

コンマ,で結合された複数の定数は、 ?ではなく...として正規化されます。

例えば:

SELECT * FROM t limit 10
SELECT * FROM t limit 10, 20
SELECT * FROM t WHERE a IN (1)
SELECT * FROM t WHERE a IN (1,2,3)
-- After normalization, the above statements are as follows:
SELECT * FROM test . t limit ?
SELECT * FROM test . t limit ...
SELECT * FROM test . t WHERE a IN ( ? )
SELECT * FROM test . t WHERE a IN ( ... )

バインディングが作成されると、TiDB は単一の定数を含む SQL ステートメントと、コンマで結合された複数の定数を含む SQL ステートメントを異なる方法で処理します。したがって、2 つの SQL タイプのバインディングを個別に作成する必要があります。

SQL ステートメントが GLOBAL スコープと SESSION スコープの両方でバインドされた実行計画を持っている場合、オプティマイザは SESSION バインディングに遭遇したときに GLOBAL スコープでバインドされた実行計画を無視するため、SESSION スコープでこのステートメントのバインドされた実行計画は実行計画を保護します。グローバルスコープ。

例えば:

--  Creates a GLOBAL binding and specifies using `sort merge join` in this binding.
CREATE GLOBAL BINDING for
    SELECT * FROM t1, t2 WHERE t1.id = t2.id
USING
    SELECT /*+ merge_join(t1, t2) */ * FROM t1, t2 WHERE t1.id = t2.id;

-- The execution plan of this SQL statement uses the `sort merge join` specified in the GLOBAL binding.
explain SELECT * FROM t1, t2 WHERE t1.id = t2.id;

-- Creates another SESSION binding and specifies using `hash join` in this binding.
CREATE BINDING for
    SELECT * FROM t1, t2 WHERE t1.id = t2.id
USING
    SELECT /*+ hash_join(t1, t2) */ * FROM t1, t2 WHERE t1.id = t2.id;

-- In the execution plan of this statement, `hash join` specified in the SESSION binding is used, instead of `sort merge join` specified in the GLOBAL binding.
explain SELECT * FROM t1, t2 WHERE t1.id = t2.id;

最初のSELECTステートメントが実行されると、オプティマイザーは GLOBAL スコープのバインディングを介してステートメントにsm_join(t1, t2)ヒントを追加します。 explain番目の結果の実行計画の最上位ノードは MergeJoin です。 2 番目のSELECTステートメントが実行されると、オプティマイザーは GLOBAL スコープのバインディングではなく SESSION スコープのバインディングを使用し、ステートメントにhash_join(t1, t2)ヒントを追加します。 explainの結果の実行計画のトップノードはHashJoinです。

標準化された各 SQL ステートメントは、一度にCREATE BINDINGつを使用して作成されたバインディングを 1 つだけ持つことができます。同じ標準化された SQL ステートメントに対して複数のバインディングが作成されると、最後に作成されたバインディングが保持され、以前に作成されたすべてのバインディング (作成および展開されたもの) は削除済みとしてマークされます。ただし、セッション バインディングとグローバル バインディングは共存でき、このロジックの影響を受けません。

さらに、バインディングを作成するとき、TiDB はセッションがデータベース コンテキスト内にあることを要求します。つまり、クライアントが接続されたとき、またはuse ${database}が実行されたときにデータベースが指定されます。

元の SQL ステートメントとバインドされたステートメントは、正規化とヒントの削除後に同じテキストを持っている必要があります。そうでない場合、バインドは失敗します。次の例を見てください。

  • このバインドは、パラメーター化とヒントの削除の前後のテキストが同じであるため、正常に作成できます: SELECT * FROM test . t WHERE a > ?

    CREATE BINDING FOR SELECT * FROM t WHERE a > 1 USING SELECT * FROM t use index  (idx) WHERE a > 2
    
  • 元の SQL ステートメントはSELECT * FROM test . t WHERE a > ?として処理されるのに対し、バインドされた SQL ステートメントはSELECT * FROM test . t WHERE b > ?として異なる方法で処理されるため、このバインドは失敗します。

    CREATE BINDING FOR SELECT * FROM t WHERE a > 1 USING SELECT * FROM t use index(idx) WHERE b > 2
    

ノート:

PREPARE / EXECUTEステートメントおよびバイナリ プロトコルで実行されるクエリの場合、 PREPARE / EXECUTEステートメントではなく、実際のクエリ ステートメントに対して実行プラン バインディングを作成する必要があります。

バインディングを削除

DROP [GLOBAL | SESSION] BINDING FOR BindableStmt;

このステートメントは、GLOBAL または SESSION レベルで指定された実行計画バインディングを削除します。デフォルトのスコープは SESSION です。

一般に、SESSION スコープのバインディングは、主にテストまたは特別な状況で使用されます。すべての TiDB プロセスでバインディングを有効にするには、GLOBAL バインディングを使用する必要があります。作成された SESSION バインディングは、セッションが終了する前に SESSION バインディングが削除された場合でも、SESSION が終了するまで対応する GLOBAL バインディングを保護します。この場合、バインディングは有効ではなく、プランはオプティマイザによって選択されます。

次の例は、SESSION バインディングが GLOBAL バインディングを保護するバインディングを作成するの例に基づいています。

-- Drops the binding created in the SESSION scope.
drop session binding for SELECT * FROM t1, t2 WHERE t1.id = t2.id;

-- Views the SQL execution plan again.
explain SELECT * FROM t1,t2 WHERE t1.id = t2.id;

上記の例では、SESSION スコープで削除されたバインドにより、GLOBAL スコープの対応するバインドがシールドされます。オプティマイザーは、ステートメントにsm_join(t1, t2)ヒントを追加しません。 explain結果の実行計画の最上位ノードは、このヒントによって MergeJoin に固定されません。代わりに、最上位ノードは、コスト見積もりに従って最適化プログラムによって個別に選択されます。

ノート:

DROP GLOBAL BINDINGを実行すると、現在の tidb-server インスタンス キャッシュ内のバインディングが削除され、システム テーブル内の対応する行のステータスが「削除済み」に変更されます。このステートメントは、システム テーブル内のレコードを直接削除しません。他の tidb-server インスタンスは、キャッシュ内の対応するバインディングを削除するために「削除済み」ステータスを読み取る必要があるためです。これらのシステム テーブル内のステータスが「削除済み」のレコードの場合、100 bind-info-lease (デフォルト値は3sで、合計で300s ) の間隔ごとに、バックグラウンド スレッドは 10 より前にupdate_timeのバインディングで回収およびクリアの操作をトリガーします。 bind-info-lease (すべての tidb-server インスタンスが「削除済み」ステータスを読み取り、キャッシュを更新したことを確認するため)。

バインディング ステータスの変更

SET BINDING [ENABLED | DISABLED] FOR BindableStmt;

このステートメントを実行して、バインディングのステータスを変更できます。デフォルトのステータスは ENABLED です。有効なスコープはデフォルトで GLOBAL であり、変更できません。

このステートメントを実行すると、バインディングのステータスをDisabledからEnabledまたはEnabledからDisabledにのみ変更できます。ステータス変更に使用できるバインディングがない場合は、 There are no bindings can be set the status. Please check the SQL textという警告メッセージが返されます。 Disabledステータスのバインディングは、どのクエリでも使用されないことに注意してください。

バインディングをビュー

SHOW [GLOBAL | SESSION] BINDINGS [ShowLikeOrWhere]

このステートメントは、バインディングの更新時刻が新しいものから古いものへの順序に従って、GLOBAL または SESSION レベルで実行計画バインディングを出力します。デフォルトのスコープは SESSION です。現在、以下に示すように、 SHOW BINDINGSは 8 つの列を出力します。

カラム名ノート
original_sqlパラメータ化後の元の SQL ステートメント
bind_sqlヒント付きのバインドされた SQL ステートメント
default_dbデフォルトのデータベース
状態有効 (v6.0 の使用中ステータスを置き換える)、無効、削除済み、無効、拒否済み、および検証保留中を含むステータス
create_time時を創る
update_time更新時間
文字コードキャラクターセット
照合順序注文規則
ソースmanual ( create [global] binding SQL ステートメントによって作成される)、 capture (TiDB によって自動的にキャプチャされる)、およびevolve (TiDB によって自動的に展開される) を含むバインディングが作成される方法

バインディングのトラブルシューティング

バインディングのトラブルシューティングには、次のいずれかの方法を使用できます。

  • システム変数last_plan_from_bindingを使用して、最後に実行されたステートメントで使用された実行プランがバインディングからのものかどうかを示します。

    -- Create a global binding
    CREATE GLOBAL BINDING for
        SELECT * FROM t
    USING
        SELECT /*+ USE_INDEX(t, idx_a) */ * FROM t;
    
    SELECT * FROM t;
    SELECT @@[SESSION.]last_plan_from_binding;
    
    +--------------------------+
    | @@last_plan_from_binding |
    +--------------------------+
    |                        1 |
    +--------------------------+
    1 row in set (0.00 sec)
    
  • explain format = 'verbose'ステートメントを使用して、SQL ステートメントのクエリ プランを表示します。 SQL ステートメントでバインディングが使用されている場合は、 show warningsを実行して、SQL ステートメントで使用されているバインディングを確認できます。

    -- Create a global binding
    
    CREATE GLOBAL BINDING for
        SELECT * FROM t
    USING
        SELECT /*+ USE_INDEX(t, idx_a) */ * FROM t;
    
    -- Use explain format = 'verbose' to view the execution plan of a SQL statement
    
    explain format = 'verbose' SELECT * FROM t;
    
    -- Run `show warnings` to view the binding used in the query.
    
    show warnings;
    
    +-------+------+--------------------------------------------------------------------------+
    | Level | Code | Message                                                                  |
    +-------+------+--------------------------------------------------------------------------+
    | Note  | 1105 | Using the bindSQL: SELECT /*+ USE_INDEX(`t` `idx_a`)*/ * FROM `test`.`t` |
    +-------+------+--------------------------------------------------------------------------+
    1 row in set (0.01 sec)
    
    

キャッシュ バインディング

各 TiDB インスタンスには、バインディング用の LRU (Least Recent Used) キャッシュがあります。キャッシュ容量は、システム変数tidb_mem_quota_binding_cacheによって制御されます。 TiDB インスタンスにキャッシュされているバインディングを表示できます。

バインディングのキャッシュ ステータスを表示するには、 SHOW binding_cache statusステートメントを実行します。このステートメントでは、有効範囲はデフォルトで GLOBAL であり、変更できません。このステートメントは、キャッシュ内の使用可能なバインディングの数、システム内の使用可能なバインディングの合計数、キャッシュされたすべてのバインディングのメモリ使用量、およびキャッシュの合計メモリを返します。


SHOW binding_cache status;
+-------------------+-------------------+--------------+--------------+
| bindings_in_cache | bindings_in_table | memory_usage | memory_quota |
+-------------------+-------------------+--------------+--------------+
|                 1 |                 1 | 159 Bytes    | 64 MB        |
+-------------------+-------------------+--------------+--------------+
1 row in set (0.00 sec)

ベースラインのキャプチャ

アップグレード中の実行計画の後退を防ぐに使用されるこの機能は、キャプチャ条件を満たすクエリをキャプチャし、これらのクエリのバインディングを作成します。

キャプチャを有効にする

ベースラインのキャプチャを有効にするには、 tidb_capture_plan_baselinesonに設定します。デフォルト値はoffです。

ノート:

自動バインディング作成機能は声明の要約に依存しているため、自動バインディングを使用する前に必ず Statement Summary を有効にしてください。

バインディングの自動作成を有効にすると、Statement Summary の履歴 SQL ステートメントがbind-info-leaseごとにトラバースされ (デフォルト値は3s )、少なくとも 2 回出現する SQL ステートメントに対してバインディングが自動的に作成されます。これらの SQL ステートメントの場合、TiDB は Statement Summary に記録された実行計画を自動的にバインドします。

ただし、TiDB は、次のタイプの SQL ステートメントのバインディングを自動的にキャプチャしません。

  • EXPLAINおよびEXPLAIN ANALYZEステートメント。
  • 統計情報を自動的にロードするために使用されるSELECTクエリなど、TiDB で内部的に実行される SQL ステートメント。
  • EnabledつまたはDisabledのバインディングを含むステートメント。
  • 条件を取得することによって除外されるステートメント。

ノート:

現在、バインディングは、クエリ ステートメントによって生成された実行プランを修正するためのヒントのグループを生成します。このように、同じクエリの場合、実行計画は変更されません。同じインデックスまたは結合アルゴリズム (HashJoin や IndexJoin など) を使用するクエリを含むほとんどの OLTP クエリでは、TiDB はバインディングの前後でプランの一貫性を保証します。ただし、ヒントの制限により、TiDB は、3 つ以上のテーブルの結合、MPP クエリ、複雑な OLAP クエリなど、一部の複雑なクエリのプランの一貫性を保証できません。

PREPARE / EXECUTEステートメントとバイナリ プロトコルで実行されるクエリの場合、TiDB はPREPARE / EXECUTEステートメントではなく、実際のクエリ ステートメントのバインディングを自動的にキャプチャします。

ノート:

TiDB には一部の機能の正確性を確保するために SQL ステートメントが埋め込まれているため、ベースライン キャプチャはデフォルトでこれらの SQL ステートメントを自動的に保護します。

バインディングを除外する

この機能を使用すると、ブロックリストを構成して、バインディングをキャプチャしたくないクエリを除外できます。ブロックリストには、テーブル名、頻度、およびユーザー名の 3 つのディメンションがあります。

使用法

フィルタリング条件をシステム テーブルに挿入しますmysql.capture_plan_baselines_blacklist 。その後、フィルター条件はクラスター全体ですぐに有効になります。

-- Filter by table name
 INSERT INTO mysql.capture_plan_baselines_blacklist(filter_type, filter_value) VALUES('table', 'test.t');

-- Filter by database name and table name through wildcards
 INSERT INTO mysql.capture_plan_baselines_blacklist(filter_type, filter_value) VALUES('table', 'test.table_*');
 INSERT INTO mysql.capture_plan_baselines_blacklist(filter_type, filter_value) VALUES('table', 'db_*.table_*');

-- Filter by frequency
 INSERT INTO mysql.capture_plan_baselines_blacklist(filter_type, filter_value) VALUES('frequency', '2');

-- Filter by user name
 INSERT INTO mysql.capture_plan_baselines_blacklist(filter_type, filter_value) VALUES('user', 'user1');
ディメンション名説明備考
テーブルテーブル名でフィルタリングします。各フィルタリング ルールはdb.table形式です。サポートされているフィルタリング構文には、 プレーンなテーブル名ワイルドカードが含まれます。大文字小文字を区別しません。テーブル名に不正な文字が含まれている場合、ログは警告メッセージ[sql-bind] failed to load mysql.capture_plan_baselines_blacklistを返します。
周波数頻度でフィルタリングします。複数回実行された SQL ステートメントは、デフォルトでキャプチャされます。頻繁に実行されるステートメントをキャプチャするために、高い頻度を設定できます。frequency を 1 より小さい値に設定することは違法と見なされ、ログは警告メッセージ[sql-bind] frequency threshold is less than 1, ignore itを返します。複数の頻度フィルタ ルールが挿入されている場合は、頻度が最も高い値が優先されます。
ユーザーユーザー名でフィルタリングします。ブロックリストに登録されたユーザーによって実行されたステートメントはキャプチャされません。複数のユーザーが同じステートメントを実行し、そのユーザー名がすべてブロックリストにある場合、このステートメントはキャプチャされません。

ノート:

  • ブロックリストを変更するには、スーパー権限が必要です。

  • ブロックリストに不正なフィルターが含まれている場合、TiDB はログに警告メッセージ[sql-bind] unknown capture filter type, ignore itを返します。

アップグレード中の実行計画の後退を防ぐ

TiDB クラスターをアップグレードする前に、次の手順を実行することにより、ベースライン キャプチャを使用して実行計画の回帰を防ぐことができます。

  1. ベースラインのキャプチャを有効にして、引き続き機能させます。

    ノート:

    テスト データは、ベースライン キャプチャの長期的な作業がクラスター負荷のパフォーマンスにわずかな影響を与えることを示しています。したがって、重要な計画 (2 回以上表示される) がキャプチャされるように、可能な限りベースラインのキャプチャを有効にすることをお勧めします。

  2. TiDB クラスターをアップグレードします。アップグレード後、TiDB はこれらのキャプチャされたバインディングを使用して、実行計画の一貫性を確保します。

  3. アップグレード後、必要に応じてバインディングを削除します。

    • SHOW GLOBAL BINDINGSステートメントを実行してバインディング ソースを確認します。

      出力のSourceフィールドをチェックして、バインディングがキャプチャされているか ( capture )、手動で作成されているか ( manual ) を確認します。

    • キャプチャされたバインディングを保持するかどうかを決定します。

      -- View the plan with the binding enabled
      SET @@SESSION.TIDB_USE_PLAN_BASELINES = true;
      EXPLAIN FORMAT='VERBOSE' SELECT * FROM t1 WHERE ...;
      
      -- View the plan with the binding disabled
      SET @@SESSION.TIDB_USE_PLAN_BASELINES = false;
      EXPLAIN FORMAT='VERBOSE' SELECT * FROM t1 WHERE ...;
      
      • 実行計画に一貫性がある場合は、バインディングを安全に削除できます。

      • 実行計画に一貫性がない場合は、統計を確認するなどして原因を特定する必要があります。この場合、計画の一貫性を確保するためにバインディングを保持する必要があります。

ベースラインの進化

ベースラインの進化は、TiDB v4.0 で導入された SPM の重要な機能です。

データが更新されると、以前にバインドされた実行計画が最適でなくなる可能性があります。ベースライン進化機能は、バインドされた実行計画を自動的に最適化できます。

さらに、ベースラインの進化は、統計情報の変更によって実行計画にもたらされるジッタをある程度回避することもできます。

使用法

自動バインディングの進化を有効にするには、次のステートメントを使用します。

SET GLOBAL tidb_evolve_plan_baselines = ON;

tidb_evolve_plan_baselinesのデフォルト値はoffです。

自動バインディング進化機能が有効になった後、オプティマイザによって選択された最適な実行計画がバインディング実行計画に含まれていない場合、オプティマイザはその計画を検証を待つ実行計画としてマークします。 bind-info-lease (デフォルト値は3s ) 間隔ごとに、検証する実行計画が選択され、実際の実行時間に関して最小のコストを持つバインディング実行計画と比較されます。検証対象の計画の実行時間が短い場合 (現在の比較基準は、検証対象の計画の実行時間が拘束力のある実行計画の実行時間の 2/3 を超えないことです)、この計画は使用可能としてマークされます。バインディング。次の例では、上記のプロセスについて説明します。

tが次のように定義されているとします。

CREATE TABLE t(a INT, b INT, KEY(a), KEY(b));

テーブルtに対して次のクエリを実行します。

SELECT * FROM t WHERE a < 100 AND b < 100;

上で定義した表では、 a < 100の条件を満たす行はほとんどありません。しかし、何らかの理由で、オプティマイザーは、インデックスaを使用する最適な実行計画ではなく、誤って全テーブル スキャンを選択します。まず、次のステートメントを使用してバインディングを作成できます。

CREATE GLOBAL BINDING for SELECT * FROM t WHERE a < 100 AND b < 100 using SELECT * FROM t use index(a) WHERE a < 100 AND b < 100;

上記のクエリが再度実行されると、オプティマイザーはクエリ時間を短縮するためにインデックスa (上記で作成されたバインディングの影響を受ける) を選択します。

テーブルtで挿入と削除が実行されると、条件a < 100を満たす行数が増加し、条件b < 100を満たす行数が減少するとします。現時点では、バインディングでインデックスaを使用することは、最適な計画ではない可能性があります。

バインディングの進化は、この種の問題に対処できます。オプティマイザーは、テーブル内のデータの変更を認識すると、インデックスbを使用するクエリの実行プランを生成します。ただし、現在のプランのバインドが存在するため、このクエリ プランは採用されず、実行されません。代わりに、この計画はバックエンド進化リストに保存されます。展開プロセス中に、この計画がインデックスaを使用する現在の実行計画よりも明らかに短い実行時間であることが確認された場合、インデックスbが使用可能なバインディング リストに追加されます。この後、クエリが再度実行されると、オプティマイザーは最初にインデックスbを使用する実行プランを生成し、このプランがバインディング リストに含まれていることを確認します。次に、オプティマイザーはこの計画を採用して実行し、データ変更後のクエリ時間を短縮します。

自動進化がクラスターに与える影響を軽減するには、次の構成を使用します。

  • 各実行計画の最大実行時間を制限するには、 tidb_evolve_plan_task_max_timeを設定します。デフォルト値は600sです。実際の検証プロセスでは、最大実行時間も、検証済みの実行計画の時間の 2 倍を超えないように制限されます。
  • 時間枠を制限するには、 tidb_evolve_plan_task_start_time (デフォルトでは00:00 +0000 ) とtidb_evolve_plan_task_end_time (デフォルトでは23:59 +0000 ) を設定します。

ノート

ベースラインの進化によって新しいバインディングが自動的に作成されるため、クエリ環境が変化すると、自動的に作成されたバインディングに複数の動作の選択肢が生じる場合があります。次の注意事項に注意してください。

  • ベースラインの進化は、少なくとも 1 つのグローバル バインディングを持つ標準化された SQL ステートメントのみを進化させます。

  • 新しいバインディングを作成すると以前のすべてのバインディングが削除されるため (標準化された SQL ステートメントの場合)、新しいバインディングを手動で作成すると、自動的に展開されたバインディングが削除されます。

  • 計算プロセスに関連するすべてのヒントは、進化中に保持されます。これらのヒントは次のとおりです。

    ヒント説明
    memory_quotaクエリに使用できる最大メモリ。
    use_tojaオプティマイザーがサブクエリを Join に変換するかどうか。
    use_cascadesカスケード オプティマイザを使用するかどうか。
    no_index_mergeオプティマイザーがテーブルを読み取るためのオプションとして Index Merge を使用するかどうか。
    read_consistent_replicaテーブルの読み取り時に強制的にフォロワー読み取りを有効にするかどうか。
    max_execution_timeクエリの最長期間。
  • read_from_storageは、テーブルを読み取るときに TiKV からデータを読み取るか、TiFlash からデータを読み取るかを指定するという点で、特別なヒントです。 TiDB は分離読み取りを提供するため、分離条件が変更された場合、このヒントは進化した実行計画に大きな影響を与えます。したがって、このヒントが最初に作成されたバインディングに存在する場合、TiDB はすべての進化したバインディングを無視します。

アップグレードのチェックリスト

クラスターのアップグレード中に、SQL Plan Management (SPM) が互換性の問題を引き起こし、アップグレードが失敗する可能性があります。アップグレードを確実に成功させるには、アップグレードの事前チェックに次のリストを含める必要があります。

  • v5.2.0 より前のバージョン (つまり、v4.0、v5.0、および v5.1) から現在のバージョンにアップグレードする場合は、アップグレードの前にtidb_evolve_plan_baselinesが無効になっていることを確認してください。この変数を無効にするには、次の手順を実行します。

    -- Check whether `tidb_evolve_plan_baselines` is disabled in the earlier version.
    
    SELECT @@global.tidb_evolve_plan_baselines;
    
    -- If `tidb_evolve_plan_baselines` is still enabled, disable it.
    
    SET GLOBAL tidb_evolve_plan_baselines = OFF;
    
  • v4.0 から現在のバージョンにアップグレードする前に、使用可能な SQL バインディングに対応するすべてのクエリの構文が新しいバージョンで正しいかどうかを確認する必要があります。構文エラーが存在する場合は、対応する SQL バインディングを削除します。これを行うには、次の手順を実行します。

    -- Check the query corresponding to the available SQL binding in the version to be upgraded.
    
    SELECT bind_sql FROM mysql.bind_info WHERE status = 'using';
    
    -- Verify the result from the above SQL query in the test environment of the new version.
    
    bind_sql_0;
    bind_sql_1;
    ...
    
    -- In the case of a syntax error (ERROR 1064 (42000): You have an error in your SQL syntax), delete the corresponding binding.
    -- For any other errors (for example, tables are not found), it means that the syntax is compatible. No other operation is needed.
    
エコシステム
TiDB
TiKV
TiSpark
Chaos Mesh
© 2022 PingCAP. All Rights Reserved.