の暗黙的および明示的なソートの削除MySQLでは、歴史的にGROUP BYもソートを提供するために使用されていました。 クエリでGROUP BYが指定されている場合、結果はクエリにORDER BYが存在するかのようにソートされました。p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mysql-5.7> CREATE TABLE t (id INTEGER, cnt INTEGER);
Query OK, 0 rows affected (0.03秒)
mysql-5.7>t値に挿入します(4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6); クエリOK、影響を受けた12行(0.02秒)
レコード:12重複:0警告:0
mysql-5.7>SELECT id、SUM(cnt)FROM t GROUP BY id;
レコード:12重複:0警告:0
mysql-5.7>
SELECT ID、SUM(cnt)FROM t GROUP BY id;
+——+———-+
|id|SUM(cnt)|
+——+———-+
| 1 | 13 |
| 2 | 9 |
| 3 | 12 |
| 4 | 6 |
+——+———-+
セット内の4行(0。00 sec)
|
MySQL here implicitly sorts the results from GROUP BY (i.e. in the absence of ASC
or DESC
designators for GROUP BY
columns ).
MySQL also supported explicit sorting with GROUP BY (i.e. by using explicit ASC
or DESC
designators for GROUP BY
columns).
1
2
3
4
5
6
7
8
9
10
|
mysql-5.7> SELECT id, SUM(cnt) FROM t GROUP BY id DESC;
+——+———-+
|id|SUM(cnt)|
+——+———-+
| 4 | 6 |
| 3 | 12 |
| 2 | 9 |
| 1 | 13 |
+——+———-+
4行セット、1警告(0.00秒)
|
これは、GROUP BYの暗黙的または明示的なソートをサポートしていないため、8.0で変更されました。 このブログ記事では、なぜこの変更が必要になったのか、またこの変更の前兆として行われた作業について説明します。MYSQLのGROUP BY
行のセットをグループ化するには、MySQLオプティマイザは異なるメソッドを選択します。 そのうちの1つは、行をグループ化する前に行をソートすることです。 これにより、グループを次々にグループ化することが容易になります。 また、ソートされた行を取得するために使用できるインデックスがある場合は、安価になります。 インデックスがない場合でも、MySQL optimizerはグループ化する前に外部(filesort)ソートを行うことを決定できます。/div>
25
例に見られるように、テーブルにインデックスを追加する前に、MySQLは外部ソートを使用してGROUP BYを実行します。 例のクエリでは、SQL_BIG_RESULTを使用して計画を強制しました(MySQLは私たちが持っているデータセットに対してこの計画を選択しないため)。 しかし、MySQLは、ソートされた行を取得するためにインデックスがない場合にグループ化するためにこの計画を使用し、グループの数が多いために一時テーブル 索引が追加されると、索引を使用してGROUP BYを実行することになります。
しかし、グループ化する前に行をソートすることは必要ではありません。 オプティマイザは、一時テーブルを使用してそれを行うことを決定できます。 このテーブルの各行はグループ化された行になり、受信する行ごとに、テーブル内のそのグループに対応する行が更新されます。 ここではソートは必要ありません。 ただし、MySQLのGROUP BYはソートされると予想されていたため、この場合でもグループ化された行をソートする必要がありました。/div>1
クエリ例では、一時テーブルが使用されていますが、MySQLはまだ外部ソートを行います。 ユーザーは、MYSQLにGROUP BYがソートする必要がないことを知らせるために、ORDER BY NULLを明示的に指定する必要があります。 そのため、別の非標準拡張(GROUP BY sorting)の効果に対抗するために、非標準(ORDER BY NULL)構文が必要でした。 それは私達がその混乱を除去したので大いによりきれいである。GROUP BYの暗黙的なソートの削除
いくつかの時間前に私はバグ71804を修正しようとしていました。 Reporterは、MySQLがGROUP BYのために行っていた不要なファイルソートを行わないことを期待していました。 バグのパッチを作成しようとすると、この特定の状況を最適化することは、そのGROUP BYが提供する暗黙的および明示的なソートのサポートのためにあまり そのため、この最適化を行う前に、GROUP BYのソートに関連するコードを再因数分解する必要があると結論付けました。その最初のステップは、GROUP BYの暗黙的なソートを削除することでした。 ここのユーザーマニュアルに記載されているように、しばらく前にサポートを削除することにしました。 これは、8.0の降順インデックス機能の一部として行われています。p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2
|
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
19
19
19
19
19
19
19
19
19
19
19
19>
mysql>SELECT id,SUM(cnt)FROM T GROUP BY id;
+——+———-+
|id|SUM(cnt)|
+——+———-+
| 4 | 6 |
| 3 | 12 |
| 1 | 13 |
| 2 | 9 |
+——+———-+ mysql>EXPLAIN SELECT id,SUM(cnt)FROM t GROUP BY id\G
セット内の4行(0.00秒)
mysql>EXPLAIN SELECT id,SUM(cnt)FROM t GROUP BY id\G
*************************** 1. 行***************************
id:1
select_type:SIMPLE
テーブル: /div>
行数:12
フィルタリング:100.00
余分:一時的な使用
セット内の1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)
1行、1つの警告(0.00秒)div>
|
上記の例に見られるように、クエリに対してソートは実行されません。 その結果、グループ化された行は最終的な結果でソートされません。 ユーザーがソートされた行が必要な場合は、クエリでORDER BYを指定する必要があります。
MySQL5で。7および版の下で、ユーザーはマニュアルの次の警告を見つけます。
“GROUP BY
ASC
DESC
GROUP BY
GROUP BY
ASC
DESC
GROUP BY
ASC
DESC
GROUP BY
ORDER BY
句を指定します。 “
GROUP BYの明示的な並べ替えの削除
明示的な並べ替えの削除に関しては、それを行うのはもう少し難しいでした。 MySQLがROLLUPでORDER BYをサポートしていない限り、削除できませんでした。 ORDER BYを使用したROLLUPは、MySQL5.7以前のバージョンでは許可されていませんでした。 そのため、別の方法として、ユーザーはGROUP BY ASC/DESCを使用してrollupでソートされたデータを取得します(ただし、ASCの場合はsuper aggregate行が常に計算に使用された行の後に配置され、DESCの場合はその逆もあります)。 GROUP BYの明示的なソートのサポートを削除する前に、この制限を解除する必要がありました。
MySQLでは、ORDER BY with ROLLUPが許可されるようになりました。 私はここでこの改善を利用する方法について詳細に説明しました。 同じブログで説明したように、ユーザーがMySQL5.7のロールアップとまったく同じNullのソート順序を望む場合は、GROUPING()関数を使用して簡単な方法でクエリを書き直要するに、GROUP BYの明示的なソートを削除する前に、次のことを行っています。
1. GROUPING()関数の追加
2. GROUP BY
の暗黙的なソートの削除3. ROLLUPでORDER BYを許可し、最後にMySQL8.0.13でGROUP BYの明示的なソートを削除しました。私たちはコミュニティの意見をいくつかの時間前に求めました。
MySQLが提供するこの非標準の拡張機能を認識していたユーザーは、それが消えても問題ないと結論づけました。
結論
バグ71804を修正する前に、まだいくつかの作業がありますが、これが完了したことを嬉しく思います。 ご感想をお聞かせください。 MySQLを使用してくれてありがとう!