【问题标题】:Very slow JOIN query非常慢的 JOIN 查询
【发布时间】:2014-10-23 09:34:31
【问题描述】:

我有一个问题:

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 大约有 160 万行

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)

【问题讨论】:

  • 可能是因为你加入了一个不能使用索引的函数调用。
  • @Strawberry 抱歉,现在包含它! :)
  • @juergend (像往常一样)是正确的。如果你存储并索引 inet_aton 值,这个查询会快很多。
  • ipaddress 上添加了一个索引,但查询仍然和以前一样慢

标签: mysql performance


【解决方案1】:

像这样进行地址查找是非常低效的。首先,您使用函数作为连接表达式,这意味着您不能使用索引,并且范围查询(尤其是 IP 地址)非常低效。

在两个表中使用相同的数据类型会有所帮助。要解决范围查找问题,有两种解决方案:

1) 使用固定范围(例如 255.255.255.0 网络掩码)而不是具有任意网络范围的参考集,这可以是当前表之间的 n:m 分解形式,这也允许您保持不同的数据类型,但使用索引。

这是一个相当笨拙的解决方案。

2) 将 IP 地址的参考集保存在地理空间表中。请注意,虽然地址范围是一维空间,但 MySQL 地理空间数据库仅真正理解二维空间,因此您需要稍微捏造空间 - 这很好地描述了 here

请注意,时间范围查找的影响较小,因为谓词的上限和下限由表中的同一列定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多