Je faisais face à un problème similaire, où je devais rechercher une base de données avec environ 4 millions de plages d'adresses IP et trouver une solution intéressante qui faisait passer le nombre de lignes analysées de 4 millions à environ ~ 5 (selon l'adresse IP) :
Cette instruction SQL :
SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end
est transformé en :
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_end >= $iplong
Le problème est que MySQL récupère toutes les lignes avec 'range_begin <=$iplong' et doit ensuite analyser si 'range_end>=$iplong'. Cette première condition AND (range_begin <=$iplong) a récupéré environ 2 millions de lignes, et toutes doivent être vérifiées si range_end correspond.
Cela peut cependant être considérablement simplifié en ajoutant une condition ET :
SELECT id FROM geoip WHERE range_begin <= $iplong AND range_begin >= $iplong-65535 AND range_end >= $iplong
La déclaration
range_begin <= $iplong AND range_begin >= $iplong-65535
récupère uniquement les entrées où le range_begin est compris entre $iplong-65535 et $iplong. Dans mon cas, cela a réduit le nombre de lignes récupérées de 4 millions. à environ 5 et la durée d'exécution du script est passée de plusieurs minutes à quelques secondes.
Remarque sur 65535 :Ceci est pour ma table la distance maximale entre range_begin et range_end, c'est-à-dire (range_end-range_begin) <=65535 pour toutes mes lignes. Si vous avez des plages IP plus grandes, vous devez augmenter le 65535, si vous avez des plages IP plus petites, vous pouvez diminuer cette constante. Si cette constante est trop grande (par exemple 4 milliards), vous ne gagnerez pas de temps de requête.
Pour cette requête, vous n'avez besoin que d'un index sur range_begin.