Занимавах се с подобен проблем, където трябваше да търся база данни с около 4 милиона IP диапазони и намерих хубаво решение, което намали броя на сканираните редове от 4 милиона на около ~5 (в зависимост от IP):
Това SQL изявление:
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
се трансформира в:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
Проблемът е, че MySQL извлича всички редове с 'range_begin <=$iplong' и след това трябва да сканира, ако 'range_end>=$iplong'. Това първо условие И (range_begin <=$iplong) извлече около 2 милиона реда и всички трябва да бъдат проверени дали range_end съвпада.
Това обаче може да се опрости драстично чрез добавяне на едно условие И:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
Изявлението
range_begin <= $iplong AND range_begin >= $iplong-65535
извлича само записи, където range_begin е между $iplong-65535 и $iplong. В моя случай това намали броя на извлечените редове от 4 милиона. до около 5 и времето за изпълнение на скрипта намаля от няколко минути на няколко секунди.
Бележка за 65535 :Това е за моята таблица максималното разстояние между range_begin и range_end, т.е. (range_end-range_begin) <=65535 за всичките ми редове. Ако имате по-големи IP-обхвати, трябва да увеличите 65535, ако имате по-малки IP-обхвати, можете да намалите тази константа. Ако тази константа е твърде голяма (например 4 милиарда), няма да спестите време за заявка.
За тази заявка се нуждаете само от индекс на range_begin.