(旧) kano-e no memo

こっちは更新してません

GROUP BY

例えば、以下のようなテーブルがあるとする。

  • users
    • id
  • accesses
    • id
    • code
    • user_id
    • created_at

この時、accessesをカウントしたい。
要件は以下のような感じ。

  • accesses.codeはとある一つを指定する
  • 1日毎に集計
  • 1日にあった総アクセスを確認したい
  • 同じように、同一ユーザによる再アクセスをカウントしないアクセス数を確認したい
  • 一度に見るのは一ヶ月分

とりあえず、うだうだ書いているうちに、以下のようなSQLができた。

SELECT
  day,
  count(code) AS access,
  count(distinct user_id) AS once_day
FROM (
  SELECT
    day(created_at) AS day,
    code,
    user_id
  FROM accesses
  WHERE code = 'c'
    AND created_at >= '2007-05-01 00:00:00'
    AND created_at ≷ '2007-06-01 00:00:00'
  ) AS a
GROUP BY day

+------+--------+----------+
| day  | access | once_day |
+------+--------+----------+
|    1 |    *** |      *** |
|    2 |    *** |      *** |
|    3 |    *** |      *** |
|    4 |    *** |      *** |
|    5 |    *** |      *** |
|    6 |    *** |      *** |
|    7 |    *** |      *** |
|    9 |    *** |      *** |
+------+--------+----------+
8 rows in set (0.15 sec)

うん、良い感じ。ちゃんと意図した結果が出てる。
それじゃあ、もうちょっとSQLをすっきりさせよう、と思って、以下のような感じにしてみた。

SELECT
  day(created_at) AS day,
  count(id) AS access,
  count(distinct user_id) AS once_day
FROM accesses
WHERE code = 'c'
  AND created_at >= '2007-05-01 00:00:00'
  AND created_at < '2007-06-01 00:00:00'
GROUP BY day

+------+--------+----------+
| day  | access | once_day |
+------+--------+----------+
|    1 |    *** |      *** |
|    2 |    *** |      *** |
|    3 |    *** |      *** |
|    4 |    *** |      *** |
|    5 |    *** |      *** |
|    6 |    *** |      *** |
|    7 |    *** |      *** |
|    9 |    *** |      *** |
+------+--------+----------+
8 rows in set (0.20 sec)

この時気付いたのですが、前の方が速い……。
キャッシュの問題とかあるのかと思って、何度も試したんですが、何度やっても最初のSQLの方が速い。
なんでだー。

実際のところ、0.05程度の差なんで、仕事としては気にしなくてもOKそうなんですが、なんか気になる。
というか、これがわからなくてはいけない気がする。

前々から、group by(というか、集計関数)使うともっさりするなーという印象はあったんですが、その辺りの問題かなー、とか、つらつら考えてみました。
絞り込んでからgroup by使ったほうが速いのかと考えると、そんな気もするけど……。

SQLの仕組みをもっと体で感じるレベルで理解しないと駄目だなーと思いました。
うん、頭で考えてわかるとかじゃなくて、SQL見たら、データベースの中で何が行われるか、自然とわかっちゃうレベルになれたら、きっと格好良い(仕事でそれを求められてるのか、というのとはまた別の話だったり……)。