【发布时间】:2020-05-16 10:44:37
【问题描述】:
这是我的系统:
Linux Ubuntu 18.04 LTS
MySQL 5.7
我有一个查询(如下)需要很长时间才能完成。
需要 9 秒才能完成。在等待网页完成加载时,这对于用户来说是难以承受的。
此外,数据集庞大且不断增长。事件表有 250,000 行。我倾向于每天添加 1200 到 1800 行。
为了帮助优化,我想添加索引等,但对于如何(以及是否)可以使用我拥有的派生/连接选择查询来做到这一点,我感到很困惑。
这是我的查询。 (有谁知道如何限制输出的宽度,这样我们就不必向右滚动才能看到整行?)
mysql> explain select OUTSIDE.ownerUID as Owner,
OUTSIDE.propUID as Property,
OUTSIDE.camname as 'Camera Name',
OUTSIDE.direction as Direction,
OUTSIDE.camtimestamp as 'Event Time',
convert_tz(now(),'UTC','US/Central') as Now,
sec_to_time(convert_tz(now(),'UTC','US/Central') - OUTSIDE.CamTimeStamp) as 'Elapsed Time'
from events OUTSIDE,
(select camname,max(camtimestamp) as maxtimestamp from events group by camname) as INSIDE
where OUTSIDE.camname = INSIDE.camname
AND OUTSIDE.camtimestamp = INSIDE.maxtimestamp;
+----+-------------+------------+------------+-------+----------------------+--------------+---------+---------------------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+----------------------+--------------+---------+---------------------+--------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 263103 | 100.00 | Using where |
| 1 | PRIMARY | OUTSIDE | NULL | ref | camtimestamp,camname | camtimestamp | 6 | INSIDE.maxtimestamp | 1 | 99.73 | Using where |
| 2 | DERIVED | events | NULL | index | camname | camname | 257 | NULL | 263103 | 100.00 | NULL |
+----+-------------+------------+------------+-------+----------------------+--------------+---------+---------------------+--------+----------+-------------+
3 rows in set, 1 warning (0.03 sec)
查询结果如下:
mysql> select OUTSIDE.ownerUID as Owner,
OUTSIDE.propUID as Property,
OUTSIDE.camname as 'Camera Name',
OUTSIDE.direction as Direction,
OUTSIDE.camtimestamp as 'Event Time',
convert_tz(now(),'UTC','US/Central') as Now,
sec_to_time(convert_tz(now(),'UTC','US/Central') - OUTSIDE.CamTimeStamp) as 'Elapsed Time'
from events OUTSIDE,
(select camname,max(camtimestamp) as maxtimestamp from events group by camname) as INSIDE
where OUTSIDE.camname = INSIDE.camname
AND OUTSIDE.camtimestamp = INSIDE.maxtimestamp;
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
| Owner | Property | Camera Name | Direction | Event Time | Now | Elapsed Time |
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
| 1 | 1 | wls1 | In | 2020-01-30 12:27:31 | 2020-01-30 12:29:53 | 00:03:42 |
| 1 | 1 | wls2 | Out | 2020-01-30 12:25:29 | 2020-01-30 12:29:53 | 00:07:04 |
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
2 rows in set (6.49 sec)
================================================ =========== 感谢所有回答问题或发表评论的人。我采纳了 Uueerdo 的综合索引建议,得出以下结果:
mysql> create index CamNameCamTime on events (camname,camtimestamp);
mysql> select OUTSIDE.ownerUID as Owner,
OUTSIDE.propUID as Property,
OUTSIDE.camname as 'Camera Name',
OUTSIDE.direction as Direction,
OUTSIDE.camtimestamp as 'Event Time',
convert_tz(now(),'UTC','US/Central') as Now,
sec_to_time(convert_tz(now(),'UTC','US/Central') - OUTSIDE.CamTimeStamp) as 'Elapsed Time'
from events OUTSIDE,
(select camname,max(camtimestamp) as maxtimestamp
from events group by camname) as INSIDE
where OUTSIDE.camname = INSIDE.camname AND OUTSIDE.camtimestamp = INSIDE.maxtimestamp;
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
| Owner | Property | Camera Name | Direction | Event Time | Now | Elapsed Time |
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
| 1 | 1 | wls1 | In | 2020-01-30 18:43:19 | 2020-01-30 18:44:33 | 00:01:54 |
| 1 | 1 | wls2 | Out | 2020-01-30 18:41:51 | 2020-01-30 18:44:33 | 00:04:42 |
+-------+----------+-------------+-----------+---------------------+---------------------+--------------+
2 rows in set (0.00 sec)
mysql> explain select OUTSIDE.ownerUID as Owner,
-> OUTSIDE.propUID as Property,
-> OUTSIDE.camname as 'Camera Name',
-> OUTSIDE.direction as Direction,
-> OUTSIDE.camtimestamp as 'Event Time',
-> convert_tz(now(),'UTC','US/Central') as Now,
-> sec_to_time(convert_tz(now(),'UTC','US/Central') - OUTSIDE.CamTimeStamp) as 'Elapsed Time'
-> from events OUTSIDE,
-> (select camname,max(camtimestamp) as maxtimestamp
-> from events group by camname) as INSIDE
-> where OUTSIDE.camname = INSIDE.camname AND OUTSIDE.camtimestamp = INSIDE.maxtimestamp;
+----+-------------+------------+------------+-------+-------------------------------------+----------------+---------+------------------------------------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+-------------------------------------+----------------+---------+------------------------------------+------+----------+--------------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where |
| 1 | PRIMARY | OUTSIDE | NULL | ref | camtimestamp,camname,CamNameCamTime | CamNameCamTime | 263 | INSIDE.camname,INSIDE.maxtimestamp | 1 | 100.00 | NULL |
| 2 | DERIVED | events | NULL | range | camname,CamNameCamTime | CamNameCamTime | 257 | NULL | 2 | 100.00 | Using index for group-by |
+----+-------------+------------+------------+-------+-------------------------------------+----------------+---------+------------------------------------+------+----------+--------------------------+
3 rows in set, 1 warning (0.00 sec)
成功了!
【问题讨论】:
-
在
(camname, camtimestamp)上添加复合索引应该有助于提高子查询和连接的性能。此外,虽然我认为它不一定会提高性能,但我还建议切换到显式 JOIN 语法,而不是继续使用过时的隐式“逗号”连接。 -
Uueerdo,您的建议非常有效!请考虑回答这个问题,以便我可以授予您解决方案。请参阅上面的编辑,其中总结了我对您的解决方案的发现。
-
这是执行“groupwise-max”的最快方法,但它确实需要该索引。
标签: mysql select optimization groupwise-maximum