大家好,我有一个需要优化的查询。它的工作原理,但它的狗,表现明智。
内容如下:
SELECT * FROM ( SELECT * FROM views WHERE user_id = '1' ORDER BY page DESC ) v GROUP BY v.session
我正在跟踪查看不同页面的视图,并且我想知道每个会话的最高页面,以便了解在任何给定条件下他们的点击量(从头到尾查看所有页面)会议。
基本上,我想做的是在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"
模式:
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
索引信息:
views 0 PRIMARY 1 ID A 196008 (NULL) (NULL) BTREE views 1 page 1 page A 259 (NULL) (NULL) YES BTREE
分组之前先订购是一种非常不可靠的方法。
MySQL扩展GROUP BY语法:您可以在SELECTandORDER BY子句中使用未分组和未聚合的字段。
MySQL
GROUP BY
SELECT
ORDER BY
在这种情况下,page每个输出一个随机值session。
page
session
文档 明确指出,您永远不应对将确切确定为哪个值做任何假设:
如果您从GROUP BY零件中省略的列在组中不是恒定的,请不要使用此功能。服务器可以自由地从组中返回任何值,因此除非所有值都相同,否则结果是不确定的。
但是,实际上,将返回扫描的第一行中的值。
由于您ORDER BY page DESC在子查询中使用,因此该行恰好是page每个会话最多的行。
ORDER BY page DESC
您不应该依赖它,因为此行为没有记录,并且如果在下一版本中将返回其他行,则不会将其视为错误。
但是,您甚至不必做这些令人讨厌的把戏。
只需使用聚合函数:
SELECT MAX(page) FROM views WHERE user_id = '1' GROUP BY session
这是记录在案的,干净的方法来做您想要的。
创建一个复合索引(user_id, session, page)以使查询运行更快。
(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 )
这假设id是PRIMARY KEYon views。
id
PRIMARY KEY
views