Я думаю, что главная причина, по которой запрос выполняется медленно даже с индексом ipfrom, ipto , заключается в том, что движок не может правильно использовать индекс.
Он принимает первое условие ipfrom <= @ip
и может использовать индекс для этого, однако это неравенство имеет низкий выбор, и если ваши диапазоны ip охватывают все ips и не перекрываются, то для индекса есть только один ipto запись для каждого ipfrom индексный лист.
Это не очень полезно, и в итоге выполняется полное сканирование индекса (допущение1).
Итак, чтобы ускорить его, есть несколько хитростей
1) Если select @ip_max_delta = max(ipto-ipfrom)
не слишком большой (~ 1000 записей), вы можете добавить WHERE ipfrom > (@ip - @ip_max_delta)
(это можно использовать напрямую, только если ip хранятся как int). Это будет хорошо работать с любым индексом, начинающимся с ipfrom
2)
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
Это должно вернуться очень быстро (особенно если вы кластеризуетесь по ipfrom и должны делать это, так как ваши данные редко изменяются).
Если вышеупомянутое не возвращает быстро, вы можете проверить время выполнения (и план) по следующему запросу, просто для справки
SELECT id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom = @ip
(выберите существующий @ip, который существует в столбце ipfrom)
EDIT2 : решение Re Martin
Не вижу смысла a) использовать пересечение / подзапрос и b) для поддержания двух индексов
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
Должен возвращать то же, что и запрос Мартина, если существует корреляция между ipfrom и ipto в последовательных строках. Если нет, то дополнительное условие может быть применено непосредственно
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip AND @ip <= ipto
ORDER BY ipfrom DESC
Этот запрос очень похож на начальный, но ORDER BY должен позволять парсеру выбирать лучший план (не проверенный). Если нет, то
SELECT id, ipfrom, ipto, countrycode, countryname,region,city
FROM
(SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC) s
WHERE @ip <= ipto
Должен сделать трюк и потребует только индекс на ipfrom.