Type de données MySQL pour les entiers 128 bits

12

J'ai besoin de stocker des entiers non signés de 128 bits dans MySQL et je me demandais quel est le meilleur type de données pour stocker de tels grands nombres.

En ce moment, j'utilise binary(16)mais cela implique beaucoup de fonctions de conversion pack(/huge number in hex .../).

Existe-t-il un meilleur type de données pour stocker un entier non signé de 128 bits?

Kami
la source
4
Je ne peux pas m'empêcher de remarquer que c'est la deuxième question où il semble que vous deviez faire des choses étranges avec votre solution afin de pouvoir utiliser MySql. Avez-vous envisagé une plate-forme DB plus robuste?
Russell Steen,
Je serais enclin à regarder comment FORTRAN et d'autres langages ont pris en charge les entiers 64 bits alors que nous avions encore affaire à des systèmes 8 et 16 bits.
Joe
@Russel Steen, que recommanderiez-vous comme plate-forme DB plus robuste?
Kami
Vous auriez toujours besoin de l'emballer et de le déballer, mais Postgres a un type natif de 128 bits .
Gaius
En fait, le type Bigserial Postgres devrait le faire.
Gaius

Réponses:

10

Je ne sais pas quelle est la meilleure façon de le stocker - mais il y a au moins une meilleure option que d'utiliser un varchar(39)(ou varchar(40)si vous en aviez besoin signé); utilisez plutôt a decimal(39,0). Depuis les documents mysql :

Types à virgule fixe (valeur exacte)

Les types DECIMAL et NUMERIC stockent des valeurs de données numériques exactes. Ces types sont utilisés lorsqu'il est important de conserver une précision exacte, par exemple avec des données monétaires. Dans MySQL, NUMERIC est implémenté en tant que DECIMAL, donc les remarques suivantes sur DECIMAL s'appliquent également à NUMERIC.

MySQL 5.1 stocke les valeurs DECIMAL au format binaire. Avant MySQL 5.0.3, ils étaient stockés sous forme de chaînes. Voir Section 11.18, «Mathématiques de précision».

Dans une déclaration de colonne DECIMAL, la précision et l'échelle peuvent être (et sont généralement) spécifiées; par exemple:

salary DECIMAL(5,2)

Dans cet exemple, 5 est la précision et 2 est l'échelle. La précision représente le nombre de chiffres significatifs qui sont stockés pour les valeurs, et l'échelle représente le nombre de chiffres qui peuvent être stockés après le point décimal.

SQL standard requiert que DECIMAL (5,2) soit capable de stocker n'importe quelle valeur avec cinq chiffres et deux décimales, de sorte que les valeurs qui peuvent être stockées dans la colonne de salaire vont de -999,99 à 999,99.

Dans SQL standard, la syntaxe DECIMAL (M) est équivalente à DECIMAL (M, 0). De même, la syntaxe DECIMAL est équivalente à DECIMAL (M, 0), où l'implémentation est autorisée à décider de la valeur de M. MySQL prend en charge ces deux variantes de syntaxe DECIMAL. La valeur par défaut de M est 10.

Si l'échelle est 0, les valeurs DÉCIMALES ne contiennent ni point décimal ni partie fractionnaire.

Le nombre maximal de chiffres pour DECIMAL est de 65, mais la plage réelle pour une colonne DECIMAL donnée peut être limitée par la précision ou l'échelle d'une colonne donnée. Lorsqu'une telle colonne se voit attribuer une valeur avec plus de chiffres après la virgule décimale que ne le permet l'échelle spécifiée, la valeur est convertie à cette échelle. (Le comportement précis est spécifique au système d'exploitation, mais généralement l'effet est la troncature au nombre de chiffres autorisé.)

Il est stocké emballé, donc il prendra moins d'espace que le varchar ( 18 octets, si je fais bien mes calculs ), et j'espère que vous pourrez faire des calculs directement dessus, mais j'ai jamais essayé avec un si grand nombre de voir ce qui se passe.

Joe
la source
8

Je me suis retrouvé à poser cette question et de tous les articles que j'ai lus, je n'ai jamais trouvé de comparaison de performances. Voici donc ma tentative.

J'ai créé les tableaux suivants, remplis avec 2 000 000 d'adresses IP aléatoires provenant de 100 réseaux aléatoires.

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

Ensuite, je sélectionne toutes les adresses IP pour chaque réseau et enregistre le temps de réponse. Le temps de réponse moyen sur la table à deux chiffres est d'environ 1 seconde tandis que sur la table binaire, il est d'environ un centième de seconde.

Voici les requêtes.

Remarque:

X_ [HIGH / LOW] est le 64 bits le plus / le moins significatif de X

lorsque NETMASK_LOW est égal à 0, la condition AND est omise car elle donne toujours la valeur true. n'affecte pas beaucoup les performances.

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

Temps de réponse moyens:

Temps de réponse moyens

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
la source
2

Je crois que la seule autre option est de le stocker dans un varchar(39)champ.

BenV
la source
2
Je pense que cela fonctionnerait si vous souhaitez uniquement stocker les données.
eiefai
1
@eiefai: N'est-ce pas ce qu'il demande? "J'ai besoin de stocker des entiers non signés de 128 bits"
BenV
Oh ouais, c'est un bon conseil, je viens de commenter pour m'assurer qu'il ne veut stocker que des calculs.
eiefai
@eiefai: ah ok, j'ai mal compris. Vous avez absolument raison, la valeur doit être exprimée avant de pouvoir être traitée comme un nombre.
BenV