the*_*ott 4 mysql sql optimization
嘿所有,我有一个需要优化的查询.它有效,但它是一只狗,性能明智.
它看起来像这样:
SELECT *
FROM (
SELECT *
FROM views
WHERE user_id = '1'
ORDER BY
page DESC
) v
GROUP BY
v.session
Run Code Online (Sandbox Code Playgroud)
我正在跟踪不同页面的视图,我想知道每个会话的最高页面,以便知道他们在任何给定的时间点击了多远(他们需要一直查看每个页面)会话.
基本上我要做的是在GROUP之前对结果进行排序.以上实现了这一点,成本很高.
任何人都可以拍我的头脑怎么做?多谢你们!
更新:
解释:
"1" "PRIMARY" "<derived2>" "ALL" \N \N \N \N "3545" "Using temporary; Using filesort"
"2" "DERIVED" "views" "index" \N "page" "5" \N "196168" "Using where"
Run Code Online (Sandbox Code Playgroud)
架构:
ID int(8) unsigned (NULL) NO PRI (NULL) auto_increment select,insert,update,references
page int(8) (NULL) YES MUL (NULL) select,insert,update,references
user_id int(8) (NULL) YES (NULL) select,insert,update,references
session int(8) (NULL) YES (NULL) select,insert,update,references
created datetime (NULL) NO select,insert,update,references
Run Code Online (Sandbox Code Playgroud)
索引信息:
views 0 PRIMARY 1 ID A 196008 (NULL) (NULL) BTREE
views 1 page 1 page A 259 (NULL) (NULL) YES BTREE
Run Code Online (Sandbox Code Playgroud)
我正在跟踪不同页面的视图,我想知道每个会话的最高页面,以便知道他们在任何给定的时间点击了多远(他们需要一直查看每个页面)会话.
在分组之前进行排序是一种非常不可靠的方法.
MySQL
扩展GROUP BY
语法:您可以在SELECT
和ORDER BY
子句中使用未组合和未聚合的字段.
在这种情况下,page
每个输出随机值session
.
文档明确指出,您永远不应该对它的确切值做出任何假设:
如果从
GROUP BY
零件中省略的列在组中不是常量,请不要使用此功能.服务器可以自由地从组中返回任何值,因此除非所有值都相同,否则结果是不确定的.
但是,实际上,将返回扫描的第一行的值.
由于您ORDER BY page DESC
在子查询中使用了一个,因此该行恰好是page
每个会话具有最大值的行.
您不应该依赖它,因为此行为未记录,如果在下一版本中将返回其他行,则不会将其视为错误.
但你甚至不必做这些讨厌的伎俩.
只需使用聚合函数:
SELECT MAX(page)
FROM views
WHERE user_id = '1'
GROUP BY
session
Run Code Online (Sandbox Code Playgroud)
这是记录和干净的方式来做你想要的.
(user_id, session, page)
为查询创建复合索引以更快地运行.
如果您需要表中的所有列,而不仅是聚合列,请使用以下语法:
SELECT v.*
FROM (
SELECT DISTINCT user_id, session
FROM views
) vo
JOIN views v
ON v.id =
(
SELECT id
FROM views vi
WHERE vi.user_id = vo.user_id
AND vi.session = vo.session
ORDER BY
page DESC
LIMIT 1
)
Run Code Online (Sandbox Code Playgroud)
这假设id
是PRIMARY KEY
开启的views
.