【问题标题】:mysql select most recent records that match a given statusmysql 选择与给定状态匹配的最新记录
【发布时间】:2020-12-19 11:24:02
【问题描述】:

我有一个数据库表,其中包含设备及其状态 ..up 或 down。 当设备更改状态时,该表会从设备监控应用程序更新。

CREATE TABLE device_status( 
time TIMESTAMP(6) NOT NULL, 
device_name VARCHAR(10) NOT NULL,   
type ENUM('up', 'down') NOT NULL,   
device_status_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);

INSERT INTO device_status VALUES    
('2020-07-01 09:00:00.000001','device1','down',NULL),   
('2020-07-01 09:00:05.000001','device2','down',NULL),   
('2020-07-01 10:00:00.000001','device3','down',NULL),   
('2020-07-01 10:00:05.000001','device1','up',NULL), 
('2020-07-01 10:00:08.000001','device1','down',NULL),   
('2020-07-01 11:00:00.000001','device2','down',NULL),   
('2020-07-01 11:00:05.000001','device1','up',NULL); 

    mysql> select * from device_status;
+----------------------------+-------------+------+------------------+
| time                       | device_name | type | device_status_id |
+----------------------------+-------------+------+------------------+
| 2020-07-01 09:00:00.000001 | device1     | down |                1 |
| 2020-07-01 09:00:05.000001 | device2     | down |                2 |
| 2020-07-01 10:00:00.000001 | device3     | down |                3 |
| 2020-07-01 10:00:05.000001 | device1     | up   |                4 |
| 2020-07-01 10:00:06.000001 | device2     | up   |                5 |
| 2020-07-01 10:00:08.000001 | device1     | down |                6 |
| 2020-07-01 11:00:00.000001 | device2     | down |                7 |
| 2020-07-01 11:00:05.000001 | device1     | up   |                8 |
+----------------------------+-------------+------+------------------+
8 rows in set (0.00 sec)

我想创建一个显示当前停机设备的查询。输出 对于上表应显示如下内容:

+----------------------------+-------------+------+------------------+
| time                       | device_name | type | device_status_id |
+----------------------------+-------------+------+------------------+
| 2020-07-01 11:00:00.000001 | device2     | down |                7 |
| 2020-07-01 10:00:00.000001 | device3     | down |                3 |
+----------------------------+-------------+------+------------------+
2 rows in set (0.00 sec)

我有 700 台设备,每天向表中添加大约 5k 条记录。 非常感谢任何帮助!

好的,所以这个查询确实产生了所需的结果,但是随着表的增长,它需要很长时间..当前表有大约 50k 行,大约需要 5 分钟 :-(

mysql> select t1.*  
    -> from device_status t1    
    -> left outer join device_status t2 
    -> on (t1.device_name = t2.device_name and t1.time < t2.time)   
    -> where (t2.device_name is null and t1.type = 'down')  
    -> order by device_name;    
+----------------------------+-------------+------+------------------+  
| time                       | device_name | type | device_status_id |  
+----------------------------+-------------+------+------------------+  
| 2020-07-01 11:00:00.000001 | device2     | down |                7 |  
| 2020-07-01 10:00:00.000001 | device3     | down |                3 |  
+----------------------------+-------------+------+------------------+  
2 rows in set (0.00 sec)    

我已按照建议为列添加索引:

mysql> describe device_status;  
+------------------+-------------------+------+-----+----------------------+--------------------------------+   
| Field            | Type              | Null | Key | Default              | Extra                          |   
+------------------+-------------------+------+-----+----------------------+--------------------------------+   
| time             | timestamp(6)      | NO   | MUL | CURRENT_TIMESTAMP(6) | on update CURRENT_TIMESTAMP(6) |   
| device_name      | varchar(10)       | NO   | MUL | NULL                 |                                |   
| type             | enum('up','down') | NO   | MUL | NULL                 |                                |   
| device_status_id | int(10) unsigned  | NO   | PRI | NULL                 | auto_increment                 |   
+------------------+-------------------+------+-----+----------------------+--------------------------------+   
4 rows in set (0.02 sec)    

我还增加了 12k 条记录:

mysql> SELECT COUNT(*) FROM device_status;
+----------+
| COUNT(*) |
+----------+
|    12002 |
+----------+

1 row in set (0.01 sec)

现在如果我运行我的原始查询:

mysql> select t1.*
    -> from device_status t1
    -> left outer join device_status t2
    -> on (t1.device_name = t2.device_name and t1.time < t2.time)
    -> where (t2.device_name is null and t1.type = 'down')
    -> order by device_name;
+----------------------------+-------------+------+------------------+
| time                       | device_name | type | device_status_id |
+----------------------------+-------------+------+------------------+
| 2020-08-31 15:48:58.597929 | device1     | down |            12001 |
| 2020-08-31 15:48:58.677924 | device2     | down |            12002 |
+----------------------------+-------------+------+------------------+
2 rows in set (23.56 sec)

所以我想我在这里做错了..非常感谢所有帮助!

【问题讨论】:

  • 尝试在您的时间戳列上使用order by

标签: mysql


【解决方案1】:

MySql 8.0 可以使用row_number()窗口函数

select time, device_name, type, device_status_id
from (
select *, 
row_number() over (partition by device_name order by time desc) rn
from device_status
) t where rn=1 and type='down'

编辑 - 如果是 MySql 5.7 或更早版本

select time, device_name, type, device_status_id from (
  SELECT    *,
              IF(device_name=@last,@_seq:=@_seq+1,@_seq:=1) AS rn,
              @last:=device_name
    FROM      device_status , (SELECT @_seq:=1, @last:=0) r
    ORDER BY  device_name, time desc) t 
    where rn=1 and type='down';

同时使用适当的表索引,这将提高性能。

【讨论】:

  • 非常感谢您的回答..不幸的是我的数据库是 8.0 之前的版本。
  • @user2149346 我也更新了以前版本的答案。
  • 那太棒了 Akhilesh ..但是当我运行时我得到:错误 1267 (HY000): 排序规则的非法混合 (latin1_swedish_ci,IMPLICIT) 和 (cp850_general_ci,IMPLICIT) 用于操作 '=' ..我是检查如何解决这个问题!
  • @user2149346 请参考此Link 了解您的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多