Jag hade att göra med ett liknande problem, där jag var tvungen att söka i en databas med cirka 4 miljoner IP-intervall och hittade en bra lösning som minskade antalet skannade rader från 4 miljoner till cirka ~5 (beroende på IP):
Denna SQL-sats:
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
omvandlas till:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
Problemet är att MySQL hämtar alla rader med 'range_begin <=$iplong' och måste sedan skanna om 'range_end>=$iplong'. Detta första AND-villkor (range_begin <=$iplong) hämtade cirka 2 miljoner rader, och alla måste kontrolleras om range_end matchar.
Detta kan dock förenklas dramatiskt genom att lägga till ett AND-villkor:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
Uttalandet
range_begin <= $iplong AND range_begin >= $iplong-65535
hämtar endast poster där range_begin är mellan $iplong-65535 och $iplong. I mitt fall minskade detta antalet hämtade rader från 4 miljoner. till cirka 5 och skriptets körtid gick ner från flera minuter till några sekunder.
Anmärkning om 65535 :Detta är för min tabell det maximala avståndet mellan range_begin och range_end, dvs (range_end-range_begin) <=65535 för alla mina rader. Om du har större IP-intervall måste du öka 65535, om du har mindre IP-intervall kan du minska denna konstant. Om denna konstant är för stor (till exempel 4 miljarder), kommer du inte att spara någon frågetid.
För den här frågan behöver du bara ett index på range_begin.