sql >> Database teknologi >  >> RDS >> Mysql

MySQL:Hvordan laver man en hurtigere IP-områdeforespørgsel? GeoIP

Jeg havde at gøre med et lignende problem, hvor jeg skulle søge i en database med omkring 4 millioner IP-intervaller og fandt en fin løsning, der bragte antallet af scannede rækker ned fra 4 millioner til omkring ~5 (afhængigt af IP):

Denne SQL-sætning:

SELECT id FROM geoip WHERE $iplong BETWEEN range_begin AND range_end 

er omdannet til:

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

Problemet er, at MySQL henter alle rækker med 'range_begin <=$iplong' og derefter skal scannes, hvis 'range_end>=$iplong'. Denne første AND betingelse (range_begin <=$iplong) hentede omkring 2 millioner rækker, og alle skal kontrolleres, hvis range_end matcher.

Dette kan dog forenkles dramatisk ved at tilføje en OG-betingelse:

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

Udtalelsen

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

henter kun poster, hvor range_begin er mellem $iplong-65535 og $iplong. I mit tilfælde reducerede dette antallet af hentede rækker fra 4 mio. til omkring 5, og scriptets køretid gik ned fra flere minutter til et par sekunder.

Bemærk om 65535 :Dette er for min tabel den maksimale afstand mellem range_begin og range_end, dvs. (range_end-range_begin) <=65535 for alle mine rækker. Hvis du har større IP-områder, skal du øge 65535, hvis du har mindre IP-områder, kan du reducere denne konstant. Hvis denne konstant er for stor (for eksempel 4 milliarder), sparer du ingen forespørgselstid.

Til denne forespørgsel behøver du kun et indeks på range_begin.



  1. Indsæt i en MySQL-tabel eller opdater, hvis den findes

  2. Sådan installeres Libreoffice på Ubuntu 16.04

  3. InnoDB eller MyISAM - Hvorfor ikke begge dele?

  4. MySql:Vis kolonner, men ekskluder alt undtagen feltnavnene