sql >> データベース >  >> RDS >> Mysql

整数として保存されている部分的なIPアドレスを検索します

    実際、符号なし整数列は、部分的なIPアドレスで一致するものを検索するための最も効率的な方法です。ドット付き表記に戻したり、ある種の文字列列でLIKE検索を行ったりするときに、エネルギーやCPU時間を無駄にしないでください。

    部分的なIPアドレスを書き留める方法はいくつかありますが、最終的には、すべてネットマスクを使用してベースIPになります。また、部分的に、共通のプレフィックスを持つすべてのIPを意味すると仮定すると、これはIPの範囲を指定することにも相当します。

    いずれにせよ、部分的なIPアドレスの指定は、データベース列と同じ形式でエンコードされた2つの32ビットの符号なし整数として記述されることになります。開始IPと終了IPがあるか、ベースIPとマスクがあります。これらの整数をSQLクエリ内で直接使用して、一致を効率的に取得できます。さらに良いことに、IP範囲アプローチを使用すると、エンジンはIP列の順序付きインデックスを利用できるようになります。これ以上期待することはできません。

    では、IP範囲を構築する方法は?そもそも部分アドレスがどのように指定されたかによって異なりますが、ネットマスクを知っていると仮定すると、開始アドレスは(base ip&net mask)に等しく、終了アドレスは((base ip &ネットマスク)|(〜netmask))、ここで&、|および〜は、それぞれビット単位-および、ビット単位-またはビット単位-ではないことを意味します。

    更新

    これが私が説明した戦略を適用するためのサンプルコードです。

    さて、最後にPHPコードを書いてから久しぶりですが、以下は実行されていないので、エラーが発生した場合はご容赦ください。また、すべての表記シナリオを1つの非常に複雑な正規表現にまとめるのではなく、理解しやすくするために、各表記シナリオを意図的に「拡張」することを選択しました。

    if (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [/] (\d{1,2}) $/x', $input, $r)) {
        // Four-dotted IP with number of significant bits: 123.45.67.89/24
    
        $a = intval($r[1]);
        $b = intval($r[2]);
        $c = intval($r[3]);
        $d = intval($r[4]);
        $mask = intval($r[5]);
    
    } elseif (preg_match(' /^ (\d{1,3}) (?: [.] [*0] [.] [*0] [.] [*0] )? $/x', $input, $r)) {
        // Four-dotted IP with three-last numbers missing, or equals to 0 or '*':
        // 123.45, 123.45.0.0, 123.45.*.*  (assume netmask of 8 bits)
    
        $a = intval($r[1]);
        $b = 0;
        $c = 0;
        $d = 0;
        $mask = 8;
    
    } elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] [.] [*0] )? $/x', $input, $r)) {
        // Four-dotted IP with two-last numbers missing, or equals to 0 or '*':
        // 123.45, 123.45.0.0, 123.45.*.*  (assume netmask of 16 bits)
    
        $a = intval($r[1]);
        $b = intval($r[2]);
        $c = 0;
        $d = 0;
        $mask = 16;
    
    } elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] )? $/x', $input, $r)) {
        // Four-dotted IP with last number missing, or equals to 0 or *:
        // 123.45.67, 123.45.67.0, 123.45.67.*  (assume netmask of 24 bits)
    
        $a = intval($r[1]);
        $b = intval($r[2]);
        $c = intval($r[3]);
        $d = 0;
        $mask = 24;
    
    } elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) $/x', $input, $r)) {
        // Four-dotted IP: 123.45.67.89 (assume netmask of 32 bits)
    
        $a = intval($r[1]);
        $b = intval($r[2]);
        $c = intval($r[3]);
        $d = intval($r[4]);
        $mask = 32;
    
    } else {
        throw new Exception('...');
    }
    
    if ($a < 0 || $a > 255) {  throw new Exception('...') };
    if ($b < 0 || $b > 255) {  throw new Exception('...') };
    if ($c < 0 || $c > 255) {  throw new Exception('...') };
    if ($d < 0 || $d > 255) {  throw new Exception('...') };
    if ($mask < 1 || $mask > 32) {  throw new Exception('...') };
    
    $baseip = ($a << 24) + ($b << 16) + ($c << 8) + ($d);
    $netmask = (1 << (32 - $mask)) - 1;
    
    $startip = $baseip & netmask;
    $endip = ($baseip & netmask) | (~netmask);
    
    // ...
    
    doSql( "SELECT ... FROM ... WHERE ipaddress >= ? && ipaddress <= ?", $startip, $endip);
    
    // or
    
    doSql( "SELECT ... FROM ... WHERE ((ipaddress & ?) = ?)", $netmask, $startip);
    


    1. PHP/MySQLを使用したメッセージングシステム

    2. SQLは、別のテーブルの別の列から1つの列を更新します

    3. cc1:エラー:認識されないコマンドラインオプション-Wno-null-Mac10.7.5にpython-mysqlをインストールする際の変換

    4. MySQLでデータベース内のすべてのテーブルのサイズを確認する方法