使用 SQL 查询(MySQL 数据库)获取不同项目的最新“事件”

Posted

技术标签:

【中文标题】使用 SQL 查询(MySQL 数据库)获取不同项目的最新“事件”【英文标题】:Get the most recent "event" for distinct items using an SQL query (MySQL database) 【发布时间】:2015-01-02 04:39:38 【问题描述】:

我有一个“事件”表,用于存储有关实验室计算机登录、注销、关机和启动的一些统计数据。

我希望生成的是最后每个人计算机名所做的操作列表。

这是我的名为 raw 的表的示例:

mysql> select * from raw limit 20;
+--------+--------------+-------+---------------------+
| id     | computername | event | timestamp           |
+--------+--------------+-------+---------------------+
| 148776 | REF-18       |     1 | 2014-11-05 15:05:29 |
| 148775 | DEC-02       |     3 | 2014-11-05 15:05:19 |
| 148774 | GPS-06       |     3 | 2014-11-05 15:05:18 |
| 148773 | DEC-15       |     3 | 2014-11-05 15:05:16 |
| 148772 | DEC-02       |     1 | 2014-11-05 15:04:33 |
| 148771 | REF-18       |     2 | 2014-11-05 15:04:18 |
| 148770 | REF-09       |     1 | 2014-11-05 15:04:14 |
| 148769 | REF-18       |     4 | 2014-11-05 15:04:02 |
| 148768 | DEC-02       |     2 | 2014-11-05 15:03:39 |
| 148767 | DEC-02       |     4 | 2014-11-05 15:03:24 |
| 148766 | REF-09       |     2 | 2014-11-05 15:03:00 |
| 148765 | DEC-08       |     3 | 2014-11-05 15:02:54 |
| 148764 | REF-09       |     4 | 2014-11-05 15:02:44 |
| 148763 | REF-09       |     3 | 2014-11-05 15:01:31 |
| 148762 | DEC-01       |     1 | 2014-11-05 15:01:13 |
| 148760 | REF-19       |     1 | 2014-11-05 15:00:50 |
| 148761 | DEC-04       |     3 | 2014-11-05 15:00:50 |
| 148759 | REF-18       |     3 | 2014-11-05 15:00:25 |
| 148758 | DEC-36       |     1 | 2014-11-05 15:00:10 |
| 148757 | DEC-01       |     2 | 2014-11-05 15:00:09 |
+--------+--------------+-------+---------------------+

我想出了几个我认为可行的解决方案;

SELECT r1.id, r1.computername, r1.event, r1.timestamp
FROM raw r1 
JOIN (SELECT id, computername, event, MAX(timestamp) AS timestamp 
      FROM raw GROUP BY computername) 
AS r2
ON r1.computername = r2.computername 
   AND r1.timestamp = r2.timestamp 
GROUP BY r1.computername;

这似乎可以完成这项工作,但它需要f o r e v e r

SELECT * 
FROM (SELECT * from raw order by timestamp desc) row_result 
GROUP BY computername;

到目前为止,这花费的时间要少得多,但似乎产生了相同的结果。哪个更好?第二个查询仅仅是对 MySQL 工作方式的hack 吗?我可以优化我的数据,或者以某种方式查询以产生更快更可靠的结果吗?

谢谢!

【问题讨论】:

第二个查询只有在您对时间戳非常幸运时才有效。 当事情永远不会发生时,发布EXPLAIN 的结果以供您查询,以查看您的查询是如何执行的。这几乎总是缺少索引和无情的表扫描的情况。 你应该尝试为诸如此类的问题提供一个 sql fiddle(至少在我看来),以使可能的回答者更容易 - 因为我们中的许多人可能最终还是单独做. 适当索引,您的第一个查询应该非常非常快。与第二个查询相比,它具有被记录的优势,虽然这里的一些人很受欢迎,但正如您所猜测的那样,它是一个未记录的黑客攻击。 ...此外,在子查询中包含 id 和 event 似乎没有任何目的,在外部查询中也包含 GROUP BY 子句 【参考方案1】:

你有没有尝试过这样的事情:

select r.id, r.computername, r.event, r.timestamp
from raw r
inner join (
    select max(id) as id
    from raw
    group by computerName
) as maxEventPerComputer on r.id = maxEventPerComputer.Id

当然,它与您的初始查询非常相似,但您可能会得到更好的结果,特别是考虑到您的 id 列(可能)被索引到您的日期列可能不在的位置(我想)。

但据我了解,与其他 RDBMS 相比,mysql 的子查询不太好......但希望这会有所帮助。

【讨论】:

这是 LOADS 更快...非常感谢。这似乎确实是最好的解决方案。我真的应该考虑一下我可以拉 MAX(id) 的事实,因为它无论如何都是有罪的。

以上是关于使用 SQL 查询(MySQL 数据库)获取不同项目的最新“事件”的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Azure SQL db 中的存储过程一次性获取查询的所有批次?

MySQL FOUND_ROWS() 方法的 SQL 等效项是啥?

如何获取mysql重复项中的最后一条数据

MYSQL优化 学习笔记

多选择筛选查询SQL语句怎么写

SQL合并两个具有不同列号的选择查询,同时删除重复项?