【发布时间】:2015-06-19 21:30:29
【问题描述】:
我需要用geoip 表中的国家名称填充users 表中的location 字段,具体取决于用户的IP。
这是表的 CREATE 代码。
CREATE TABLE `geoip` (
`IP_FROM` INT(10) UNSIGNED ZEROFILL NOT NULL DEFAULT '0000000000',
`IP_TO` INT(10) UNSIGNED ZEROFILL NOT NULL DEFAULT '0000000000',
`COUNTRY_NAME` VARCHAR(50) NOT NULL DEFAULT '',
PRIMARY KEY (`IP_FROM`, `IP_TO`)
)
ENGINE=InnoDB;
CREATE TABLE `users` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`login` VARCHAR(25) NOT NULL DEFAULT ''
`password` VARCHAR(64) NOT NULL DEFAULT ''
`ip` VARCHAR(128) NULL DEFAULT ''
`location` VARCHAR(128) NULL DEFAULT ''
PRIMARY KEY (`id`),
UNIQUE INDEX `login` (`login`),
INDEX `ip` (`ip`(10))
)
ENGINE=InnoDB
ROW_FORMAT=DYNAMIC;
我尝试运行的更新查询是:
UPDATE users u
SET u.location =
(SELECT COUNTRY_NAME FROM geoip WHERE INET_ATON(u.ip) BETWEEN IP_FROM AND IP_TO)
问题是这个查询拒绝在geoip 表上使用PRIMARY 索引,尽管它会加快速度。解释给了我:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY u index NULL PRIMARY 4 NULL 1254395
2 DEPENDENT SUBQUERY geoip ALL PRIMARY NULL NULL NULL 62271 Using where
我最终将 geoip 表转换为仅用于此查询的 MEMORY 引擎,但我想知道什么是正确的方法。
更新 我使用的 DBMS 是 MariaDB 10.0.17,如果它可以有所作为的话。
【问题讨论】:
-
可能 inet_aton() 正在扔东西。您正在强制数据库即时转换您的所有 IP,因此无法使用索引 - 派生值未编制索引。
-
@MarcB,不幸的是,即使我使用计算出的 INET_ATON() 结果创建一个 INT 列并使用该列运行查询,查询计划也保持不变。
-
这不是 inet_aton - 这也是我的第一个想法,但索引位于 ip_from 和 ip_to 列上,它可以很好地用于选择范围优化。据我所知,查询优化中可能会忽略 NULL 列,所以这是我目前的理论。
-
我已经检查过了,NULL 也不是这里的情况。即使我使用 INT NOT NULL 列,它仍然会忽略索引。此外,如果我使用一些整数常量而不是实际的
ip列,则会使用索引。那么,也许是一个错误?
标签: mysql mariadb query-performance