このトピックでは、PolarDB for MySQLがコストベースのクエリ変換 (CBQT) を使用して複雑なクエリの実行効率を向上させる方法について説明します。
前提条件
古いバージョンのクエリ変換
クラスターはPolarDB for MySQL 8.0.2で、リビジョンバージョンは8.0.2.2.0以降です。
新しいバージョンのクエリ変換
クラスターはPolarDB for MySQL 8.0.2で、リビジョンバージョンは8.0.2.2.19以降です。
クラスターのバージョンを確認する方法については、「エンジンバージョンの照会」をご参照ください。
背景情報
クエリ変換とは、クエリステートメントを別の同等のクエリステートメントに変換するプロセスを指します。 次のサンプルのクエリ文を参照してください。
SELECT *
FROM d1
JOIN f1 ON d1.c1 = f1.c1
LEFT JOIN (
SELECT d2.c2 AS d2_c2, f2.c3 AS f2_c3
FROM d2, f2
WHERE d2.c1 = f2.c1
) derived
ON derived.d2_c2 = d1.c2
AND derived.f2_c3 = f1.c3;
クエリステートメントは、具体化されたテーブルのマージルールに基づいて、次のクエリステートメントに変更できます。
SELECT *
FROM d1
JOIN f1 ON d1.c1 = f1.c1
LEFT JOIN (d2
JOIN f2 ON TRUE)
ON d2.c1 = f2.c1
AND f2.c3 = f1.c3
AND d2.c2 = d1.c2;
MySQL Community Editionは、セマンティック変換が実行されるルールベースのクエリ変換のみをサポートします。 上記の例は、MySQL Community Editionによって実行される一般的なクエリ変換です。 しかしながら、このような変換は、場合によっては性能最適化をもたらさない。 上記のクエリステートメントを例にとると、d1
、f1
、およびd2
、f2
のインデックスが相関していない場合、d1
およびf1
の結合演算の出力の各行には、d2
およびf2
の個別の結合演算が必要です。 その結果、実行効率が著しく低下する。 したがって、クエリ変換、特に複雑な変換は、実行コストに基づいて実行されるべきである。 カーディナリティ、アクセス方法、結合順序などの要因が実行コストに影響を与える場合があります。 PolarDB for MySQLは、実行コストに基づいて特定の種類の変換を実行できるコストベースのクエリ変換をサポートしています。
複雑なクエリの場合、CBQTはすべての可能な変換メソッドを組み合わせて、状態空間と呼ばれるコレクションにします。 次に、CBQTは、クエリのコストが最も低い実行プランを選択します。 次の図では、コストベースのクエリ変換プロセスについて説明します。 CBQTは、変換方法AおよびBを収集し、状態空間において以下の組み合わせを生成する: なし (変換なし) 、A (変換Aのみ) 、B (変換Bのみ) 、およびAB (変換AおよびBの両方) 。 状態空間内の組み合わせは、それぞれ実行プランに対応する。 次いで、CBQTは、コストが最も低い実行計画を選択する。 この例では、変換Aに対応するプラン2が選択される。さらに、実行コストを節約することができる変換は、ルールベースのクエリ変換として定義される。 このような変換は、クエリ変換ルールが満たされる場合に実行される。
上記のクエリ文を例に取ります。 マテリアライズドテーブルのマージ後の実行計画を次の図に示します。
マテリアライズドテーブルのマージ前の実行計画を次の図に示します。
どのプランが最適であるかは、d2
、f2
およびd1
、f1
のインデックスが相関しているかどうか、および結合結果セットのサイズに依存する。 インデックスが関連付けられている場合、マージ後の実行計画は最適です。 そうでない場合、マージ前の実行計画は最適です。 CBQTフレームワークは、テーブルマージの前後の実行計画のコストを計算して比較します。 現在のシナリオで最適なプランが選択されます。
条件
ネストされたクエリとネストの深さ
ネストされたクエリは、別のクエリにネストされたクエリブロックです。 クエリブロックはサブクエリまたは内部クエリであり、外部クエリは親クエリまたは外部クエリです。 ネストの深さは、クエリのネストされたレイヤーの数であり、主にサブクエリと具体化されたテーブルを記述するために使用されます。 例:
SELECT * FROM t1 WHERE t1.a IN (SELECT t2.b FROM t2 WHERE t2.c=t1.b);
入れ子の深さは2です。 親クエリはt1
テーブルをクエリするクエリステートメントであり、サブクエリはt2
テーブルをクエリするクエリステートメントです。
UNION文は、同じレイヤーのSQL文のみを結合します。 例:
SELECT *
FROM t1
WHERE t1.a IN (
SELECT dt.b
FROM (
SELECT b, c
FROM t2
UNION
SELECT b, c
FROM t3
) dt
WHERE dt.c = t1.b
);
上記のクエリ文の入れ子の深さは3です。 dt
テーブルのサブクエリは、UNION文を使用した同じレイヤーのSQL文の組み合わせです。
変革
背景情報のセクションで説明されている具体化されたテーブルマージなど、等価ルールに基づいてクエリを別の形式に変換するプロセス。
変換オブジェクト
[背景情報] セクションのマテリアライズドテーブルマージから派生したテーブルなど、同値ルールが適用されるオブジェクト。 異なる変換ルールが異なる変換オブジェクトに適用されます。 例えば、マテリアライズドテーブルマージの変換オブジェクトはマテリアライズドテーブルです。 サブクエリからSEMI JOIN文への変換の変換オブジェクトは、サブクエリです。
イテレーション
変換が実行される回数。 CBQTは、すべてのオブジェクトに対して可能なすべての変換を実行します。 変換が実行された後、いくつかのクエリブロックを再び変換することが可能である。 たとえば、サブクエリが具体化されたテーブルに変換された後、具体化されたテーブルマージルールを使用してテーブルを変換できます。 したがって、新しいオブジェクトに対して変換を実行する必要があります。 このプロセスは、CBQTの反復として知られている。 反復回数は、変換プロセスが繰り返し実行される回数である。
Usage
PolarDB for MySQLは、CBQTの2つのバージョンを提供します。 cbqt_enabled
パラメーターを設定して、機能を有効または無効にします。 cbqt_version
パラメーターを設定して、cbqtのバージョンを指定します。 cbqt_version
が1に設定されている場合、古いバージョンが使用されます。 cbqt_version
が2に設定されている場合、新しいバージョンが使用されます。
パラメーター | レベル | 説明 |
cbqt_enabled | グローバルとセッション | CBQTを有効または無効にします。 デフォルト値はONです。 有効な値:
|
cbqt_version | グローバルとセッション | CBQTのバージョンを指定します。 有効な値:
|
両方のバージョンのパラメータの詳細な説明を参照してください。
CBQTの旧バージョン
CBQTは、最適な実行プランを選択するのに長い時間を費やすことがある。 短期間のクエリへの影響を避けるために、cbqt_cost_threshold
パラメーターを使用して、クエリのCBQTをトリガーするためのしきい値を指定できます。 CBQTは、クエリのコストがこのパラメーター値を超えた場合にのみトリガーされます。 MySQL Community EditionではなくPolarDBによって提供されるサブクエリの場合、CBQTに基づくGROUP by句を使用して脱相関が実行されます。 MySQL Community Editionで提供される変換については、コストに基づいて実行するかどうかを指定できます。 派生マージ機能は、polar_optimizer_switch
パラメーターのderived_merge_cost_based
変数によって制御されます。
パラメーター | レベル | 説明 |
cbqt_cost_threshold | グローバルとセッション | クエリのCBQTをトリガーするためのしきい値。 CBQTは、クエリのコストがこのパラメーター値を超えた場合にのみトリガーされます。 有効な値: 0 ~ 18446744073709551615 デフォルト値:100000。 |
cbqt_timeout | グローバルとセッション | CBQTのタイムアウト期間。 最適な実行プランを見つけるのにかかる時間が指定された期間よりも長い場合、CBQTは最適なプランの検索を停止し、見つけた最適なプランを使用してクエリを実行します。 有効な値: 0 ~ 18446744073709551615 デフォルト値:200 単位:ミリ秒。 説明 値を0に設定した場合、タイムアウト期間は指定されません。 |
polar_optimizer_switch | グローバルとセッション | PolarDBのクエリ最適化機能を有効にするかどうかを指定します。 有効な値:
|
CBQTの新バージョン
CBQTは、反復を実行し、最適な実行プランを選択するのに長い時間を費やし得る。 プロセスを制御する次のパラメーターを設定できます。
パラメーター | レベル | 説明 |
cbqt_iteration_limit | グローバル | CBQTの反復回数。 繰り返し回数が多いほど、最適なプランを選択する可能性が高く、時間がかかることを示す。 反復回数が少ないほど、最適なプランを選択する可能性が低く、時間消費が少ないことを示す。 有効な値: 1 ~ 10。 デフォルト値は 1 です。 |
cbqt_max_nested_level | グローバルとセッション | CBQTが処理できるクエリ文の最大ネスト深さ。 クエリ文の入れ子の深さがこの値を超える場合、CBQTはクエリ文に実装されません。 有効な値: 1 ~ 64。 既定値:5 |
cbqt_search_strategy | グローバル | CBQTが最適なプランを選択するための戦略。 有効な値:
|
cbqt_rule_switch | グローバルとセッション | クエリ最適化機能を有効にするかどうか、およびクエリ変換を実行するかどうかを指定します。 有効な値:
|