6

私のテーブル「my_logs」には約 20,000,000 のレコードがあり、数日以内に各日付にいくつのログがあるかを調べたいと考えています。

みたいな結果になりたい

+------------+---------+ | date | count | +------------+---------+ | 2016-07-01 | 1623 | | 2016-07-02 | 1280 | | 2016-07-03 | 2032 | +------------+---------+

以下のこのクエリは、完了するのに数ミリ秒しかかかりません。

SELECT  DATE_FORMAT(created_at, '%Y-%m-%d') as date,
        COUNT(*) as count
    FROM  my_logs
    WHERE  created_at BETWEEN '2016-07-01' AND '2016-07-04'
    GROUP BY  DATE_FORMAT(created_at, '%Y-%m-%d')

クエリの説明:

+------------+---------+-------+-----------------------------+ |select_type | table | type | possible_keys | +------------+---------+-------+-----------------------------+ | SIMPLE | my_logs| index | index_my_logs_on_created_at | +------------+---------+-------+-----------------------------+

+-----------------------------+---------+----------+ | key | key_len | rows | +-----------------------------+---------+----------+ | index_my_logs_on_created_at | 10 | 23458462 | +-----------------------------+---------+----------+

+-----------------------------------------------------------+ | Extra | +-----------------------------------------------------------+ | Using where; Using index; Using temporary; Using filesort | +-----------------------------------------------------------+

ただし、各レコードのタイムゾーンを自国の時間に合わせて変換する必要があり、「日付」情報でグループ化する必要があるため、列自体を変換する必要があります。

両方

SELECT  COUNT(*)
    FROM  my_logs
    WHERE  DATE_ADD(created_at, INTERVAL 8 HOUR) BETWEEN '2016-07-01' AND '2016-07-04'
    GROUP BY  DATE_FORMAT(DATE_ADD(created_at, INTERVAL 8 HOUR), '%Y-%m-%d')

SELECT  COUNT(*)
    FROM  my_logs
    WHERE  CONVERT_TZ(created_at, "+00:00", "+08:00") BETWEEN '2016-07-01' AND '2016-07-04'
    GROUP BY  DATE_FORMAT(CONVERT_TZ(created_at, "+00:00", "+08:00"),

'%Y-%m-%d')

クエリを完了するのに約 12 秒かかります。

(説明は、上のクエリと同じです)


よくある問題だと思いますが、うまく対処する方法が見つかりません。もっと効率的な方法はありますか?ありがとう!

4

1 に答える 1

4

TIMESTAMPを使用した場合と比べて、どのデータ型DATETIMEを使用しましたか? (でも、無視します。)

created_at関数 ( ) 内でインデックス付きの列 ( ) を「非表示」にしないでくださいCONVERT_TZ()WHERE句がインデックスを使用できず、代わりにテーブルをスキャンする必要があるようにします。この修正は簡単です:

WHERE created_at >= '2016-07-01' - INTERVAL 8 HOUR
  AND created_at  < '2016-07-04' - INTERVAL 8 HOUR

(または を使用CONVERT_TZ)。また、4日からの午前0時を含めたバグも修正したことに注意してください。注: Even+ INTERVAL...は実質的に関数です。

SELECTと の式は、GROUP BYパフォーマンスにとってそれほど重要ではありません。

于 2016-08-25T20:41:45.613 に答える