簡體   English   中英

MySQL最佳/第一得分差異查詢優化

[英]MySQL best/first score difference query optimisation

誰能幫助我優化此查詢? 我有下表:

cdu_user_progress:
--------------------------------------------------------------
|id    |uid     |lesson_id    |game_id    |date    |score    |
--------------------------------------------------------------

對於每個用戶,我試圖獲取特定的game_id和特定的lesson_id的最高分數與第一分數之間的差異,並按該差異對結果進行排序(查詢中的“進度”):

SELECT ms.uid AS id, ms.max_score - fs.first_score AS progress
FROM (
    SELECT up.uid, MAX(CASE WHEN game_id = 3 THEN score ELSE NULL END) AS max_score
    FROM cdu_user_progress up
    WHERE  (up.uid IN  ('1671', '1672', '1673', '1674', '1675', '1676', '1679', '1716', '1725',         '1726', '1937', '1964', '1996', '2062', '2065', '2066', '2085', '2086')) AND (up.lesson_id = '65') AND (up.score > '-1')
GROUP BY up.uid
) ms
LEFT JOIN (
    SELECT up.uid, up.score AS first_score 
    FROM cdu_user_progress up
    INNER JOIN (
        SELECT up.uid, MIN(CASE WHEN game_id = 3 THEN date ELSE NULL END) AS first_date
        FROM cdu_user_progress up
        WHERE  (up.uid IN  ('1671', '1672', '1673', '1674', '1675', '1676', '1679', '1716', '1725', '1726', '1937', '1964', '1996', '2062', '2065', '2066', '2085', '2086')) AND (up.lesson_id = '65') AND (up.score > '-1') 
        GROUP BY up.uid
    ) fd ON fd.uid = up.uid AND fd.first_date = up.date
) fs ON fs.uid = ms.uid
ORDER BY progress DESC

非常感激任何的幫助!

缺少任何EXPLAIN輸出或索引定義,我們無法提出任何建議。 (我在一條評論中指出,看起來有些cdu_user_progress謂詞丟失了,如果我們不能保證cdu_user_progress(uid,date)元組具有唯一性...我們有可能會獲得用於不同的lesson_id或分數不大於'-1'

在查詢文本中,緊接在) fs之前,我要添加

        AND up.lesson_id = '65'
        AND up.score > '-1'
      GROUP BY up.uid

我還將up.score列(在fd視圖的SELECT列表中)包裝在聚合函數MIN()MAX() ,以符合ANSI標准(即使MySQL不需要)當SQL_MODE不包含ONLY_FULL_GROUP_BY


如果沒有定義合適的索引,則可以考慮添加一個索引:

... ON cdu_user_progress (lesson_id, uid, score, game_id, date)

派生表(實現內聯視圖)有一些開銷,並且這些派生表不會在它們上具有索引(在MySQL 5.5和更早的版本中。)但是每個內聯視圖中的GROUP BY可以確保我們擁有少於20行,所以這實際上不是問題。

因此,如果存在性能問題,則在視圖查詢中。 同樣,我們確實需要查看EXPLAIN的輸出和索引定義以及一些基數估計,以便提出建議。


跟進

鑒於(uid,date)並沒有唯一的約束,我將這些謂詞添加到fs視圖查詢中。 我還將在查詢中使用唯一的表別名(針對cdu_user_progress每個引用),以使語句和EXPLAIN輸出都更易於閱讀。 另外,在fd視圖中添加GROUP BY子句和聚合函數...我將這樣編寫查詢:

SELECT ms.uid AS id
     , ms.max_score - fs.first_score AS progress
  FROM ( SELECT up.uid
              , MAX(CASE WHEN up.game_id = 3 THEN up.score ELSE NULL END) AS max_score
           FROM cdu_user_progress up
          WHERE up.uid IN ('1671','1672','1673','1674','1675','1676','1679','1716','1725','1726','1937','1964','1996','2062','2065','2066','2085','2086')
            AND up.lesson_id = '65'
            AND up.score > '-1'
          GROUP BY up.uid
       ) ms
  LEFT
  JOIN ( SELECT uo.uid
              , MIN(uo.score) AS first_score
           FROM ( SELECT un.uid
                       , MIN(CASE WHEN un.game_id = 3 THEN un.date ELSE NULL END) AS first_date
                    FROM cdu_user_progress un
                   WHERE un.uid IN ('1671','1672','1673','1674','1675','1676','1679','1716','1725','1726','1937','1964','1996','2062','2065','2066','2085','2086')
                     AND un.lesson_id = '65' 
                     AND un.score > '-1' 
                   GROUP BY un.uid
                ) fd
           JOIN cdu_user_progress uo
             ON uo.uid = fd.uid
            AND uo.date = fd.first_date
            AND uo.lesson_id = '65'
            AND uo.score > '-1'
          GROUP BY uo.uid
       ) fs
    ON fs.uid = ms.uid
 ORDER BY progress DESC

而且我相信這將使我上面推薦的索引適合所有對cdu_user_progress的引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM