web-dev-qa-db-ja.com

GROUP BYは、ファイルソートを回避するためにORDER BY NULLを必要とします

EXPLAINGROUP BY句を使用してクエリを実行すると、追加の条件としてfilesortが返されることに繰り返し気付きました。ずっと前に、私はこれらのケースでGROUP BY NULLを使用してfilesortを回避するという提案を読みましたが、実際に不快に見えるfilesort状態を排除しています。

ORDER BY句が存在しない場合、dbmsは、ファイルソートを必要とする不思議な列による順序付けではなく、任意の順序または最も効率的なものを提示するだけだと思います。基本的に"愚かなことは何もしない"と言ってくれる追加の指示を含める必要があるのは不思議に思えます。

私の質問は、なぜこれが必要なのか、そしてORDER BY NULLを追加することが実際にパフォーマンスに役立つのかということです。

5
billynoah

MySQL 5.7リファレンスマニュアル/ .../SELECT構文

GROUP BYを使用する場合、出力列は、同じ列にORDER BYがある場合と同様に、GROUP BY列に従ってソートされます。 GROUP BYが生成するソートのオーバーヘッドを回避するには、ORDER BY NULLを追加します

5
Akina

Using filesortは、グループ化に使用される列に適切なインデックスがない場合に表示されます。上記のように、GROUP BYによって返される結果は同じ列で並べ替えられます。並べ替え用にfilesortを取得した場合、グループ化用のfilesortもあります。それは同じようにパフォーマンスを侮辱します。したがって、ソートを抑制するためではなく、インデックスを作成する必要があります。

EXPLAIN 
SELECT w.t_id
     , count(1) AS counter
  FROM points AS w
 GROUP BY w.t_id
;

+----+-------------+-------+-------+---------------+-------+---------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows     | Extra       |
+----+-------------+-------+-------+---------------+-------+---------+------+----------+-------------+
|  1 | SIMPLE      | w     | index | t_id          | t_id  | 2       | NULL | 27228500 | Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+----------+-------------+

ORDER BY NULLがなければfilesortはありません。

SELECT w.t_id, count(1) AS counter FROM points AS w GROUP BY w.t_id;
/* Affected rows: 0  Found rows: 606  Warnings: 0  Duration for 1 query: 6,922 sec. */
SELECT w.t_id, count(1) AS counter FROM points AS w GROUP BY w.t_id ORDER BY NULL;
/* Affected rows: 0  Found rows: 606  Warnings: 0  Duration for 1 query: 6,781 sec. */

追伸.

Fidlleが失敗する限り、ここにmysql出力があります。

複数列のインデックスなし:

+----+-------------+---------------+------+-----------------+------+---------+------+------+----------------------------------------------------+
| id | select_type | table         | type | possible_keys   | key  | key_len | ref  | rows | Extra                                              |
+----+-------------+---------------+------+-----------------+------+---------+------+------+----------------------------------------------------+
|  1 | SIMPLE      | animals       | ALL  | PRIMARY         | NULL | NULL    | NULL |    3 | Using temporary; Using filesort                    |
|  1 | SIMPLE      | animal_colors | ALL  | animal_id,color | NULL | NULL    | NULL |    6 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+---------------+------+-----------------+------+---------+------+------+----------------------------------------------------+
2 rows in set (0.00 sec)

追加された複数列インデックス:

+----+-------------+---------------+-------+---------------------------------+-----------+---------+------------------------+------+-------------+
| id | select_type | table         | type  | possible_keys                   | key       | key_len | ref                    | rows | Extra       |
+----+-------------+---------------+-------+---------------------------------+-----------+---------+------------------------+------+-------------+
|  1 | SIMPLE      | animals       | index | PRIMARY                         | PRIMARY   | 4       | NULL                   |    3 | NULL        |
|  1 | SIMPLE      | animal_colors | ref   | animal_id,color,animal_id_color | animal_id | 4       | test.animals.animal_id |    1 | Using where |
+----+-------------+---------------+-------+---------------------------------+-----------+---------+------------------------+------+-------------+
2 rows in set (0.00 sec)
2
Kondybas