web-dev-qa-db-ja.com

MySQLの単一の列に128ビットの数値を格納する方法は?

IPアドレスを文字列ではなく数値として格納するようにいくつかのテーブルを変更しています。これは、32ビットアドレスが整数列に収まるIPv4では簡単です。ただし、IPv6アドレスは128ビットです。

MySQLドキュメント は64ビットまでの数値タイプ( "bigint")のみを表示します。

IPv6ではchar/varcharを使用する必要がありますか? (理想的には、IPv4とIPv6に同じ列を使用したいので、これは使用したくない)。

2つのbigint列を使用するよりも良いものはありますか?アドレスを使用するときはいつでも、値を上下の/ 64に分割する必要はありません。

私はMariaDB5.1を使用しています-MySQLの新しいバージョンにもっと良い解決策があるなら、それは知っておくといいでしょうが、すぐには役に立ちません。

[編集]これを行うための最良の方法の推奨を求めていることに注意してください-それはこれを行うにはさまざまな方法(既存の文字列表現を含む)があることは明らかですが、(パフォーマンスの観点から)どちらが最適ですか? (つまり、誰かがすでに分析を行っている場合は、それを行う手間が省けます。または、明らかな何かが欠けている場合は、それも知っておくと便利です)。

36
Tony Meyer

私は自分自身がこの質問をしていることに気づき、私が読んだすべての投稿から、パフォーマンスの比較は見つかりませんでした。だからここに私の試みがあります。

次のテーブルを作成し、100個のランダムネットワークからの2,000,000個のランダムIPアドレスを入力しました。

CREATE TABLE ipv6_address_binary (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr BINARY(16) NOT NULL UNIQUE
);

CREATE TABLE ipv6_address_twobigints (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    haddr BIGINT UNSIGNED NOT NULL,
    laddr BIGINT UNSIGNED NOT NULL,
    UNIQUE uidx (haddr, laddr)
);

CREATE TABLE ipv6_address_decimal (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr DECIMAL(39,0) NOT NULL UNIQUE
);

次に、各ネットワークのすべてのIPアドレスを選択し、応答時間を記録します。 twobigintsテーブルの平均応答時間は約1秒ですが、バイナリテーブルの平均応答時間は約100分の1秒です。

これがクエリです。

注意:

X_ [HIGH/LOW]は、Xの最上位/最下位の64ビットです。

nETMASK_LOWが0の場合、AND条件は常にtrueになるため、省略されます。パフォーマンスにはあまり影響しません。

SELECT COUNT(*) FROM ipv6_address_twobigints
WHERE haddr & NETMASK_HIGH = NETWORK_HIGH
AND laddr & NETMASK_LOW = NETWORK_LOW

SELECT COUNT(*) FROM ipv6_address_binary
WHERE addr >= NETWORK
AND addr <= BROADCAST

SELECT COUNT(*) FROM ipv6_address_decimal
WHERE addr >= NETWORK
AND addr <= BROADCAST

平均応答時間:

グラフ:

http://i.stack.imgur.com/5NJvQ.jpg

BINARY_InnoDB  0.0119529819489
BINARY_MyISAM  0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB  0.782350552082
BIGINT_MyISAM  1.07809265852
45
Jake

私は常に文字列または2つの64ビット整数を使用してきました。前者は単に記録したい場合、後者は特定のアドレスが特定のネットワークに含まれているかどうか、あるいは2つのネットワークが重複しているかどうかを計算する必要がある場合です。

整数として格納する場合、唯一のオプションは、実際には2つの64ビット数値に分割することです。これは比較をより面倒にするので、IPが特定のネットワーク内にあるかどうかを確認するために数値計算が必要でない限り、これは行いません。

データに対して行うルックアップの数に応じて、IPv6アドレスを文字列に格納するためのパフォーマンスについてはあまり心配しません。通常、データはごくわずかであるか、ごくわずかです。はい、保存と検索は数字よりも効率的ではありませんが、電子メールアドレス、個人名、またはユーザー名を保存するよりもそれほど苦痛ではありません。

そして、なぜ文字列フィールドでIPv4とIPv6を混在させることができないのでしょうか。それらは1つを取得するときに簡単に区別できます。それらの可能な値の範囲は重複しません。

つまり、重複をチェックするために数字を使用し、他の場所で文字列を使用します。文字列の非効率性は、使いやすさに比べれば関係ありません。

4
user188041

引用:「バイナリ(64)を検討しましたか?」

MySQLに非常に大きな整数を格納する

1
Bnjmn