ネットワークの列から、ネットマスク内のビット数を確認できます。少しのビット単位の計算によって、ユーザーのIPがそのネットワーク内にあるかどうかを簡単に検出できます。したがって、私はあなたがその(2進)ネットワークIPとそのcidr番号にその列を分割することをお勧めします。
私を説明しましょう。あなたが提供した最初の例(10.0.32.0/19)を見れば、ネットマスク( "/ 19"ビット)はバイナリで19個のビットとして表現され、他のすべてのビットはゼロに設定されていることがわかります:
11111111 11111111 11100000 00000000
のは、1.0.32.56のサンプルユーザーのIPを見てみましょう:
00000001 00000000 00100000 00111000
あなたはその/ 19ネットマスクのユーザーIPと一緒にビット単位を取っている場合、あなたがになってしまいますことを見ることができます。
00000001 00000000 00100000 00000000
... dotted quaに変換するdsを1.0.32.0とする。見覚えがあります?
とにかく、あなたの問題に取り組んでいます。まず、udfを使ってIPアドレスをバイナリに変換する必要があります。私は臆面もなくthis answerから1を盗んだ:
CREATE FUNCTION dbo.fnBinaryIPv4(@ip AS VARCHAR(15)) RETURNS BINARY(4)
AS
BEGIN
DECLARE @bin AS BINARY(4)
SELECT @bin = CAST(CAST(PARSENAME(@ip, 4) AS INTEGER) AS BINARY(1))
+ CAST(CAST(PARSENAME(@ip, 3) AS INTEGER) AS BINARY(1))
+ CAST(CAST(PARSENAME(@ip, 2) AS INTEGER) AS BINARY(1))
+ CAST(CAST(PARSENAME(@ip, 1) AS INTEGER) AS BINARY(1))
RETURN @bin
END
GO
私も小さなルックアップテーブルにネットマスクのすべてを持っている、それは参考:
CREATE TABLE netmask (
bits TINYINT PRIMARY KEY,
binary_mask BINARY(4) NOT NULL
)
INSERT INTO netmask (bits, binary_mask) VALUES
(0, 0x00000000), (1, 0x80000000), (2, 0xc0000000), (3, 0xe0000000),
(4, 0xf0000000), (5, 0xf8000000), (6, 0xfc000000), (7, 0xfe000000),
(8, 0xff000000), (9, 0xff800000), (10, 0xffc00000), (11, 0xffe00000),
(12, 0xfff00000), (13, 0xfff80000), (14, 0xfffc0000), (15, 0xfffe0000),
(16, 0xffff0000), (17, 0xffff8000), (18, 0xffffc000), (19, 0xffffe000),
(20, 0xfffff000), (21, 0xfffff800), (22, 0xfffffc00), (23, 0xfffffc00),
(24, 0xffffff00), (25, 0xffffff80), (26, 0xffffffc0), (27, 0xffffffe0),
(28, 0xfffffff0), (29, 0xfffffff8), (30, 0xfffffffc), (31, 0xfffffffe),
(32, 0xffffffff)
次の我々は我々の2つの新しい列を作成し、移入しますそれら:
ALTER TABLE GeoIP
ADD binary_network BINARY(4), network_bits TINYINT
GO
UPDATE GeoIP
SET binary_network = dbo.fnBinaryIPv4(SUBSTRING(network, 0, PATINDEX('%/%', network))),
network_bits = CAST(SUBSTRING(network, PATINDEX('%/%', network) + 1, 3) AS TINYINT)
だから今、私たちのようにクエリを書き直すことができます。
DECLARE @binary_user_ip BIGINT
SELECT @binary_user_ip = dbo.fnBinaryIPv4(@user_ip)
SELECT geoname_id
FROM GeoIP g
JOIN netmask n ON g.network_bits = n.bits
WHERE @binary_user_ip & n.binary_mask = g.binary_network
注 - これはIPv4でのみ機能します。 IPv6サブネットを検出したい場合、一般的なアプローチは同じですが、文字列の変換と算術はもっと複雑になります。
これは素晴らしい動作します。この行が何をしているのか説明できますか? (ここで@binary_user_ip&n.binary_mask = g.binary_network)。 –
また、binary_networkをプライマリ検索列として使用している場合は、その列のインデックスを作成する必要がありますか? –
その行はビット単位のANDです。私が前に示したバイナリの例と同じことです。そして、ええ、もしbinary_networkがあなたの主な検索カラムであれば、それはほぼ確実に索引付けするべきです。 – duckbenny