Mysql
 sql >> база данни >  >> RDS >> Mysql

GeoIP таблица се присъединява към таблица с IP адреси в MySQL

Този подход има някои проблеми с мащабируемостта (ако решите да преминете, да речем, към специфични за града геоип данни), но за дадения размер на данните той ще осигури значителна оптимизация.

Проблемът, с който се сблъсквате, всъщност е, че MySQL не оптимизира много добре базираните на диапазона заявки. В идеалния случай искате да направите точно ("=") търсене на индекс, а не "по-голямо от", така че ще трябва да изградим индекс като този от наличните данни. По този начин MySQL ще има много по-малко редове за оценка, докато търси съвпадение.

За да направите това, предлагам да създадете таблица за търсене, която индексира таблицата за геолокация въз основа на първия октет (=1 от 1.2.3.4) от IP адресите. Идеята е, че за всяко търсене, което трябва да направите, можете да игнорирате всички IP адреси за геолокация, които не започват със същия октет от IP, който търсите.

CREATE TABLE `ip_geolocation_lookup` (
  `first_octet` int(10) unsigned NOT NULL DEFAULT '0',
  `ip_numeric_start` int(10) unsigned NOT NULL DEFAULT '0',
  `ip_numeric_end` int(10) unsigned NOT NULL DEFAULT '0',
  KEY `first_octet` (`first_octet`,`ip_numeric_start`,`ip_numeric_end`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

След това трябва да вземем наличните данни във вашата таблица за геолокация и да създадем данни, които обхващат всички (първи) октети на реда за геолокация покрива:Ако имате запис с ip_start = '5.3.0.0' и ip_end = '8.16.0.0' , таблицата за търсене ще се нуждае от редове за октети 5, 6, 7 и 8. Така че...

ip_geolocation
|ip_start       |ip_end          |ip_numeric_start|ip_numeric_end|
|72.255.119.248 |74.3.127.255    |1224701944      |1241743359    |

Трябва да се преобразува в:

ip_geolocation_lookup
|first_octet|ip_numeric_start|ip_numeric_end|
|72         |1224701944      |1241743359    |
|73         |1224701944      |1241743359    |
|74         |1224701944      |1241743359    |

Тъй като някой тук е поискал собствено MySQL решение, ето съхранена процедура, която ще генерира тези данни за вас:

DROP PROCEDURE IF EXISTS recalculate_ip_geolocation_lookup;

CREATE PROCEDURE recalculate_ip_geolocation_lookup()
BEGIN
    DECLARE i INT DEFAULT 0;

    DELETE FROM ip_geolocation_lookup;

    WHILE i < 256 DO
       INSERT INTO ip_geolocation_lookup (first_octet, ip_numeric_start, ip_numeric_end) 
                SELECT  i, ip_numeric_start, ip_numeric_end FROM ip_geolocation WHERE 
                ( ip_numeric_start & 0xFF000000 ) >> 24 <= i AND 
                ( ip_numeric_end & 0xFF000000 ) >> 24 >= i;

       SET i = i + 1;
    END WHILE;
END;

И тогава ще трябва да попълните таблицата, като извикате тази съхранена процедура:

CALL recalculate_ip_geolocation_lookup();

В този момент можете да изтриете процедурата, която току-що създадохте – тя вече не е необходима, освен ако не искате да преизчислите таблицата за справка.

След като таблицата за търсене е на мястото си, всичко, което трябва да направите, е да я интегрирате във вашите заявки и да се уверите, че правите заявка до първия октет. Вашата заявка към таблицата за търсене ще удовлетвори две условия:

  1. Намерете всички редове, които съответстват на първия октет от вашия IP адрес
  2. От това подмножество :Намерете реда, който съдържа диапазона, който съответства на вашия IP адрес

Тъй като стъпка 2 се извършва върху подмножество от данни, тя е значително по-бърза от извършването на тестове на обхвата на всички данни. Това е ключът към тази стратегия за оптимизиране.

Има различни начини да разберете какъв е първият октет на IP адрес; Използвах ( r.ip_numeric & 0xFF000000 ) >> 24 тъй като моите изходни IP адреси са в числова форма:

SELECT 
    r.*, 
    g.country_code
FROM 
    ip_geolocation g,
    ip_geolocation_lookup l,
    ip_random r
WHERE 
    l.first_octet = ( r.ip_numeric & 0xFF000000 ) >> 24 AND 
    l.ip_numeric_start <= r.ip_numeric AND      
    l.ip_numeric_end >= r.ip_numeric AND 
    g.ip_numeric_start = l.ip_numeric_start;

Сега, да си призная, накрая станах малко мързелив:лесно бихте могли да се отървете от ip_geolocation таблицата като цяло, ако сте направили ip_geolocation_lookup таблицата съдържа и данните за страната. Предполагам, че премахването на една таблица от тази заявка ще я направи малко по-бърза.

И накрая, ето другите две таблици, които използвах в този отговор за справка, тъй като те се различават от вашите таблици. Сигурен съм обаче, че са съвместими.

# This table contains the original geolocation data

CREATE TABLE `ip_geolocation` (
  `ip_start` varchar(16) NOT NULL DEFAULT '',
  `ip_end` varchar(16) NOT NULL DEFAULT '',
  `ip_numeric_start` int(10) unsigned NOT NULL DEFAULT '0',
  `ip_numeric_end` int(10) unsigned NOT NULL DEFAULT '0',
  `country_code` varchar(3) NOT NULL DEFAULT '',
  `country_name` varchar(64) NOT NULL DEFAULT '',
  PRIMARY KEY (`ip_numeric_start`),
  KEY `country_code` (`country_code`),
  KEY `ip_start` (`ip_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


# This table simply holds random IP data that can be used for testing

CREATE TABLE `ip_random` (
  `ip` varchar(16) NOT NULL DEFAULT '',
  `ip_numeric` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да добавя нова колона към таблицата на MYSQL?

  2. Премахване на връщане на карета в Mysql DB

  3. MySQL какъв е максималният размер на база данни?

  4. php mysql пълнотекстово търсене:lucene, sphinx или?

  5. MySQL конвертира между два формата на дата