Řešil jsem podobný problém, kdy jsem musel prohledat databázi s asi 4 miliony rozsahů IP a našel pěkné řešení, které snížilo počet naskenovaných řádků ze 4 milionů na přibližně ~5 (v závislosti na IP):
Tento příkaz SQL:
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
se transformuje na:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
Problém je v tom, že MySQL načte všechny řádky s 'range_begin <=$iplong' a poté potřebuje skenovat, pokud 'range_end>=$iplong'. Tato první podmínka AND (range_begin <=$iplong) načetla asi 2 miliony řádků a všechny je třeba zkontrolovat, pokud se range_end shoduje.
To však lze výrazně zjednodušit přidáním jedné podmínky AND:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
Prohlášení
range_begin <= $iplong AND range_begin >= $iplong-65535
načte pouze záznamy, kde je range_begin mezi $iplong-65535 a $iplong. V mém případě to snížilo počet načtených řádků ze 4 milionů. na přibližně 5 a běh skriptu se zkrátil z několika minut na několik sekund.
Poznámka na 65535 :Toto je pro mou tabulku maximální vzdálenost mezi range_begin a range_end, tj. (range_end-range_begin) <=65535 pro všechny mé řádky. Pokud máte větší rozsahy IP, musíte zvýšit 65535, pokud máte menší rozsahy IP, můžete tuto konstantu snížit. Pokud je tato konstanta příliš velká (například 4 miliardy), neušetříte čas na dotaz.
Pro tento dotaz potřebujete pouze index na range_begin.