如何优化MySQL查询(组和顺序)

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)

Qua*_*noi 8

我正在跟踪不同页面的视图,我想知道每个会话的最高页面,以便知道他们在任何给定的时间点击了多远(他们需要一直查看每个页面)会话.

在分组之前进行排序是一种非常不可靠的方法.

MySQL扩展GROUP BY语法:您可以在SELECTORDER 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)

这假设idPRIMARY KEY开启的views.