私は128ビットの符号なし整数をMySQLに保存する必要があり、そのような大きな数を保存するのに最適なデータ型は何だろうと思っていました。
現在、私は使用してbinary(16)
いますが、それは多くの変換関数を伴いますpack(/huge number in hex .../)
。
128ビットの符号なし整数を格納するのに最適なデータ型はありますか?
私は128ビットの符号なし整数をMySQLに保存する必要があり、そのような大きな数を保存するのに最適なデータ型は何だろうと思っていました。
現在、私は使用して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