MySQL-Datentyp für 128-Bit-Ganzzahlen

12

Ich muss 128-Bit-Ganzzahlen ohne Vorzeichen in MySQL speichern und habe mich gefragt, welcher Datentyp am besten geeignet ist, um so große Zahlen zu speichern.

Im Moment benutze ich binary(16)aber das beinhaltet eine Menge Konvertierungsfunktionen pack(/huge number in hex .../).

Gibt es den besten Datentyp, um eine 128-Bit-Ganzzahl ohne Vorzeichen zu speichern?

Kami
quelle
4
Ich kann nicht anders, als zu bemerken, dass dies die zweite Frage ist, bei der Sie seltsame Dinge mit Ihrer Lösung tun müssen, um MySql verwenden zu können. Haben Sie eine robustere DB-Plattform in Betracht gezogen?
Russell Steen
Ich würde gerne sehen, wie FORTRAN und andere Sprachen 64-Bit-Ganzzahlen unterstützen, als wir noch mit 8- und 16-Bit-Systemen zu tun hatten.
Joe
@Russel Steen, was würden Sie als robustere DB-Plattform empfehlen?
Kami
Sie müssten es immer noch packen und entpacken, aber Postgres hat einen nativen 128-Bit-Typ .
Gaius
Eigentlich sollte es der Postgres- Bigserial-Typ tun.
Gaius

Antworten:

10

Ich weiß nicht, wie ich es am besten aufbewahren soll - aber es gibt zumindest eine bessere Option als die Verwendung von varchar(39)(oder varchar(40)wenn Sie es signieren mussten); Verwenden Sie stattdessen a decimal(39,0). Aus den MySQL-Dokumenten :

Festkommatypen (exakter Wert)

Die Typen DECIMAL und NUMERIC speichern genaue numerische Datenwerte. Diese Typen werden verwendet, wenn es wichtig ist, eine genaue Genauigkeit zu gewährleisten, beispielsweise bei Währungsdaten. In MySQL ist NUMERIC als DECIMAL implementiert, daher gelten die folgenden Bemerkungen zu DECIMAL gleichermaßen für NUMERIC.

MySQL 5.1 speichert DECIMAL-Werte im Binärformat. Vor MySQL 5.0.3 wurden sie als Zeichenfolgen gespeichert. Siehe auch Abschnitt 11.18, „Präzisionsmathematik“.

In einer DECIMAL-Spaltendeklaration können (und werden normalerweise) die Genauigkeit und der Maßstab angegeben. beispielsweise:

salary DECIMAL(5,2)

In diesem Beispiel ist 5 die Genauigkeit und 2 die Skala. Die Genauigkeit gibt die Anzahl der signifikanten Stellen an, die für Werte gespeichert werden, und die Skala gibt die Anzahl der Stellen an, die nach dem Dezimalpunkt gespeichert werden können.

Standard-SQL erfordert, dass DECIMAL (5,2) einen beliebigen Wert mit fünf Stellen und zwei Dezimalstellen speichern kann. Werte, die in der Gehaltsspalte gespeichert werden können, reichen von -999,99 bis 999,99.

In Standard-SQL entspricht die Syntax DECIMAL (M) DECIMAL (M, 0). In ähnlicher Weise entspricht die Syntax DECIMAL DECIMAL (M, 0), wobei die Implementierung den Wert von M bestimmen darf. MySQL unterstützt beide Varianten der DECIMAL-Syntax. Der Standardwert von M ist 10.

Wenn die Skala 0 ist, enthalten die DECIMAL-Werte keinen Dezimalpunkt oder Bruchteil.

Die maximale Anzahl von Stellen für DECIMAL beträgt 65. Der tatsächliche Bereich für eine bestimmte DECIMAL-Spalte kann jedoch durch die Genauigkeit oder Skalierung für eine bestimmte Spalte eingeschränkt werden. Wenn einer solchen Spalte ein Wert mit mehr Nachkommastellen zugewiesen wird, als die angegebene Skala zulässt, wird der Wert in diese Skala konvertiert. (Das genaue Verhalten ist betriebssystemspezifisch, im Allgemeinen wird es jedoch auf die zulässige Anzahl von Stellen gekürzt.)

Es ist gepackt gespeichert, nimmt also weniger Platz ein als das varchar ( 18 Bytes, wenn ich richtig rechne ), und ich hoffe, Sie können direkt damit rechnen , aber ich habe es getan Ich habe noch nie versucht, mit so einer großen Zahl zu sehen, was passiert.

Joe
quelle
8

Ich habe diese Frage gestellt und in all den Posts, die ich gelesen habe, nie Leistungsvergleiche gefunden. Also hier ist mein Versuch.

Ich habe die folgenden Tabellen erstellt, die mit 2.000.000 zufälligen IP-Adressen aus 100 zufälligen Netzwerken gefüllt sind.

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

Dann wähle ich alle IP-Adressen für jedes Netzwerk und notiere die Antwortzeit. Die durchschnittliche Antwortzeit in der Tabelle twobigints beträgt ungefähr 1 Sekunde, in der Binärtabelle ungefähr eine Hundertstelsekunde.

Hier sind die Fragen.

Hinweis:

X_ [HOCH / NIEDRIG] ist das 64-Bit mit der höchsten / niedrigsten Wertigkeit von X

Wenn NETMASK_LOW 0 ist, wird die AND-Bedingung weggelassen, da sie immer true ergibt. beeinträchtigt die Leistung nicht sehr.

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

Durchschnittliche Antwortzeiten:

Durchschnittliche Antwortzeiten

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
quelle
2

Ich glaube, die einzige andere Möglichkeit ist, es in einem varchar(39)Feld zu speichern .

BenV
quelle
2
Ich denke, das würde funktionieren, wenn Sie nur die Daten speichern möchten.
Eiefai
1
@ Eiefai: Ist es nicht das, was er fragt? "Ich muss 128-Bit-Ganzzahlen ohne Vorzeichen speichern"
BenV
Oh ja, das ist ein guter Rat, ich habe es nur kommentiert, um sicherzustellen, dass er nur speichern möchte, anstatt ein paar Kalkulationen zu machen.
Eiefai
@eiefai: ah ok, ich habe es falsch verstanden. Sie haben vollkommen recht, der Wert muss erst umgewandelt werden, bevor er als Zahl behandelt werden kann.
BenV