Ik had te maken met een soortgelijk probleem, waarbij ik een database met ongeveer 4 miljoen IP-bereiken moest doorzoeken en een mooie oplossing vond die het aantal gescande rijen terugbracht van 4 miljoen naar ongeveer ~5 (afhankelijk van het IP):
Deze SQL-instructie:
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
wordt getransformeerd naar:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
Het probleem is dat MySQL alle rijen met 'range_begin <=$iplong' ophaalt en vervolgens moet scannen als 'range_end>=$iplong'. Deze eerste AND-voorwaarde (range_begin <=$iplong) heeft ongeveer 2 miljoen rijen opgehaald en ze moeten allemaal worden gecontroleerd of range_end overeenkomt.
Dit kan echter drastisch worden vereenvoudigd door één EN-voorwaarde toe te voegen:
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
De verklaring
range_begin <= $iplong AND range_begin >= $iplong-65535
haalt alleen items op waarvan de range_begin tussen $iplong-65535 en $iplong ligt. In mijn geval verminderde dit het aantal opgehaalde rijen van 4 miljoen. tot ongeveer 5 en de runtime van het script daalde van meerdere minuten tot een paar seconden.
Opmerking over 65535 :Dit is voor mijn tabel de maximale afstand tussen range_begin en range_end, d.w.z. (range_end-range_begin) <=65535 voor al mijn rijen. Als je grotere IP-bereiken hebt, moet je de 65535 verhogen, als je kleinere IP-bereiken hebt, kun je deze constante verlagen. Als deze constante te groot is (bijvoorbeeld 4 miljard), bespaart u geen zoektijd.
Voor deze zoekopdracht heeft u alleen een index op range_begin nodig.