Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL:Wie erstelle ich eine schnellere IP-Bereichsabfrage? GeoIP

Ich hatte es mit einem ähnlichen Problem zu tun, bei dem ich eine Datenbank mit etwa 4 Millionen IP-Bereichen durchsuchen musste und eine nette Lösung fand, die die Anzahl der gescannten Zeilen von 4 Millionen auf etwa 5 (je nach IP) reduzierte:

Diese SQL-Anweisung:

SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end 

wird umgewandelt in:

SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong 

Das Problem ist, dass MySQL alle Zeilen mit „range_begin <=$iplong“ abruft und dann scannen muss, wenn „range_end>=$iplong“ ist. Diese erste UND-Bedingung (range_begin <=$iplong) hat ungefähr 2 Millionen Zeilen abgerufen, und alle müssen überprüft werden, ob range_end übereinstimmt.

Dies kann jedoch drastisch vereinfacht werden, indem eine UND-Bedingung hinzugefügt wird:

SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong 

Die Aussage

range_begin <= $iplong AND range_begin >= $iplong-65535

ruft nur Einträge ab, bei denen range_begin zwischen $iplong-65535 und $iplong liegt. In meinem Fall reduzierte dies die Anzahl der abgerufenen Zeilen von 4 Mio. auf etwa 5 und die Laufzeit des Skripts ging von mehreren Minuten auf wenige Sekunden zurück.

Hinweis zu 65535 :Dies ist für meine Tabelle der maximale Abstand zwischen range_begin und range_end, dh (range_end-range_begin) <=65535 für alle meine Zeilen. Wenn Sie größere IP-Bereiche haben, müssen Sie die 65535 erhöhen, wenn Sie kleinere IP-Bereiche haben, können Sie diese Konstante verringern. Wenn diese Konstante zu groß ist (z. B. 4 Milliarden), sparen Sie keine Abfragezeit.

Für diese Abfrage brauchen Sie nur einen Index auf range_begin.