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

标签 sql mysql optimization

大家好,我有一个查询需要优化。它有效,但它是一只狗,性能明智。

它是这样写的:

SELECT  *
FROM    (
        SELECT  *
        FROM    views
        WHERE   user_id = '1'
        ORDER BY
                page DESC
        ) v
GROUP BY
        v.session

我正在跟踪不同页面的浏览量,我想知道每个 session 的最高页面,以便了解他们点击了多远(他们需要一直查看每个页面直到最后)在任何给定的 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 

最佳答案

I'm tracking views to different pages, and I want to know the highest page per session, in order to know how far they've clicked through (they're required to view every page all the way to the end) in any given session.

在分组前排序是一种非常不可靠的方法。

MySQL 扩展了 GROUP BY 语法:您可以在 SELECTORDER BY 子句中使用未分组和未聚合的字段.

在这种情况下,page 的随机值是每个 session 的输出。

Documentation明确指出你永远不应该对它到底是哪个值做出任何假设:

Do not use this feature if the columns you omit from the GROUP BY part are not constant in the group. The server is free to return any value from the group, so the results are indeterminate unless all values are the same.

但是,实际上,返回扫描的第一行中的值。

由于您在子查询中使用了 ORDER BY page DESC,因此该行恰好是每个 session 具有最大 page 的行。

你不应该依赖它,因为这个行为没有记录,如果在下一个版本中会返回一些其他行,它不会被认为是一个错误。

但你甚至不必做这种卑鄙的把戏。

只需使用聚合函数:

SELECT  MAX(page)
FROM    views
WHERE   user_id = '1'
GROUP BY
        session

这是有据可查的干净方式来做你想做的事。

(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
        )

这假设 idviews 上的 PRIMARY KEY

关于sql - 如何优化MySQL查询(分组和顺序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1201296/

相关文章:

mysql - 从另一个表更新多次

mysql - 使用内部查询中的列名选择要在外部查询中显示的列

mysql - mysql 中什么更快,数字列等于或更大?

r - data.frame 列的子集以最大化 "complete"观察

mysql - 消息系统查询以获取最后一条消息、未读消息的数量和对话中的用户数组

php - SQL - 记录多个日期/时间和计算时间差的最佳方法。

将 32 位数字转换为 16 位或更少

MySQL 查询优化(运行 7.6 秒)

php - html <select multiple=multiple> + SQL查询搜索

php - 在 PHP、MySql 中生成自定义唯一 ID