我有一个问题:
EXPLAIN
SELECT i.ipStart, i.ipEnd, i.descr
FROM orgs i
JOIN visit_count v
on inet_aton(v.ipaddress) BETWEEN i.ipStart and i.ipEnd
WHERE v.last_visit BETWEEN '2014-10-10' AND '2014-10-22'
AND v.user_id = 1
随着时间的增加,上述情况非常缓慢。以上大约需要20秒。
我的两个表模式:
`visit_count` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`visitCount` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`cookieId` varchar(50) NOT NULL,
`ipaddress` varchar(50) NOT NULL,
`last_visit` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `cookieId` (`cookieId`),
KEY `user_id` (`user_id`),
KEY `last_visit` (`last_visit`),
KEY `user_id_2` (`user_id`,`last_visit`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
`orgs` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ipStart` bigint(100) DEFAULT NULL,
`ipEnd` bigint(100) DEFAULT NULL,
`land` varchar(250) DEFAULT NULL,
`descr` varchar(250) DEFAULT NULL,
`ipStartRead` varchar(250) DEFAULT NULL,
`ipEndRead` varchar(250) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ipStart` (`ipStart`,`ipEnd`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
visit_count
有大约1,6 mil行
和
orgs
有大约14k行
我有什么想法可以让它变得更快?
修改
解释:
+----+-------------+-------+-------+------------------------------+-----------+---------+------+-------+---------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------------+-----------+---------+------+-------+---------------------------------------------------+
1 SIMPLE v range user_id,last_visit,user_id_2 user_id_2 9 NULL 357 Using index condition
1 SIMPLE i ALL NULL NULL NULL NULL 22068 Using where; Using join buffer (Block Nested Loop)
答案 0 :(得分:0)
执行这样的地址查找非常有效。首先,您使用函数作为连接表达式,这意味着您无法使用索引,范围查询(尤其是IP地址)非常无效。
在两个表中使用相同的数据类型会有所帮助。要解决范围查找问题,有两种解决方案:
1)而不是具有任意网络范围的参考集,使用固定范围(例如255.255.255.0 netmasked)这可以是:当前表之间的m分解形式,这也可以让你保持不同数据类型但使用索引。
这是一个相当愚蠢的解决方案。
2)在地理空间表中保留IP地址的参考集。请注意,尽管地址范围是一维空间,但MySQL地理空间数据库只能真正了解二维空间,因此您需要稍微调整一下空间 - 这很好地描述了here
请注意,时间范围查找的影响较小,因为谓词的上限和下限是由表中相同列定义的。