この記事は BASE Advent Calendar 2021の19日目の記事です。
こんにちは、BASE株式会社でバックエンドエンジニアをしている小川です。
私たちのチームでは10月からレスポンス改善PJとして、BASEのレスポンスが遅い処理を改善する施策を行なってきました。 その中で下記の例のようなクエリが重い処理として挙がり、そのクエリではGROUP BYが使われていたのですがDISTINCTを使った方が早くなるのではという意見がありました。
SELECT c1 FROM t1 WHERE c1 > const GROUP BY c1;
そこで、DISTINCTとGROUP BYでどちらが早いのかをネット上で調べたところ、DISTINCTの方が早い説やGROUP BYの方が早い説、どちらも変わらない説などいろんな説があり、実際のところどうなんだろうと思ったことがきっかけで検証してみることにしました。
DISTINCTとGROUP BYどちらを使った方が良いか検証した結果をご紹介したいと思います。
DISTINCTとGROUP BYの違いについて
DISTINCTとGROUP BYは重複行をまとめるという目的で使われると思いますが、それぞれどんな違いがあるのでしょうか。
DISTINCTについて
- 射影を行う段階で重複を排除
GROUP BYについて
- 指定された列名でレコードのグループ化を行う。
- グループ化したレコードは、集約関数を用いることで集計することができる。
つまり、 DISTINCTは、重複を排除した結果を出力する場合に使用 GROUP BYは、重複を排除した結果に対して集計処理を行いたい場合に使用 という違いがあります。
今回例に挙げたクエリはGROUP BYを使用していましたがグループ化した後、集計処理をせずに重複行を削除するためだけに使われています。
こういった重複行を削除するためだけなら、用途にあったDISTINCTを使うべきだと思います。
次に肝心なDISTINCTとGROUP BYどちらが早いのか見ていきます。
DISTINCTとGROUP BYどちらの方が早い
下記のようなDISTINCTとGROUP BYを使用したクエリを使って、クエリキャッシュを無効にしてそれぞれの実行計画と実行速度を検証してみました。
SELECT DISTINCT c1 FROM t1 WHERE c1 > const; SELECT c1 FROM t1 WHERE c1 > const GROUP BY c1; ※c1にはインデックスが貼ってある状態
検証環境
- MySQL5.6
検証結果としましては、実行計画は全く同じで実行速度もほぼ同じ結果となりました。
In most cases, a DISTINCT clause can be considered as a special case of GROUP BY. For example, the following two queries are equivalent: Due to this equivalence, the optimizations applicable to GROUP BY queries can be also applied to queries with a DISTINCT clause. Thus, for more details on the optimization possibilities for DISTINCT queries, see Section 8.2.1.14, “GROUP BY Optimization”.
こちらのURLのMYSQLのドキュメントにも記載されている通り、オプティマイザによって最適化された結果、内部では同じ処理になり性能は同じということが分かります。
実行速度も検索結果も同じということであれば、DISTINCTとGROUP BYは使用用途によって使い分けてください。
おわりに
DISTINCTとGROUP BYについての違いや、速度に関して紹介させていただきましたが参考になったら幸いです。
今回の調査ではレスポンスの改善にはなりませんでしたが、ほんの些細なことでも調べて、検証することによって新たな発見があると思います。 実際に私も検証するまでは、GROUP BYよりも重複行を削除するだけの処理のDISTINCTの方が早いと思っていました。 ぜひ気になったことがあれば検証してみてください!
明日のアドベントカレンダーはyusugiuraさんとShoTakeuchiさんです!お楽しみに!