Reputation: 1
Strange thing happens. Can anyone please explain. I have a table.
CREATE TABLE "country_ip" (
"begin_ip" varchar(15) NOT NULL,
"end_ip" varchar(15) NOT NULL,
"begin_ip_long" int(10) unsigned NOT NULL,
"end_ip_long" int(10) unsigned NOT NULL,
"id" char(2) NOT NULL,
"label" varchar(50) NOT NULL,
KEY "begin_ip_long" ("begin_ip_long","end_ip_long"),
KEY "end_ip_long" ("end_ip_long")
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
There are about 150 000 records. next queries have huge time difference
0.06329400 | SELECT * FROM `country_ip` WHERE '1405662435' BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1
0.06214600 | SELECT * FROM `country_ip` USE INDEX (begin_ip_long, end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1
0.00008400 | SELECT * FROM `country_ip` USE INDEX (end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1
Can anyone explain why does it happens? I mean why only USE INDEX (end_ip_long) helps while using USE INDEX (begin_ip_long) or USE INDEX (begin_ip_long, end_ip_long) has no effect. Thanks.
Upvotes: 0
Views: 59
Reputation: 14164
Since you can get the single-column (END_IP_LONG) index to work fast, why not just index & search on one column?
I'd probably use BEGIN_IP_LONG and search for the first record where specified IP was >= country.BEGIN_IP_LONG, order them by IP descending, limit 1. That should retrieve the "floor" entry, all you need to do then is check the specified IP is not beyond the END_IP_LONG of that country.
This will accomplish the lookup correctly, using only a single-column index. (All of this assumes ranges do not overlap, which I assume is true given your stated structures.)
As others suggested, investigating MySQL's plan (and perhaps rebuilding statistics) would be worthwhile -- but technically, non-overlapping range lookups should technically be possible using an index on only a single bound.
Upvotes: 1
Reputation: 2576
Maybe it's because index (end_ip_long)
is smaller then (begin_ip_long, end_ip_long)
and it fits in memory and one column is selective enough. While bigger index may require to read from disk.
Upvotes: 1