GROUP BY 演算子は主にSQLにおけるグループ集計演算を行うために使用されます。
データをグループ化するアルゴリズムとしては HASH アルゴリズムと MERGE アルゴリズムがあり、そのためアルゴリズムに基づいて GROUP BY 演算子は HASH GROUP BY と MERGE GROUP BY の2種類に分類されます。実行計画の生成時には、SQLオプティマイザーが両アルゴリズムのコスト評価に基づいて、どちらの GROUP BY 演算子を使用するかを選択します。
通常の集約関数(SUM/MAX/MIN/AVG/COUNT/STDDEV)も GROUP BY 演算子を割り当てることで実現されます。一方、集約関数のみで GROUP BY を含まないSQL文に対しては SCALAR GROUP BY 演算子が割り当てられるため、GROUP BY 演算子はさらに SCALAR GROUP BY、HASH GROUP BY、MERGE GROUP BY の3種類に分類できます。
SCALAR GROUP BY
例1:SCALAR GROUP BY演算子を含む実行計画
obclient> CREATE TABLE t1(c1 INT, c2 INT);
Query OK, 0 rows affected
obclient> INSERT INTO t1 VALUES(1, 1);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(2, 2);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(3, 3);
Query OK, 1 rows affected
Q1:
obclient> EXPLAIN SELECT SUM(c1) FROM t1;
Query Plan:
| ========================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------------
|0 |SCALAR GROUP BY| |1 |37 |
|1 | TABLE SCAN |T1 |3 |37 |
========================================
Outputs & filters:
-------------------------------------
0 - output([T_FUN_SUM(T1.C1)]), filter(nil),
group(nil), agg_func([T_FUN_SUM(T1.C1)])
1 - output([T1.C1]), filter(nil),
access([T1.C1]), partitions(p0)
上記の例では、Q1クエリの実行計画表示におけるoutputs & filtersに、SCALAR GROUP BY演算子の出力情報が詳細に示されています。
| 情報名 | 意味 |
|---|---|
| output | この演算子が出力する式。 |
| filter | この演算子におけるフィルタ条件。 例では、SCALAR GROUP BY 演算子に filter が設定されていないため、nil となります。 |
| group | グループ化を行う列。 例えば、Q1クエリでは SCALAR GROUP BY 演算子であるため、nil となります。 |
| agg_func | 関与する集約関数。 例えば、Q1クエリはテーブル t1 の c1 列のデータの合計を計算するため、T_FUN_SUM(t1.c1) となります。 |
HASH GROUP BY
例2:HASH GROUP BY 演算子を含む実行計画
Q2:
obclient> EXPLAIN SELECT SUM(c2) FROM t1 GROUP BY c1 HAVING SUM(c2) > 2;
Query Plan:
| ======================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
--------------------------------------
|0 |HASH GROUP BY| |1 |40 |
|1 | TABLE SCAN |T1 |3 |37 |
======================================
Outputs & filters:
-------------------------------------
0 - output([T_FUN_SUM(T1.C2)]), filter([T_FUN_SUM(T1.C2) > 2]),
group([T1.C1]), agg_func([T_FUN_SUM(T1.C2)])
1 - output([T1.C1], [T1.C2]), filter(nil),
access([T1.C1], [T1.C2]), partitions(p0)
上記の例では、Q2クエリの実行計画表示における outputs & filters で、HASH GROUP BY 演算子の出力情報が以下のように詳細に示されています。
| 情報名 | 意味 |
|---|---|
| output | この演算子が出力する式。 |
| filter | この演算子におけるフィルタ条件。 グループ化後の c2 列の合計が2より大きいことを設定要件としているため、T_FUN_SUM(t1.c2) > 2 となります。 |
| group | グループ化する列。 例えば、Q2クエリは t1 テーブルの c1 列をグループ化するため、T1.C1 となります。 |
| agg_func | 関与する集約関数。 例えば、Q2クエリではテーブル t1 の c2 列の合計を計算するため、T_FUN_SUM(t1.c2) となります。 |
説明
HASH GROUP BY 演算子は、実行時に HASH アルゴリズムを使用してグループ化することを保証します。
MERGE GROUP BY
例3:MERGE GROUP BY演算子を含む実行計画
Q3:
obclient> EXPLAIN SELECT /*+NO_USE_HASH_AGGREGATION*/SUM(c2) FROM t1 GROUP BY c1 HAVING SUM(c2) > 2;
Query Plan:
| =======================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
---------------------------------------
|0 |MERGE GROUP BY| |1 |45 |
|1 | SORT | |3 |44 |
|2 | TABLE SCAN |T1 |3 |37 |
=======================================
Outputs & filters:
-------------------------------------
0 - output([T_FUN_SUM(T1.C2)]), filter([T_FUN_SUM(T1.C2) > 2]),
group([T1.C1]), agg_func([T_FUN_SUM(T1.C2)])
1 - output([T1.C1], [T1.C2]), filter(nil), sort_keys([T1.C1, ASC])
2 - output([T1.C1], [T1.C2]), filter(nil),
access([T1.C1], [T1.C2]), partitions(p0)
上記の例では、Q3クエリの実行計画表示におけるoutputs & filtersにMERGE GROUP BY演算子の情報が詳細に示されています。同じSQLから実行計画が生成される際にMERGE GROUP BY演算子が選択されていることがわかります。その演算子の基本情報はすべて同一であり、最大の違いは実行時に選択されるグループ化アルゴリズムが異なる点です。また、ここでの2番目の演算子TABLE SCANが返す結果は無秩序な結果であり、GROUP BYアルゴリズムではMERGE GROUP BYが採用されているため、SORT演算子を割り当てる必要があります。
注意
NO_USE_HASH_AGGREGATIONおよびUSE_HASH_AGGREGATIONのヒントは、GROUP BY演算子がどのアルゴリズムを使用してグループ化するかを制御するために使用できます。