我的查询运行时间为28.39秒。我该如何优化呢?
explain SELECT distinct UNIX_TIMESTAMP(timestamp)*1000 as timestamp,count(a.sig_name) as counter from event a,network n where n.fsi='pays' and n.net=inet_ntoa(a.ip_src) group by date(timestamp) order by timestamp asc;
+----+-------------+-------+--------+---------------+---------+---------+--- ---+---------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------+---------+---------------------------------+
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 8177074 | Using temporary; Using filesort |
| 1 | SIMPLE | n | eq_ref | PRIMARY,fsi | PRIMARY | 77 | func | 1 | Using where |
+----+-------------+-------+--------+---------------+---------+---------+------+---------+---------------------------------+
答案 0 :(得分:2)
因此,通常查看您的查询,我们发现表event
a
正在检查8,177,074行。这可能是缓慢的“根”,所以我们想看看如何使用索引减少搜索空间。
event
a
的主要条件是
n.net=inet_ntoa(a.ip_src)
这里的问题是我们需要在a.ip_src的每一行上执行计算(inet_ntoa),因此除了扫描整个表之外别无选择。一个可能更好的解决方案是反转比较并确保a.ip_src被索引。
a.ip_src=inet_aton(n.net)
如果我们在n
中匹配的行数少于a
中的行数,则效果会更好。如果不是这种情况,您应该认真考虑在表中缓存此函数的结果并在其上创建索引。
最后我猜测时间戳列在event
a
中,在这种情况下,索引可能有助于排序和分组,但可能没有。您可以在(ip_src,timestamp)
答案 1 :(得分:0)
实践是在可以在WHERE/JOIN
子句中使用的列上引入至少索引。我使用过至少是因为在很多情况下应该尝试使用PRIMARY/FOREIGN KEY
关系。因此,如果某些东西已经是主/外键,则无需进一步索引。
通过以下查询引入INDEX可以简单地改进上述查询:
ALTER TABLE events ADD INDEX idx_ev_ipsrc (ip_src);
此处idx_ev_ipsrc
=索引键的名称,而ip_src
是要编制索引的列。
进一步提升:
使用以下查询在网络表上引入多列索引:
ALTER TABLE network ADD INDEX idx_net_fsi_net (fsi,net);
以上情况会导致行数甚至很少。
注意:以上查询适用于MySql,可以轻松地为其他数据库量身定制。