MySQLbest/first分差查询优化
MySQL best/first score difference query optimisation
谁能帮我优化这个查询?我有下表:
cdu_user_progress:
--------------------------------------------------------------
|id |uid |lesson_id |game_id |date |score |
--------------------------------------------------------------
对于每个用户,我试图获得特定 game_id 和特定 lesson_id 的最佳分数和第一分数之间的差异,并根据该差异对结果进行排序('progress' 在我的查询中):
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
中的 (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 标准(尽管当 SQL_MODE
不包含 ONLY_FULL_GROUP_BY
时 MySQL 并不要求这样做)
如果我没有定义 suitable 索引,我会考虑添加一个索引:
... ON cdu_user_progress (lesson_id, uid, score, game_id, date)
派生的 tables(具体化内联视图)有一些开销,那些派生的 tables 不会有索引(在 MySQL 5.5 和较早。)但是每个内联视图中的 GROUP BY
确保我们的行数少于 20,因此这不会成为问题。
因此,如果存在性能问题,则出现在视图查询中。同样,我们确实需要查看 EXPLAIN
的输出和索引定义,以及一些基数估计,以便提出建议。
跟进
鉴于 (uid,date)
没有唯一约束,我将在 fs
视图查询中添加这些谓词。我还会在查询中使用唯一的 table 别名(对于 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
而且我相信这将使我在上面推荐的索引成为 suitable 用于所有对 cdu_user_progress
.
的引用
谁能帮我优化这个查询?我有下表:
cdu_user_progress:
--------------------------------------------------------------
|id |uid |lesson_id |game_id |date |score |
--------------------------------------------------------------
对于每个用户,我试图获得特定 game_id 和特定 lesson_id 的最佳分数和第一分数之间的差异,并根据该差异对结果进行排序('progress' 在我的查询中):
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
中的 (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 标准(尽管当 SQL_MODE
不包含 ONLY_FULL_GROUP_BY
时 MySQL 并不要求这样做)
如果我没有定义 suitable 索引,我会考虑添加一个索引:
... ON cdu_user_progress (lesson_id, uid, score, game_id, date)
派生的 tables(具体化内联视图)有一些开销,那些派生的 tables 不会有索引(在 MySQL 5.5 和较早。)但是每个内联视图中的 GROUP BY
确保我们的行数少于 20,因此这不会成为问题。
因此,如果存在性能问题,则出现在视图查询中。同样,我们确实需要查看 EXPLAIN
的输出和索引定义,以及一些基数估计,以便提出建议。
跟进
鉴于 (uid,date)
没有唯一约束,我将在 fs
视图查询中添加这些谓词。我还会在查询中使用唯一的 table 别名(对于 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
而且我相信这将使我在上面推荐的索引成为 suitable 用于所有对 cdu_user_progress
.