私はMySQLに128ビットの符号なし整数を格納する必要があり、そのような大きな数値を格納するのに最適なデータ型は何なのかと思っていました。
現在、私はbinary(16)
を使用していますが、これには多くの変換関数pack(/huge number in hex .../)
が含まれます。
128ビットの符号なし整数を格納するのに最適なデータ型はありますか?
それを保存するための最善の方法が何であるかはわかりません-少なくとも、varchar(39)
(または、署名が必要な場合はvarchar(40)
)を使用するよりも優れたオプションがあります。代わりにdecimal(39,0)
を使用してください。 mysqlドキュメントから :
固定小数点(正確な値)のタイプ
DECIMALおよびNUMERICタイプは、正確な数値データ値を格納します。これらのタイプは、正確な精度を維持することが重要な場合(通貨データなど)に使用されます。 MySQLでは、NUMERICはDECIMALとして実装されているため、以下のDECIMALに関する注記はNUMERICにも同様に適用されます。
MySQL 5.1はDECIMAL値をバイナリ形式で格納します。 MySQL 5.0.3より前は、それらは文字列として格納されていました。セクション11.18「精度の計算」を参照してください。
DECIMAL列宣言では、精度と位取りを指定できます(通常は指定します)。例えば:
salary DECIMAL(5,2)
この例では、5が精度で、2がスケールです。精度は値に格納される有効桁数を表し、スケールは小数点に続いて格納できる桁数を表します。
標準SQLでは、DECIMAL(5,2)が5桁と10進数の2桁の任意の値を格納できる必要があるため、給与の列に格納できる値は-999.99〜999.99です。
標準SQLでは、構文DECIMAL(M)はDECIMAL(M、0)と同等です。同様に、構文DECIMALはDECIMAL(M、0)と同等であり、実装はMの値を決定することが許可されます。MySQLは、DECIMAL構文のこれらのバリアント形式の両方をサポートします。 Mのデフォルト値は10です。
スケールが0の場合、DECIMAL値には小数点も小数部も含まれません。
DECIMALの最大桁数は65ですが、特定のDECIMAL列の実際の範囲は、特定の列の精度または位取りによって制約を受ける場合があります。このような列に、小数点以下の桁数が指定されたスケールで許可されているよりも多い値が割り当てられている場合、値はそのスケールに変換されます。 (正確な動作はオペレーティングシステムに固有ですが、通常、影響は許容桁数に切り捨てられます。)
パックされて格納されるため、varchar( 計算を正しく実行している場合は18バイト )よりスペースが少なくて済み、計算を実行できるようになると思いますそれは直接ですが、何が起こるかを確認するためにこれほど多くの数を試したことがありません。
私はこの質問をしているのに気づき、読んだすべての投稿から、パフォーマンスの比較は見つかりませんでした。これが私の試みです。
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
平均応答時間:
BINARY_InnoDB 0.0119529819489
BINARY_MyISAM 0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB 0.782350552082
BIGINT_MyISAM 1.07809265852
他の唯一のオプションは、それをvarchar(39)
フィールドに格納することです。