Tipo di dati MySQL per numeri interi a 128 bit


12

Devo memorizzare numeri interi senza segno a 128 bit in MySQL e mi chiedevo quale sia il miglior tipo di dati per memorizzare numeri così grandi.

In questo momento, sto usando binary(16)ma ciò comporta molte funzioni di conversione pack(/huge number in hex .../).

Esiste un tipo di dati migliore per memorizzare un numero intero senza segno a 128 bit?


4
Non posso fare a meno di notare che questa è la seconda domanda in cui sembra che tu debba fare cose strane con la tua soluzione per poter usare MySql. Hai considerato una piattaforma DB più solida?
Russell Steen,

Sarei propenso a vedere come FORTRAN e altre lingue supportano numeri interi a 64 bit quando avevamo ancora a che fare con sistemi a 8 e 16 bit.
Joe,

@Russel Steen, cosa consiglieresti come piattaforma DB più solida?
Kami,

Dovresti comunque comprimerlo e decomprimerlo ma Postgres ha un tipo nativo a 128 bit .
Gaius,

In realtà il tipo bigserial di Postgres dovrebbe farlo.
Gaius,

Risposte:


10

Non so quale sia il modo migliore per archiviarlo, ma c'è almeno un'opzione migliore rispetto all'utilizzo di un varchar(39)(o varchar(40)se ne avevi bisogno firmato); invece usa a decimal(39,0). Dai documenti mysql :

Tipi a virgola fissa (valore esatto)

I tipi DECIMAL e NUMERIC memorizzano valori esatti di dati numerici. Questi tipi vengono utilizzati quando è importante preservare la precisione esatta, ad esempio con i dati monetari. In MySQL, NUMERIC è implementato come DECIMAL, quindi le seguenti osservazioni su DECIMAL si applicano ugualmente a NUMERIC.

MySQL 5.1 memorizza i valori DECIMAL in formato binario. Prima di MySQL 5.0.3, erano archiviati come stringhe. Vedere la Sezione 11.18, "Precisione matematica".

In una dichiarazione di colonna DECIMAL, la precisione e la scala possono essere (e solitamente sono) specificate; per esempio:

salary DECIMAL(5,2)

In questo esempio, 5 è la precisione e 2 è la scala. La precisione rappresenta il numero di cifre significative memorizzate per i valori e la scala rappresenta il numero di cifre che è possibile memorizzare dopo il punto decimale.

SQL standard richiede che DECIMAL (5,2) sia in grado di memorizzare qualsiasi valore con cinque cifre e due decimali, quindi i valori che possono essere memorizzati nella colonna di stipendio vanno da -999,99 a 999,99.

In SQL standard, la sintassi DECIMAL (M) è equivalente a DECIMAL (M, 0). Allo stesso modo, la sintassi DECIMAL è equivalente a DECIMAL (M, 0), dove l'implementazione è autorizzata a decidere il valore di M. MySQL supporta entrambe queste forme varianti di sintassi DECIMAL. Il valore predefinito di M è 10.

Se la scala è 0, i valori DECIMAL non contengono punti decimali o parti frazionarie.

Il numero massimo di cifre per DECIMAL è 65, ma l'intervallo effettivo per una determinata colonna DECIMAL può essere limitato dalla precisione o dalla scala per una determinata colonna. Quando a tale colonna viene assegnato un valore con più cifre che seguono il punto decimale di quello consentito dalla scala specificata, il valore viene convertito in quella scala. (Il comportamento preciso è specifico del sistema operativo, ma generalmente l'effetto è il troncamento al numero consentito di cifre.)

È immagazzinato imballato, quindi occuperà meno spazio del varchar ( 18 byte, se sto facendo la mia matematica nel modo giusto ), e spero che tu possa fare la matematica direttamente su di esso, ma ho mai provato con un numero così grande per vedere cosa succede.


8

Mi sono ritrovato a porre questa domanda e da tutti i post che ho letto non ho mai trovato confronti di prestazioni. Quindi ecco il mio tentativo.

Ho creato le seguenti tabelle, popolate con 2.000.000 di indirizzi IP casuali da 100 reti casuali.

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

Quindi seleziono tutti gli indirizzi IP per ciascuna rete e registro il tempo di risposta. Il tempo medio di risposta sulla tabella twobigints è di circa 1 secondo, mentre sulla tabella binaria è di circa un centesimo di secondo.

Ecco le domande.

Nota:

X_ [HIGH / LOW] è il 64 bit più / meno significativo di X

quando NETMASK_LOW è 0, la condizione AND viene omessa poiché restituisce sempre true. non influisce molto sulle prestazioni.

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

Tempi medi di risposta:

Tempi medi di risposta

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

2

Credo che l'unica altra opzione sia quella di memorizzarla in un varchar(39)campo.


2
Penso che funzionerebbe se si desidera archiviare solo i dati.
eiefai,

1
@eiefai: Non è quello che sta chiedendo? "Devo memorizzare numeri interi senza segno a 128 bit"
BenV,

Oh sì, questo è un buon consiglio, ho appena commentato per assicurarmi che volesse solo archiviare piuttosto che fare dei calcoli.
eiefai,

@eiefai: ah ok, ho capito male. Hai assolutamente ragione, il valore dovrebbe essere lanciato prima che possa essere trattato come un numero.
BenV,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.