mysql join不使用'between'运算符的索引

Posted

技术标签:

【中文标题】mysql join不使用\'between\'运算符的索引【英文标题】:mysql join not use index for 'between' operatormysql join不使用'between'运算符的索引 【发布时间】:2012-05-25 21:09:02 【问题描述】:

所以基本上我有三个表:

CREATE TABLE `cdIPAddressToLocation` (
  `IPADDR_FROM` int(10) unsigned NOT NULL COMMENT 'Low end of the IP Address block',
  `IPADDR_TO` int(10) unsigned NOT NULL COMMENT 'High end of the IP Address block',
  `IPLOCID` int(10) unsigned NOT NULL COMMENT 'The Location ID for the IP Address range',
  PRIMARY KEY  (`IPADDR_TO`),
  KEY `Index_2` USING BTREE (`IPLOCID`),
  KEY `Index_3` USING BTREE (`IPADDR_FROM`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE `cdIPLocation` (
  `IPLOCID` int(10) unsigned NOT NULL default '0',
  `Country` varchar(4) default NULL,
  `Region` int(10) unsigned default NULL,
  `City` varchar(90) default NULL,
  `PostalCode` varchar(10) default NULL,
  `Latitude` float NOT NULL,
  `Longitude` float NOT NULL,
  `MetroCode` varchar(4) default NULL,
  `AreaCode` varchar(4) default NULL,
  `State` varchar(45) default NULL,
  `Continent` varchar(10) default NULL,
  PRIMARY KEY  (`IPLOCID`)
) ENGINE=MyISAM AUTO_INCREMENT=218611 DEFAULT CHARSET=latin1;

CREATE TABLE 'data'
 'IP' varchar(50)
 'SCORE' int

我的任务是连接这三个表并找到给定 IP 地址的位置数据。 我的查询如下:

select 
    t.ip,
    l.Country,
    l.State,
    l.City,
    l.PostalCode,
    l.Latitude,
    l.Longitude,
    t.score
from
    (select 
        ip, inet_aton(ip) ipv, score
    from
        data
    order by score desc
    limit 5) t
        join
    cdIPAddressToLocation a ON t.ipv between a.IPADDR_FROM and a.IPADDR_TO
        join
    cdIPLocation l ON l.IPLOCID = a.IPLOCID

虽然此查询有效,但速度非常慢,在我的开发盒上返回结果大约需要 100 秒。

我使用的是 mysql 5.1,cdIPAddressToLocation 有 590 万行,cdIPLocation 表有大约 30 万行。

当我检查执行计划时,我发现它没有使用表“cdIPAddressToLocation”中的任何索引,因此对于“数据”表中的每一行,它都会对表“cdIPAddressToLocation”进行全表扫描。 这对我来说很奇怪。我的意思是,既然表 'cdIPAddressToLocation' 中的列 'IPADDR_FROM' 和 'IPADDR_TO' 上已经有两个索引,执行计划应该利用索引来提高性能,但为什么它没有使用它们。

还是我的查询有问题?

请帮忙,非常感谢。

【问题讨论】:

换成t.ipv >= a.IPADDR_FROM AND t.ipv <= a.IPADDR_TO,你会发现它不会使用索引。我自己也遇到过同样的事情,但无法弄清楚。最终将 ip 表拆分为多个单独的表,并根据网络掩码将查询发送到适当的范围,因为它只是一次运行。 【参考方案1】:

您是否尝试过对 cdIPAddressToLocation.IPADDR_FROM 和 cdIPAddressToLocation.IPADDR_TO 列使用复合索引?

Multiple-Column Indexes

【讨论】:

以上是关于mysql join不使用'between'运算符的索引的主要内容,如果未能解决你的问题,请参考以下文章

Mysql Inner join,Where,Between 在多个表中

使用 mySQL 运算符 BETWEEN 和经典日期间隔之间有啥区别? [复制]

MySQL的WHERE语句中BETWEEN与IN的使用教程

MySQL BETWEEN 语法

MySQL的WHERE语句中BETWEEN与IN的用法和他们的区别

带有 BETWEEN 运算符的 MySQL IF 语句,未显示为有效