I have a table in MySQL like this:
startIp | endIp | city | countryCode | latitude | longitude |
---|---|---|---|---|---|
16777216 | 16777471 | Los Angeles | US | 34.0522 | -118.244 |
16777472 | 16778239 | Fuzhou | CN | 26.0614 | 119.306 |
16778240 | 16779263 | Melbourne | AU | -37.814 | 144.963 |
and 2.7 million more entries.
Now I have a converted IP Adresss like 16777566.
This should return "Fuzhou, CN, 26.0614, 119.306"
Right now I use this query:
SELECT * FROM
kombiniert
WHERE startIp < 16777566 AND endIp > 16777566
It works really well but its to slow.
Performance:
Without LIMIT: SELECT * FROM
avg (2300ms)
kombiniert
WHERE startIp < 2264918979 AND endIp > 2264918979;
With LIMIT: SELECT * FROM
avg (1500ms)
kombiniert
WHERE startIp < 2264918979 AND endIp > 2264918979 LIMIT 1;
Indexed Without LIMIT: SELECT * FROM
avg (5300ms)
kombiniert
WHERE startIp < 2264918979 AND endIp > 2264918979;
Indexed With LIMIT: SELECT * FROM
avg (5500ms)kombiniert
WHERE startIp < 2264918979 AND endIp > 2264918979 LIMIT 1;
EDIT:I forgot to mention: The fields startIp, endIp are bigint!
EDIT2: table creation sql:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
CREATE TABLE `kombiniert` (<br>
`id` int(11) NOT NULL,<br>
`startIp` bigint(20) NOT NULL,<br>
`endIp` bigint(20) NOT NULL,<br>
`city` text NOT NULL,<br>
`countryCode` varchar(4) NOT NULL,<br>
`latitude` float NOT NULL,<br>
`longitude` float NOT NULL<br>
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;<br>
<br>
ALTER TABLE `kombiniert`<br>
ADD PRIMARY KEY (`id`),<br>
ADD KEY `startIp` (`startIp`),<br>
ADD KEY `endIp` (`endIp`);<br>
<br>
ALTER TABLE `kombiniert`<br>
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2747683;<br>
COMMIT;<br>
Searching for IP addresses (or any other metric that is split into buckets) is not efficient. Or at least not efficient with the obvious code. The best average performance you can get is scanning one-quarter of the table for what you are looking for. That is "Order(N)".
You can get "Order(1)" performance for most operations, but it takes a restructuring of the table and the query. See http://mysql.rjweb.org/doc.php/ipranges