Tipo de datos MySQL para enteros de 128 bits

12

Necesito almacenar enteros sin signo de 128 bits en MySQL y me preguntaba cuál es el mejor tipo de datos para almacenar números tan grandes.

En este momento, estoy usando binary(16)pero eso implica muchas funciones de conversión pack(/huge number in hex .../).

¿Existe un mejor tipo de datos para almacenar un entero sin signo de 128 bits?

Kami
fuente
44
No puedo evitar notar que esta es la segunda pregunta donde parece que tienes que hacer cosas raras con tu solución para poder usar MySql. ¿Has considerado una plataforma DB más robusta?
Russell Steen el
Me inclinaría a ver cómo FORTRAN y otros idiomas admiten enteros de 64 bits cuando todavía estábamos tratando con sistemas de 8 y 16 bits.
Joe
@Russel Steen, ¿qué recomendarías como una plataforma DB más robusta?
Kami
Aún necesitaría empacarlo y desempacarlo, pero Postgres tiene un tipo nativo de 128 bits .
Cayo
En realidad, el tipo bigserial de Postgres debería hacerlo.
Cayo

Respuestas:

10

No sé cuál es la mejor manera de almacenarlo necesariamente, pero hay al menos una mejor opción que usar un varchar(39)(o varchar(40)si lo necesitaras firmado); en su lugar use a decimal(39,0). De los documentos de mysql :

Tipos de punto fijo (valor exacto)

Los tipos DECIMAL y NUMERIC almacenan valores de datos numéricos exactos. Estos tipos se utilizan cuando es importante preservar la precisión exacta, por ejemplo, con datos monetarios. En MySQL, NUMERIC se implementa como DECIMAL, por lo que las siguientes observaciones sobre DECIMAL se aplican igualmente a NUMERIC.

MySQL 5.1 almacena valores DECIMALES en formato binario. Antes de MySQL 5.0.3, se almacenaban como cadenas. Consulte la Sección 11.18, "Matemáticas de precisión".

En una declaración de columna DECIMAL, la precisión y la escala pueden especificarse (y generalmente se especifican); por ejemplo:

salary DECIMAL(5,2)

En este ejemplo, 5 es la precisión y 2 es la escala. La precisión representa el número de dígitos significativos que se almacenan para los valores, y la escala representa el número de dígitos que se pueden almacenar después del punto decimal.

El SQL estándar requiere que DECIMAL (5,2) pueda almacenar cualquier valor con cinco dígitos y dos decimales, por lo que los valores que se pueden almacenar en la columna de salario oscilan entre -999.99 y 999.99.

En SQL estándar, la sintaxis DECIMAL (M) es equivalente a DECIMAL (M, 0). Del mismo modo, la sintaxis DECIMAL es equivalente a DECIMAL (M, 0), donde la implementación permite decidir el valor de M. MySQL admite ambas formas variantes de sintaxis DECIMAL. El valor predeterminado de M es 10.

Si la escala es 0, los valores DECIMALES no contienen punto decimal ni parte fraccionaria.

El número máximo de dígitos para DECIMAL es 65, pero el rango real para una columna DECIMAL dada puede estar limitado por la precisión o la escala de una columna dada. Cuando a dicha columna se le asigna un valor con más dígitos después del punto decimal que los permitidos por la escala especificada, el valor se convierte a esa escala. (El comportamiento preciso es específico del sistema operativo, pero generalmente el efecto es el truncamiento al número permitido de dígitos).

Está almacenado empaquetado, por lo que ocupará menos espacio que el varchar ( 18 bytes, si estoy haciendo mis cálculos correctamente ), y espero que puedas hacer cálculos matemáticos directamente, pero he Nunca intenté con un número tan grande para ver qué pasa.

Joe
fuente
8

Me encontré haciendo esta pregunta y de todas las publicaciones que leí nunca encontré ninguna comparación de rendimiento. Así que aquí está mi intento.

He creado las siguientes tablas, pobladas con 2.000.000 de direcciones IP aleatorias de 100 redes aleatorias.

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

Luego SELECCIONO todas las direcciones IP para cada red y registro el tiempo de respuesta. El tiempo de respuesta promedio en la tabla de dos dígitos es de aproximadamente 1 segundo, mientras que en la tabla binaria es de aproximadamente una centésima de segundo.

Aquí están las consultas.

Nota:

X_ [ALTO / BAJO] son ​​los 64 bits más / menos significativos de X

cuando NETMASK_LOW es 0, la condición AND se omite, ya que siempre produce verdadero. no afecta mucho el rendimiento

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

Tiempos de respuesta promedio:

Tiempos de respuesta promedio

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

Creo que la única otra opción es almacenarlo en un varchar(39)campo.

BenV
fuente
2
Creo que esto funcionaría si solo desea almacenar los datos.
eiefai
1
@eiefai: ¿No es eso lo que está preguntando? "Necesito almacenar números enteros sin signo de 128 bits"
BenV
Oh sí, este es un buen consejo, solo comenté para asegurarme de que solo quiere almacenar en lugar de hacer algunos cálculos.
eiefai
@eiefai: ah ok, no entendí bien. Tienes toda la razón, el valor tendría que ser lanzado antes de que pudiera tratarse como un número.
BenV