0

日付範囲の間に各ユーザーが入力したメモの合計を取得するクエリを実行しています。これは私が実行しているクエリです:

SELECT SQL_NO_CACHE 
    COUNT(notes.user_id) AS "Number of Notes"

FROM csu_users

JOIN notes      ON notes.user_id    = csu_users.user_id

WHERE notes.timestamp BETWEEN "2013-01-01" AND "2013-01-31"
AND notes.system = 0

GROUP BY csu_users.user_id

私のセットアップに関するいくつかのメモ:

  • クエリの実行には 30 ~ 35 秒かかりますが、これはシステムには長すぎます
  • これは InnoDB テーブルです
  • notesテーブルは約 1 GB で、行数は約 3,000,000 行です
  • SQL_NO_CACHE正確なベンチマークを確保するために意図的に使用しています

の出力EXPLAIN SELECTは次のとおりです(私はそれをフォーマットするために最善を尽くしました):

id  select_type table       type    possible_keys             key       key_len ref                           rows  Extra
1   SIMPLE      csu_users   index   user_id                   user_id   5       NULL                          1     Using index
1   SIMPLE      notes       ref     user_id,timestamp,system  user_id   4       REFSYS_DEV.csu_users.user_id  152   Using where

次のインデックスが適用されています。

notes

  • 主キー -id
  • item_id
  • user_id
  • timestamp (注: これは実際にはDATETIMEです。名前は誤解を招くだけです。申し訳ありません!)
  • system

csu_users

  • 主キー -id
  • user_id

これをスピードアップする方法はありますか?ありがとうございました!

4

2 に答える 2

1

csu_usersテーブルは必要ですか?関係が 1 対 1 で、ユーザー ID が常に存在する場合は、代わりに次のクエリを実行できます。

SELECT COUNT(notes.user_id) AS "Number of Notes"
FROM notes 
WHERE notes.timestamp BETWEEN "2013-01-01" AND "2013-01-31" AND notes.system = 0
GROUP BY notes.user_id

そうでない場合でも、すべての条件が on であるため、集計とフィルタリングのnotesに結合を行うことができます。

select "Number of Notes"
from (SELECT notes.user_id, COUNT(notes.user_id) AS "Number of Notes"
      FROM notes 
      WHERE notes.timestamp BETWEEN "2013-01-01" AND "2013-01-31" AND notes.system = 0
      GROUP BY notes.user_id
     ) n join
     csu_users cu
     on n.user_id = cu.user_id
于 2013-03-20T14:04:38.067 に答える
1

私が間違っていなければ、タイムスタンプを文字列表現に変換すると、その列のインデックスのすべての利点が失われます。比較でタイムスタンプ値を使用してみてください

于 2013-03-20T11:57:55.403 に答える