Tipe data MySQL untuk bilangan bulat 128 bit

12

Saya perlu menyimpan 128 bit integer tanpa tanda ke MySQL dan saya bertanya-tanya apa tipe data terbaik untuk menyimpan angka sebesar itu.

Saat ini, saya menggunakan binary(16)tetapi itu melibatkan banyak fungsi konversi pack(/huge number in hex .../).

Apakah ada tipe data terbaik untuk menyimpan integer unsigned 128 bit?

Kami
sumber
4
Saya tidak bisa membantu tetapi memperhatikan bahwa ini adalah pertanyaan kedua di mana sepertinya Anda harus melakukan hal-hal aneh dengan solusi Anda agar dapat menggunakan MySql. Sudahkah Anda mempertimbangkan platform DB yang lebih kuat?
Russell Steen
Saya akan cenderung melihat bagaimana FORTRAN dan bahasa lain mendukung bilangan bulat 64bit ketika kami masih berurusan dengan sistem 8 & 16 bit.
Joe
@Russel Steen, apa yang akan Anda rekomendasikan sebagai platform DB yang lebih kuat?
Kami
Anda masih perlu mengepak dan membukanya, tetapi Postgres memiliki tipe 128-bit asli .
Gayus
Sebenarnya tipe bigserial Postgres harus melakukannya.
Gayus

Jawaban:

10

Saya tidak tahu apa cara terbaik untuk menyimpannya - tetapi setidaknya ada opsi yang lebih baik daripada menggunakan varchar(39)(atau varchar(40)jika Anda membutuhkannya ditandatangani); alih-alih gunakan a decimal(39,0). Dari dokumen mysql :

Tipe Fixed-Point (Exact-Value)

Jenis DECIMAL dan NUMERIC menyimpan nilai data numerik yang tepat. Jenis-jenis ini digunakan ketika penting untuk menjaga presisi yang tepat, misalnya dengan data moneter. Di MySQL, NUMERIC diimplementasikan sebagai DECIMAL, jadi pernyataan berikut tentang DECIMAL berlaku sama untuk NUMERIC.

MySQL 5.1 menyimpan nilai DECIMAL dalam format biner. Sebelum MySQL 5.0.3, mereka disimpan sebagai string. Lihat Bagian 11.18, “Matematika Presisi”.

Dalam deklarasi kolom DECIMAL, presisi dan skala dapat (dan biasanya) ditentukan; sebagai contoh:

salary DECIMAL(5,2)

Dalam contoh ini, 5 adalah presisi dan 2 adalah skala. Presisi mewakili jumlah digit signifikan yang disimpan untuk nilai, dan skala mewakili jumlah digit yang dapat disimpan mengikuti titik desimal.

SQL standar mengharuskan DECIMAL (5,2) dapat menyimpan nilai apa pun dengan lima digit dan dua desimal, sehingga nilai yang dapat disimpan dalam kisaran kolom gaji dari -999,99 hingga 999,99.

Dalam SQL standar, sintaks DECIMAL (M) setara dengan DECIMAL (M, 0). Demikian pula, sintaks DECIMAL setara dengan DECIMAL (M, 0), di mana implementasi diizinkan untuk menentukan nilai M. MySQL mendukung kedua bentuk sintaks DECIMAL ini. Nilai default M adalah 10.

Jika skalanya adalah 0, nilai DECIMAL tidak mengandung titik desimal atau bagian fraksional.

Jumlah digit maksimum untuk DECIMAL adalah 65, tetapi rentang aktual untuk kolom DECIMAL tertentu dapat dibatasi oleh presisi atau skala untuk kolom tertentu. Ketika kolom tersebut diberi nilai dengan lebih banyak digit mengikuti titik desimal daripada yang diizinkan oleh skala yang ditentukan, nilai tersebut dikonversi ke skala itu. (Perilaku yang tepat adalah sistem operasi khusus, tetapi umumnya efeknya terpotong ke jumlah digit yang diizinkan.)

Itu disimpan dikemas, sehingga akan memakan ruang lebih sedikit daripada varchar ( 18 byte, jika saya melakukan matematika saya dengan benar ), dan saya berharap Anda bisa melakukan matematika secara langsung, tapi saya sudah tidak pernah mencoba dengan angka sebesar itu untuk melihat apa yang terjadi.

Joe
sumber
8

Saya menemukan diri saya mengajukan pertanyaan ini dan dari semua posting yang saya baca tidak pernah menemukan perbandingan kinerja. Jadi, inilah usaha saya.

Saya telah membuat tabel berikut, diisi dengan 2.000.000 alamat ip acak dari 100 jaringan acak.

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
);

Lalu saya PILIH semua alamat ip untuk setiap jaringan dan catat waktu respons. Waktu respons rata-rata pada tabel twobigints adalah sekitar 1 detik, sedangkan pada tabel biner sekitar seperseratus detik.

Ini pertanyaannya.

catatan:

X_ [TINGGI / RENDAH] adalah 64-bit paling signifikan dari X

ketika NETMASK_LOW adalah 0 kondisi AND dihilangkan karena selalu menghasilkan true. tidak terlalu memengaruhi kinerja.

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

Waktu respons rata-rata:

Waktu respons rata-rata

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

Saya percaya satu-satunya pilihan lain adalah menyimpannya di varchar(39)lapangan.

BenV
sumber
2
Saya pikir ini akan berhasil jika Anda hanya ingin menyimpan data.
eiefai
1
@eiefai: Bukankah itu yang dia minta? "Saya harus menyimpan 128 bit bilangan bulat tanpa tanda tangan"
BenV
Oh ya, ini saran yang bagus, saya hanya berkomentar untuk memastikan bahwa dia hanya ingin menyimpan daripada melakukan beberapa kalori.
eiefai
@eiefai: ah ok, saya salah paham. Anda benar sekali, nilainya harus dilemparkan sebelum dapat dianggap sebagai angka.
BenV