web-dev-qa-db-ja.com

GROUP BYとCASEを使用して遅いクエリを高速化する方法は?

私はMySQLの経験があまりなく、GROUP BYおよびCASEステートメントを使用して遅いクエリを高速化する方法を理解しようとしています。

ケース1-GROUP BYおよびCASE


SELECT SQL_NO_CACHE m.id, m.sku, m.movie_url 
FROM movie.movies m               
WHERE m.s_id = 1                   
GROUP BY m.mg_id, CASE WHEN m.mg_id IS NULL THEN m.id ELSE 0 END
LIMIT 100

実行時間:1.025秒、1.042秒、0.946秒

出力の説明:

+----+-------------+-------+------+--------------------+----------+---------+-------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys      | key      | key_len | ref   | rows  | Extra                                        |
+----+-------------+-------+------+--------------------+----------+---------+-------+-------+----------------------------------------------+
|  1 | SIMPLE      | m     | ref  | ind_mg_id,ind_s_id | ind_s_id | 4       | const | 39941 | Using where; Using temporary; Using filesort |
+----+-------------+-------+------+--------------------+----------+---------+-------+-------+----------------------------------------------+

ケース2-GROUP BYなしCASE


GROUP BYCASEステートメントが遅くなる可能性があることに気付いたので、テスト目的で削除しようとしました(ただし、本番環境で使用する必要があります)。

SELECT SQL_NO_CACHE m.id, m.sku, m.movie_url 
FROM movie.movies m               
WHERE m.s_id = 1                   
GROUP BY m.mg_id#, CASE WHEN m.mg_id IS NULL THEN m.id ELSE 0 END
LIMIT 100

実行時間:0.258秒、0.149秒、0.193秒

出力の説明:

+----+-------------+-------+-------+--------------------+-----------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys      | key       | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+--------------------+-----------+---------+------+------+-------------+
|  1 | SIMPLE      | m     | index | ind_mg_id,ind_s_id | ind_mg_id | 9       | NULL | 2200 | Using where |
+----+-------------+-------+-------+--------------------+-----------+---------+------+------+-------------+

はるかに良いですが、それでもかなり遅いクエリです。

ケース3-GROUP BYなし、CASEなし


GROUP BYステートメントがないと、上記の時間はさらに短くなります。

SELECT SQL_NO_CACHE m.id, m.sku, m.movie_url 
FROM movie.movies m               
WHERE m.s_id = 1                   
#GROUP BY m.mg_id, CASE WHEN m.mg_id IS NULL THEN m.id ELSE 0 END
LIMIT 100

実行時間:0.053秒、0.050秒、0.052秒

出力の説明:

+----+-------------+-------+------+---------------+----------+---------+-------+-------+-------+
| id | select_type | table | type | possible_keys | key      | key_len | ref   | rows  | Extra |
+----+-------------+-------+------+---------------+----------+---------+-------+-------+-------+
|  1 | SIMPLE      | m     | ref  | ind_s_id      | ind_s_id | 4       | const | 39941 | NULL  |
+----+-------------+-------+------+---------------+----------+---------+-------+-------+-------+

詳細情報


moviesテーブルには95,600行があります。テーブルはさらに大きなサイズ(最終的には数千万)まで成長し続けます。

関連するインデックス:

+----------+------------+-------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name                | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+-------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| movies   |          0 | PRIMARY                 |            1 | id                  | A         |       79882 | NULL     | NULL   |      | BTREE      |         |               |
| movies   |          1 | ind_mg_id               |            1 | pg_id               | A         |        7262 | NULL     | NULL   | YES  | BTREE      |         |               |
| movies   |          1 | ind_s_id                |            1 | s_id                | A         |          10 | NULL     | NULL   |      | BTREE      |         |               |
+----------+------------+-------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

クエリのパフォーマンスを向上させるにはどうすればよいですか?

3
Nate

次のインデックスを作成してください

ALTER TABLE movie.movies ADD INDEX sid_mgid_ndx (s_id,mg_id);

このインデックスは、WHEREおよびGROUP BY

おそらく別のインデックスが役立つでしょう

ALTER TABLE movie.movies
    DROP INDEX sid_mgid_ndx,
    ADD INDEX sid_mgid_id_ndx (s_id,mg_id,id)
;

クエリを調整します

SELECT SQL_NO_CACHE m.id, m.sku, m.movie_url 
FROM movie.movies m               
WHERE m.s_id = 1                   
ORDER BY m.mg_id, m.id;
LIMIT 100;

GROUP BYからORDER BY実際の集計を行っていないため(つまり、SUM()、COUNT()、AVG()、またはその他の合計を行っていないため)

2
RolandoMySQLDBA