SQL クエリ内の冗長な GROUP BY 句または ORDER BY 句は、データベースに不要なソートまたはハッシュ操作を実行させます。これらの操作は、大量の CPU およびメモリリソースを消費し、特に大規模なデータセットを扱う場合に、分析処理 (AP) クエリのパフォーマンスに深刻な影響を与えます。PolarDB for MySQL の GROUP BY/ORDER BY 削除機能は、関数従属性に基づいて、これらの冗長な操作を自動的に検出し、削除します。この機能は、アプリケーションコードを変更することなく、TPC-H ベンチマークで最大 29% の大幅なパフォーマンス向上を実現し、分析クエリのリソース消費を削減できます。
適用範囲
製品シリーズ:Cluster Edition、Standard Edition。
バージョン:MySQL 8.0.2、リビジョン 8.0.2.2.33 以降。
削除機能の有効化
この最適化機能の動作は、loose_groupby_elimination_mode および loose_orderby_elimination_mode パラメーターを設定することで制御できます。
PolarDB クラスターのパラメーターを変更する方法は、コンソールとデータベースセッションで異なります。違いは次のとおりです:
互換性:MySQL 設定ファイルとの互換性のため、PolarDB コンソールの一部のクラスターパラメーターには loose_ プレフィックスが付いています。
手順:
loose_プレフィックスが付いているパラメーターを見つけて変更します。
データベースセッション (コマンドラインまたはクライアントを使用)
手順:
SETコマンドを使用してデータベースセッションでパラメーターを変更する場合は、loose_プレフィックスを削除し、元のパラメーター名を使用します。
パラメーター名 | レベル | 説明 |
| グローバル/セッション |
|
|
|
仕組み
GROUP BY/ORDER BY 削除機能は、関数従属性 (FD) を利用します。この機能の仕組みを理解することで、より良い SQL を記述し、最適化が適用されるかどうかを予測できます。
関数従属性とは? 列 A (または列のセット) の値が列 B の値を一意に決定する場合、B は A に関数従属しています。この関係は
A -> Bと記述されます。例えば、ユーザーテーブルでは、プライマリキーuser_idがnicknameを一意に決定します。したがって、関数従属性user_id -> nicknameが存在します。オプティマイザーが関数従属性を見つける方法:PolarDB オプティマイザーは、次のメタデータとクエリ条件から依存関係を自動的に推測します:
プライマリキーとユニークキー:テーブルスキーマで定義された
PRIMARY KEYまたはUNIQUE KEYは、関数従属性の最も直接的なソースです。等価結合条件:プライマリキーの一意性は、
JOIN句のt1.pk = t2.fkなどの等価結合条件を介して、関連テーブルに伝播できます。定数フィルター条件:
WHERE句のWHERE status = 'active'などの等価フィルターは、結果セット内でその列を定数にします。
コア最適化ルール:
`GROUP BY` 削除:
GROUP BY句の列が、たとえばテーブルのプライマリキーを含むことによって、結果セットの各行をすでに一意に識別する場合、GROUP BYオペレーター全体は冗長であるため、安全に削除できます。GROUP BY句のすべての列が定数である場合、GROUP BYオペレーター全体を削除し、LIMIT 1に置き換えることができます。
`ORDER BY` の削除:
ORDER BY句のすべての列が定数である場合、ORDER BYオペレーター全体は冗長であるため安全に削除できます。`GROUP BY`/`ORDER BY` の簡略化:
GROUP BY句またはORDER BY句の列間に、GROUP BY x, yにおけるx -> yのように既知の関数従属性が存在する場合、その句をGROUP BY xに簡略化できます。これにより、グループ化またはソートに使用される列数が削減されます。
代表的な最適化シナリオと例
シナリオ 1:プライマリキーまたはユニークキーによるグループ化
GROUP BY 句にテーブルのプライマリキーまたは一意キーが含まれている場合、そのキーによってすでに一意の行が識別されるため、他の列でグループ化することは冗長です。
ビジネスシナリオ:各ユーザーの合計注文額を計算し、そのユーザー名を表示します。
元の SQL:
-- user_id は user テーブルのプライマリキーであり、user_name を一意に決定します。 SELECT u.user_id, u.user_name, COUNT(o.order_id) FROM user u JOIN orders o ON u.user_id = o.user_id GROUP BY u.user_id, u.user_name;最適化分析:
user_idはプライマリキーであるため、user_nameの値を一意に決定します。オプティマイザーは FDuser_id -> user_nameを検出し、GROUP BY u.user_id, u.user_nameをGROUP BY u.user_idに自動的に簡略化します。これにより、user_nameに対する不要なグループ化操作が排除されます。
シナリオ 2:定数によるグループ化
GROUP BY 句のすべてのカラムが定数である場合、結果セットに含まれる行は最大で 1 行になるため、グループ化操作全体が冗長になります。
ビジネスシナリオ:特定のユーザーの特定のステータス情報をクエリします。これは一般的ではない SQL パターンですが、オプティマイザーはこれを処理できます。
元の SQL:
SELECT a, b FROM t1 WHERE a = 1 AND b = 1 GROUP BY a, b;最適化分析:オプティマイザーは、
GROUP BY句の列aとbがWHERE句で定数として指定されていることを検出すると、GROUP BYオペレーターを削除し、LIMIT 1を追加します。SELECT a, b FROM t1 WHERE a = 1 AND b = 1 LIMIT 1;
シナリオ 3:複数テーブル結合における複雑なグループ化 (TPC-H Q10)
複数テーブル JOIN を使用する複雑なクエリでは、関数従属性が結合条件を介して伝播されることがあります。オプティマイザーは、この伝播を使用して、より複雑で冗長なグループ化を排除します。
元の SQL (TPC-H Q10):
SELECT c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment, SUM(l_extendedprice * (1 - l_discount)) AS revenue FROM customer, orders, lineitem, nation WHERE c_custkey = o_custkey AND l_orderkey = o_orderkey AND c_nationkey = n_nationkey -- その他のフィルター条件... GROUP BY c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment ORDER BY revenue DESC LIMIT 20;最適化分析:
プライマリキー依存:
customerテーブルでは、c_custkeyがプライマリキーです。そのため、c_name, c_acctbal, c_phone, c_address, c_comment, and c_nationkeyなどの他のすべての列を⼀意に決定します。依存関係の伝播:
JOIN条件はc_nationkey = n_nationkeyです。n_nationkeyはnationテーブルのプライマリキーであり、n_nameを決定するため、オプティマイザーはc_custkeyもn_nameを一意に決定すると推論できます。最終的な単純化: 要約すると、
GROUP BY句のc_nameやc_acctbalなどのすべての列は、c_custkeyに対して関数従属です。したがって、オプティマイザーは複雑なGROUP BYリストをGROUP BY c_custkeyに単純化します。これにより、グループ化の計算の複雑さが大幅に削減されます。
SELECT c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment, SUM(l_extendedprice * (1 - l_discount)) AS revenue FROM customer, orders, lineitem, nation WHERE c_custkey = o_custkey AND l_orderkey = o_orderkey AND c_nationkey = n_nationkey -- その他のフィルター条件... GROUP BY c_custkey ORDER BY revenue DESC LIMIT 20;
シナリオ 4:ORDER BY のシナリオ
ORDER BY 句内の列の間に関数従属性が存在する場合、オプティマイザーはソートする列の数を減らすことでソート操作を簡略化できます。
ビジネスシナリオ:一部の列が他の列によって一意に決定されるテーブルをソートします。
テーブルスキーマ:
CREATE TABLE t1 ( a int, b int, c int as (a + b) unique not null );元の SQL:
EXPLAIN SELECT a, b FROM t1 ORDER BY a,b,c;最適化分析: 列
cは、列aおよびbから計算され (c = a + b)、unique not nullとして定義されているため、関数従属性(a, b) -> cが存在します。オプティマイザーはこの従属性を認識し、ORDER BY a, b, cを自動的にORDER BY a, bに簡略化することで、ソート操作の複雑さを軽減します。SHOW warnings; +-------+------+-------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+-------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` | +-------+------+-------------------------------------------------------------------------------------------------------------------------------+
パフォーマンステスト
TPC-H 100 GB 標準データセットでのテストでは、GROUP BY 削除機能を有効にすると、Q10 クエリのパフォーマンスが大幅に向上することが示されています。
このトピックの TPC-H 実装は TPC-H ベンチマークに基づいており、公開されている TPC-H ベンチマーク結果と比較することはできません。このトピックで説明されているテストは、すべての TPC-H 要件に完全に準拠しているわけではありません。
以下のデータは特定のシナリオでのテストによるものです。実際のパフォーマンス向上率は、クエリの複雑さ、データ分布、クラスターの仕様などの要因によって異なる場合があります。
テストシナリオ |
| 無効にした場合 (実行時間) | パフォーマンスの向上 |
インメモリ列インデックス (IMCI) を 1 DOP で使用 (1 日以内のデータ生成) | 48 秒 | 68 秒 | 29% |
インメモリ列インデックス (IMCI) を 32 DOP で使用 (32 日以内のデータ生成) | 1.9 秒 | 2.6 秒 | 27% |