Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Tabel GeoIP bergabung dengan tabel IP di MySQL

Pendekatan ini memiliki beberapa masalah skalabilitas (jika Anda memilih untuk pindah ke, katakanlah, data geoip khusus kota), tetapi untuk ukuran data tertentu, ini akan memberikan pengoptimalan yang cukup besar.

Masalah yang Anda hadapi secara efektif adalah MySQL tidak mengoptimalkan kueri berbasis rentang dengan sangat baik. Idealnya Anda ingin melakukan pencarian tepat ("=") pada indeks daripada "lebih besar dari", jadi kami perlu membuat indeks seperti itu dari data yang Anda miliki. Dengan cara ini MySQL akan memiliki lebih sedikit baris untuk dievaluasi saat mencari kecocokan.

Untuk melakukan ini, saya sarankan Anda membuat tabel pencarian yang mengindeks tabel geolokasi berdasarkan oktet pertama (=1 dari 1.2.3.4) alamat IP. Idenya adalah untuk setiap pencarian yang harus Anda lakukan, Anda dapat mengabaikan semua IP geolokasi yang tidak dimulai dengan oktet yang sama dengan IP yang Anda cari.

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;

Selanjutnya, kami perlu mengambil data yang tersedia di tabel geolokasi Anda dan menghasilkan data yang mencakup semua (pertama) oktet yang mencakup baris geolokasi:Jika Anda memiliki entri dengan ip_start = '5.3.0.0' dan ip_end = '8.16.0.0' , tabel pencarian akan membutuhkan baris untuk oktet 5, 6, 7, dan 8. Jadi...

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

Harus dikonversi ke:

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

Karena seseorang di sini meminta solusi MySQL asli, berikut adalah prosedur tersimpan yang akan menghasilkan data itu untuk Anda:

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;

Dan kemudian Anda perlu mengisi tabel dengan memanggil prosedur tersimpan itu:

CALL recalculate_ip_geolocation_lookup();

Pada titik ini Anda dapat menghapus prosedur yang baru saja Anda buat -- prosedur tersebut tidak lagi diperlukan, kecuali jika Anda ingin menghitung ulang tabel pencarian.

Setelah tabel pencarian ditempatkan, yang harus Anda lakukan adalah mengintegrasikannya ke dalam kueri Anda dan pastikan Anda membuat kueri berdasarkan oktet pertama. Permintaan Anda ke tabel pencarian akan memenuhi dua kondisi:

  1. Temukan semua baris yang cocok dengan oktet pertama alamat IP Anda
  2. Dari bagian itu :Temukan baris yang memiliki rentang yang cocok dengan alamat IP Anda

Karena langkah kedua dilakukan pada subset data, maka ini jauh lebih cepat daripada melakukan uji jangkauan pada seluruh data. Inilah kunci dari strategi pengoptimalan ini.

Ada berbagai cara untuk mencari tahu apa oktet pertama dari sebuah alamat IP; Saya menggunakan ( r.ip_numeric & 0xFF000000 ) >> 24 karena IP sumber saya dalam bentuk numerik:

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;

Sekarang, memang saya agak malas pada akhirnya:Anda dapat dengan mudah menyingkirkan ip_geolocation tabel sama sekali jika Anda membuat ip_geolocation_lookup tabel juga berisi data negara. Saya kira menghapus satu tabel dari kueri ini akan membuatnya sedikit lebih cepat.

Dan, akhirnya, inilah dua tabel lain yang saya gunakan dalam tanggapan ini untuk referensi, karena mereka berbeda dari tabel Anda. Saya yakin mereka kompatibel.

# 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. Bisakah sebuah tabel memiliki beberapa kunci utama?

  2. Bagaimana cara menghubungkan meja kerja mysql untuk menjalankan mysql di dalam buruh pelabuhan?

  3. Operand Harus Berisi 1 Kolom - MySQL TIDAK DI

  4. C# MySQL SSL Connection Error saat mencoba menggunakan conn.Open()

  5. Memformat larik PHP untuk klausa SQL IN