0

どういうわけかこのクエリを高速化しようとしています。おそらく、トラフィックの少ないサイトで実行しても問題ないレベルまで。15 秒以上かかりますが、これは長すぎます。

現在、テーブルには 13,000 行ありますが、これは約 1 か月のデータですが、サイトが運用されると、月ごとのデータが 2 倍になると予想しています。目的は、先週の上位 10 の利益を選択することです。

users テーブルと tracker テーブルの 2 つのテーブルがあります。tracker テーブルには、ユーザーごとに複数の行があり、ユーザーごとに 1 日あたり少なくとも 8 行あります。

クエリの目的は、各ユーザーの最新の行を取得し、そこから 1 週間前に挿入された行から値を差し引いて、獲得した xp の量を取得し、上位 10 人の最高獲得者を選択することです。

テーブルスキーマ(これも改善できると確信しています)

ユーザー テーブル

id int(11) primary
rsn varchar(12) unique
joined timestamp
disabled bool

トラッカーテーブル

id int(11) primary
user_id int(11) index /* Associated with the id in the users table */
timestamp timestamp
overall_rank int(11)
overall_level int(4)
overall_exp int(10)

そしてクエリ。

SELECT  `users`.`rsn` ,  `tracker`.`timestamp` , @uid :=  `tracker`.`user_id` , (
    SELECT  `overall_exp` 
    FROM  `tracker` 
    WHERE  `user_id` = @uid 
    ORDER BY  `timestamp` DESC 
    LIMIT 1
) - (
    SELECT  `overall_exp` 
    FROM  `tracker` 
    WHERE  `timestamp` >= SUBDATE( NOW( ) , INTERVAL 1 WEEK ) 
    AND  `user_id` = @uid 
    ORDER BY  `timestamp` ASC 
    LIMIT 1 ) AS  `gained_exp` 
FROM  `tracker` 
JOIN  `users` ON  `tracker`.`user_id` =  `users`.`id` 
ORDER BY  `gained_exp` DESC 
LIMIT 10

出力の説明

+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
| id | select_type          | table   | type  | possible_keys | key     | key_len | ref              | rows  | Extra                                        |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
|  1 | PRIMARY              | users   | index | PRIMARY       | rsn     | 14      | NULL             |    71 | Using index; Using temporary; Using filesort |
|  1 | PRIMARY              | tracker | ref   | user_id       | user_id | 4       | surreal.users.id |   103 |                                              |
|  3 | UNCACHEABLE SUBQUERY | tracker | ALL   | NULL          | NULL    | NULL    | NULL             | 11752 | Using where; Using filesort                  |
|  2 | UNCACHEABLE SUBQUERY | tracker | ALL   | NULL          | NULL    | NULL    | NULL             | 11752 | Using where; Using filesort                  |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
4

1 に答える 1

1

最初にすべてのユーザーの今日と 1 週間前のタイムスタンプを見つけてから、再度トラッカーに 2 回参加して、overall_exp の対応する値を見つけてから、計算を実行することで、相関サブクエリを回避してみてください。

SELECT rsn, ts.thisweek, ts.user_id,
       last.overall_exp - previous.overall_exp AS gained_exp
FROM (SELECT user_id, MIN(timestamp) AS lastweek, MAX(timestamp) AS thisweek
      FROM tracker
      WHERE timestamp >= SUBDATE(NOW(), INTERVAL 1 WEEK)
      GROUP BY user_id) AS ts
INNER JOIN tracker previous
ON previous.user_id = ts.user_id AND previous.timestamp = ts.lastweek
INNER JOIN tracker last
ON last.user_id = ts.user_id AND last.timestamp = ts.thisweek
JOIN users ON ts.user_id = users.id
ORDER BY gained_exp DESC
LIMIT 10
于 2013-02-03T21:04:39.627 に答える