Tipo de dados MySQL para números inteiros de 128 bits

12

Eu preciso armazenar números inteiros não assinados de 128 bits no MySQL e queria saber qual é o melhor tipo de dados para armazenar números tão grandes.

No momento, estou usando, binary(16)mas isso envolve muitas funções de conversão pack(/huge number in hex .../).

Existe um melhor tipo de dados para armazenar um número inteiro não assinado de 128 bits?

Kami
fonte
4
Não posso deixar de notar que esta é a segunda pergunta, onde parece que você está tendo que fazer coisas estranhas com sua solução para poder usar o MySql. Você considerou uma plataforma de banco de dados mais robusta?
Russell Steen
Eu ficaria inclinado a ver como o FORTRAN e outros idiomas suportavam números inteiros de 64 bits quando ainda estávamos lidando com sistemas de 8 e 16 bits.
Joe
@ Russel Steen, o que você recomendaria como uma plataforma de banco de dados mais robusta?
Kami
Você ainda precisará empacotá-lo e descompactá-lo, mas o Postgres possui um tipo nativo de 128 bits .
Gaius
Na verdade, o tipo bigserial do Postgres deve fazê-lo.
Gaius

Respostas:

10

Não sei qual é a melhor maneira necessariamente de armazená-lo - mas há pelo menos uma opção melhor do que usar um varchar(39)(ou varchar(40)se você precisar assiná-lo); em vez disso, use a decimal(39,0). Nos documentos do mysql :

Tipos de ponto fixo (valor exato)

Os tipos DECIMAL e NUMERIC armazenam valores de dados numéricos exatos. Esses tipos são usados ​​quando é importante preservar a precisão exata, por exemplo, com dados monetários. No MySQL, NUMERIC é implementado como DECIMAL, portanto, as seguintes observações sobre DECIMAL se aplicam igualmente a NUMERIC.

O MySQL 5.1 armazena valores DECIMAIS em formato binário. Antes do MySQL 5.0.3, eles eram armazenados como strings. Consulte a Seção 11.18, “Matemática de precisão”.

Em uma declaração de coluna DECIMAL, a precisão e a escala podem ser (e geralmente são) especificadas; por exemplo:

salary DECIMAL(5,2)

Neste exemplo, 5 é a precisão e 2 é a escala. A precisão representa o número de dígitos significativos armazenados para valores e a escala representa o número de dígitos que podem ser armazenados após o ponto decimal.

O SQL padrão exige que DECIMAL (5,2) possa armazenar qualquer valor com cinco dígitos e duas casas decimais, portanto, os valores que podem ser armazenados na coluna de salário variam de -999,99 a 999,99.

No SQL padrão, a sintaxe DECIMAL (M) é equivalente a DECIMAL (M, 0). Da mesma forma, a sintaxe DECIMAL é equivalente a DECIMAL (M, 0), onde a implementação é permitida para decidir o valor de M. O MySQL suporta essas duas formas variantes da sintaxe DECIMAL. O valor padrão de M é 10.

Se a escala for 0, os valores DECIMAL não conterão ponto decimal ou parte fracionária.

O número máximo de dígitos para DECIMAL é 65, mas o intervalo real de uma determinada coluna DECIMAL pode ser restringido pela precisão ou escala de uma determinada coluna. Quando uma coluna é atribuída a um valor com mais dígitos após o ponto decimal do que o permitido pela escala especificada, o valor é convertido nessa escala. (O comportamento preciso é específico do sistema operacional, mas geralmente o efeito é truncamento para o número permitido de dígitos.)

Ele é armazenado compactado, portanto, ocupará menos espaço que o varchar ( 18 bytes, se eu estiver fazendo minha matemática corretamente ), e eu espero que você possa fazer matemática diretamente, mas eu nunca tentei com esse grande número ver o que acontece.

Joe
fonte
8

Eu me peguei fazendo essa pergunta e de todas as postagens que li nunca encontrei nenhuma comparação de desempenho. Então aqui está a minha tentativa.

Criei as tabelas a seguir, preenchidas com 2.000.000 de endereços IP aleatórios de 100 redes aleatórias.

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

Depois, seleciono todos os endereços IP de cada rede e registro o tempo de resposta. O tempo médio de resposta na tabela twobigints é de cerca de 1 segundo, enquanto na tabela binária é de cerca de um centésimo de segundo.

Aqui estão as consultas.

Nota:

X_ [ALTO / BAIXO] é o mais / menos significativo 64 bits de X

quando NETMASK_LOW é 0, a condição AND é omitida, pois sempre produz true. não afeta muito o desempenho.

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

Tempos médios de resposta:

Tempos médios de resposta

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

Acredito que a única outra opção é armazená-lo em um varchar(39)campo.

BenV
fonte
2
Eu acho que isso funcionaria se você quiser apenas armazenar os dados.
eiefai
1
@eiefai: Não é isso que ele está perguntando? "Preciso armazenar números inteiros não assinados de 128 bits"
BenV 26/01
Ah, sim, esse é um bom conselho, eu apenas comentei para garantir que ele só queira armazenar, em vez de fazer alguns cálculos.
eiefai
@eiefai: ah ok, eu entendi errado. Você está absolutamente certo, o valor teria que ser convertido antes que pudesse ser tratado como um número.
BenV