提高Mysql查询速度
我有一个包含事件的数据库表提高Mysql查询速度,mysql,Mysql,我有一个包含事件的数据库表 mysql> describe events; +-------------+------------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+------------------+-
mysql> describe events;
+-------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------------------+----------------+
| device | varchar(32) | YES | MUL | NULL | |
| psu | varchar(32) | YES | MUL | NULL | |
| event | varchar(32) | YES | MUL | NULL | |
| down_time | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| up_time | timestamp | NO | MUL | 0000-00-00 00:00:00 | |
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+-------------+------------------+------+-----+---------------------+----------------+
6 rows in set (0.01 sec)
我希望查找时间重叠的事件,并使用以下查询:
SELECT *
FROM link_events a
JOIN link_events b
ON ( a.down_time <= b.up_time )
AND ( a.up_time >= b.down_time )
WHERE (a.device = 'd1' AND b.device = 'd2')
AND (a.psu = 'p1' AND b.psu = 'p2')
AND (a.event = 'e1' AND b.event = 'e2');
+-------------+-----------+------------+---------------------+---------------------+--------+-------------+-----------+------------+---------------------+---------------------+--------+
| device | psu | event | down_time | up_time | id | device | psu | event | down_time | up_time | id |
+-------------+-----------+------------+---------------------+---------------------+--------+-------------+-----------+------------+---------------------+---------------------+--------+
| d1 | p1 | e1 | 2013-01-14 16:42:10 | 2013-01-14 16:43:00 | 374529 | d2 | p2 | e2 | 2013-01-14 16:42:14 | 2013-01-14 16:42:18 | 211570 |
| d1 | p1 | e1 | 2013-05-29 18:49:26 | 2013-05-30 12:31:15 | 374569 | d2 | p2 | e2 | 2013-05-30 08:48:20 | 2013-05-30 08:48:27 | 211787 |
| d1 | p1 | e1 | 2013-05-29 18:49:26 | 2013-05-30 12:31:15 | 374569 | d2 | p2 | e2 | 2013-05-30 08:48:54 | 2013-05-30 08:48:58 | 211788 |
+-------------+-----------+------------+---------------------+---------------------+--------+-------------+-----------+------------+---------------------+---------------------+--------+
3 rows in set (35.88 sec)
该数据库安装在Windows 7笔记本电脑上,并使用MyISAM引擎。
有没有办法更好地组织数据库或将索引更改为
提高查询时间,第一次查询为35秒。重复
但是,如果我“刷新表”并
第三次重复查询所用时间再次为35秒。
感谢您的帮助
以下是添加键后解释的输出:
mysql> EXPLAIN
-> SELECT *
->
-> FROM link_events a
-> JOIN link_events b
->
-> ON ( a.down_time <= b.up_time )
-> AND ( a.up_time >= b.down_time )
->
-> WHERE (a.device = 'd1' AND b.device = 'd2')
-> AND (a.psu = 'l1' AND b.psu = 'l2')
-> AND (a.event = 'e1' AND b.event = 'e2');
+----+-------------+-------+------+--------------------------------------------------------------------------------+---------------+---------+-------------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+--------------------------------------------------------------------------------+---------------+---------+-------------------+------+-----------------------+
| 1 | SIMPLE | b | ref | device,psu,event,down_time,up_time,device_2,device_3 | device_2 | 297 | const,const,const | 180 | Using index condition |
| 1 | SIMPLE | a | ref | device,psu,event,down_time,up_time,device_2,device_3 | device_2 | 297 | const,const,const | 7744 | Using index condition |
+----+-------------+-------+------+--------------------------------------------------------------------------------+---------------+---------+-------------------+------+-----------------------+
2 rows in set (0.07 sec)
说明:
mysql> EXPLAIN
->
-> SELECT
->
-> CONCAT('Link1','-', 'Link2') overlaps,
-> GREATEST(a.down_time,b.down_time) AS downtime,
-> LEAST(a.up_time,b.up_time) AS uptime,
-> TIME_TO_SEC(TIMEDIFF( LEAST(a.up_time,b.up_time),
-> GREATEST(a.down_time,b.down_time))) AS duration
->
-> FROM link_events a
-> JOIN link_events b
->
-> ON Intersects (a.span, b.span)
->
-> WHERE (a.device_name = 'd1' AND b.device_name = 'd2')
-> AND (a.link_name = 'l1' AND b.link_name = 'l2')
-> AND (a.event_type = 'e1' AND b.event_type = 'e1');
+----+-------------+-------+------+-------------------------------------------------------------------+---------------+---------+-------------------+-------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------------------------------------------------+---------------+---------+-------------------+-------+------------------------------------+
| 1 | SIMPLE | a | ref | span,device_name,link_name,event_type,device_name_2,device_name_3 | device_name_2 | 297 | const,const,const | 383 | Using index condition |
| 1 | SIMPLE | b | ref | span,device_name,link_name,event_type,device_name_2,device_name_3 | device_name_2 | 297 | const,const,const | 14580 | Using index condition; Using where |
+----+-------------+-------+------+-------------------------------------------------------------------+---------------+---------+-------------------+-------+------------------------------------+
2 rows in set (0.09 sec)
使用交叉点需要1分钟12秒?用于此查询:
SELECT *
FROM link_events a JOIN
link_events b
ON (a.down_time <= b.up_time) AND (a.up_time >= b.down_time)
WHERE (a.device = 'd1' AND b.device = 'd2') AND
(a.psu = 'p1' AND b.psu = 'p2') AND
(a.event = 'e1' AND b.event = 'e2');
对于此查询:
SELECT *
FROM link_events a JOIN
link_events b
ON (a.down_time <= b.up_time) AND (a.up_time >= b.down_time)
WHERE (a.device = 'd1' AND b.device = 'd2') AND
(a.psu = 'p1' AND b.psu = 'p2') AND
(a.event = 'e1' AND b.event = 'e2');
尝试:
希望这将是足够有选择性的。如果这没有帮助,请发布EXPLAIN
的结果,这样我们可以确保优化器尽其所能,如果需要,我们将从那里开始
编辑:
理解并非所有索引对于特定查询都具有相同的值是很重要的。一个常见的错误是,如果您只引用索引中的列,则将索引视为自动加快查询速度的神奇工作者。事实并非如此。密钥的设计和查询的编写都需要确保记录的最佳访问路径。更改可能看起来无关紧要的内容,例如索引中列的顺序或写入SQRT(x)=4.4
而不是x=4.4*4.4
,可能会使索引不可用,并使查询速度降低一千倍甚至一百万倍以上
我强烈建议您阅读以下内容:
了解MySQL如何使用密钥可以在将来为您节省很多麻烦
编辑2-另一个想法是添加一列span GEOMETRY NOT NULL,空格键(span)
包含linestring(point(up\u time,0),point(down\u time,0))
-时间需要是数字的(例如,您可以使用UNIX\u TIMESTAMP()
进行转换),并在查询中使用相交(a.span,b.span)
。通过一些微调,这可能比改进后的查询速度快得多,因为跨度交叉点是使用专门为此类问题设计的基于几何体的算法进行检测的。尝试:
希望这将是足够有选择性的。如果这没有帮助,请发布EXPLAIN
的结果,这样我们可以确保优化器尽其所能,如果需要,我们将从那里开始
编辑:
理解并非所有索引对于特定查询都具有相同的值是很重要的。一个常见的错误是,如果您只引用索引中的列,则将索引视为自动加快查询速度的神奇工作者。事实并非如此。密钥的设计和查询的编写都需要确保记录的最佳访问路径。更改可能看起来无关紧要的内容,例如索引中列的顺序或写入SQRT(x)=4.4
而不是x=4.4*4.4
,可能会使索引不可用,并使查询速度降低一千倍甚至一百万倍以上
我强烈建议您阅读以下内容:
了解MySQL如何使用密钥可以在将来为您节省很多麻烦
编辑2-另一个想法是添加一列
span GEOMETRY NOT NULL,空格键(span)
包含linestring(point(up\u time,0),point(down\u time,0))
-时间需要是数字的(例如,您可以使用UNIX\u TIMESTAMP()
进行转换),并在查询中使用相交(a.span,b.span)
。通过一些微调,这可能比改进后的查询速度快得多,因为跨度交点是使用专门为这类事情设计的基于几何体的算法来检测的。Flush tables会清除缓存,因此在调用后需要同样的时间。最有可能的情况是,如果您更改数据或执行一些其他查询,则会再次花费很长时间。我发现SHOW CREATE(或仅DDL)比descripbeflush tables更有用,它会清除缓存,因此在调用后再次花费相同的时间。如果您更改数据或执行其他查询,很可能会再次花费很长时间。我发现SHOW CREATE(或仅DDL)比descripbei建议的所有5列都需要一个索引更有用。我认为在这种情况下最好。非常感谢为字段添加了索引,但没有使它们成为键。这将查询时间从36秒提高到了8.6秒。我建议您对所有5列使用一个索引。我认为在这种情况下这是最好的。非常感谢为字段添加了索引,但没有使它们成为键。这将查询时间从36秒提高到了8.6秒,这使Sasha的查询时间有了很大的不同,现在是8.6秒。我在应用添加键后发布了解释。我已经为这些字段创建了索引,但没有将它们设置为键。@user2149346我不明白这意味着什么?!?!嗨,草莓..我最初在设备、psu、事件、停机时间和停机时间上创建了链接事件,但没有索引。为了加快查询速度,我决定添加索引并发布:altertablelink\u events添加索引(device、psu、event、down\u time、up\u time);但这并没有加快查询速度。正如Sasha建议的那样,我随后添加了:ALTER TABLE link_events ADD KEY(设备、psu、事件、停机时间、停机时间)、ADD KEY(设备、psu、事件、停机时间、停机时间)这将查询从35秒提高到了8.5秒。我不明白为什么需要这样做,因为我认为添加索引命令就足够了??我已经按照您的建议添加了span列。它能工作,但速度较慢!。我已经发布了解释的结果。非常感谢你的帮助。这让Sasha的查询时间大大不同,现在是8.6秒。我在应用添加键后发布了解释。我已经为这些字段创建了索引,但没有将它们设置为键。@user2149346我不明白这意味着什么?!?!嗨,草莓..我最初在设备上创建了没有索引的link_事件,p
SELECT *
FROM link_events a JOIN
link_events b
ON (a.down_time <= b.up_time) AND (a.up_time >= b.down_time)
WHERE (a.device = 'd1' AND b.device = 'd2') AND
(a.psu = 'p1' AND b.psu = 'p2') AND
(a.event = 'e1' AND b.event = 'e2');
SELECT *
FROM link_events a JOIN
link_events b
ON (a.down_time <= b.up_time) AND (a.up_time >= b.down_time)
WHERE (a.device, a.psu, a.event) IN (('d1', 'p1', 'e1')) AND
(b.device, a.psu, a.event) IN (('d2', 'p2', 'e2'));
ALTER TABLE link_events ADD KEY(device,psu,event,up_time),
ADD KEY(device,psu,event,down_time)