【发布时间】:2014-03-02 08:33:13
【问题描述】:
我有一个结构如下的表:
CREATE TABLE `geo_ip` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`start_ip` int(10) unsigned NOT NULL,
`end_ip` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `start_ip` (`start_ip`),
KEY `end_ip` (`end_ip`),
KEY `start_end` (`start_ip`,`end_ip`),
KEY `end_start` (`end_ip`,`start_ip`)) ENGINE=InnoDB;
MySQL 似乎无法对我的大多数查询使用索引,因为where 子句使用了介于start_ip 和end_ip 之间的between:
select * from geo_ip where 2393196360 between start_ip and end_ip;
+----+-------------+--------+------+-------------------------------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+-------------------------------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | geo_ip | ALL | start_ip,end_ip,start_end,end_start | NULL | NULL | NULL | 2291578 | Using where |
+----+-------------+--------+------+-------------------------------------+------+---------+------+---------+-------------+
该表有几百万条记录。我尝试通过删除start_ip 和end_ip 列来扩展表,并为start_ip 和end_ip 的每个可能值创建一行作为id,然后查询id。虽然这极大地提高了查询性能,但它导致表大小从不到 1 GB 增长到数十 GB(该表显然还有其他列)。
还可以做些什么来提高查询性能?我可以以某种方式更改查询,还是可以对列进行不同的索引以导致命中?或者可能是我还没有想到的?
编辑:
奇怪的是,索引用于某些值。例如:
explain select * from geo_ip where 3673747503 between start_ip and end_ip;
+----+-------------+--------+-------+-------------------------------------+--------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+-------------------------------------+--------+---------+------+-------+-------------+
| 1 | SIMPLE | geo_ip | range | start_ip,end_ip,start_end,end_start | end_ip | 4 | NULL | 19134 | Using where |
+----+-------------+--------+-------+-------------------------------------+--------+---------+------+-------+-------------+
【问题讨论】:
-
哪个 MySQL 版本? This fiddle(诚然表中没有数据)似乎试图使用索引
start_end。 -
mysql Ver 14.14 Distrib 5.5.35, for debian-linux-gnu (x86_64) using readline 6.2 -
如果你暂时不需要写信给表格,可以试试
ANALYZE TABLE。 -
有趣。我在那个小提琴中添加了一些数据,它似乎仍然使用 start_end 索引。不知道为什么我的结果不同。我会试试
ANALYZE TABLE,谢谢。 -
我认为这取决于这些值的基数,如果某个值的命中次数过多,优化器会选择另一个索引。是的,我迟到了。