Тип данных MySQL для 128-битных целых

12

Мне нужно хранить 128-битные целые числа без знака в MySQL, и мне было интересно, какой тип данных лучше подходит для хранения таких больших чисел.

Прямо сейчас я использую, binary(16)но это включает в себя много функций преобразования pack(/huge number in hex .../).

Есть ли лучший тип данных для хранения 128-битного целого числа без знака?

Ками
источник
4
Я не могу не заметить, что это второй вопрос, когда кажется, что вам приходится делать странные вещи с вашим решением, чтобы иметь возможность использовать MySql. Вы рассматривали более надежную платформу БД?
Рассел Стин
Я был бы склонен посмотреть, как FORTRAN и другие языки поддерживают 64-битные целые числа, когда мы еще работали с 8- и 16-битными системами.
Джо
@ Рассел Стин, что бы вы посоветовали в качестве более надежной платформы БД?
Ками
Вам все равно нужно будет упаковать и распаковать его, но Postgres имеет собственный 128-битный тип .
Гай
На самом деле это должен сделать большой тип Postgres .
Гай

Ответы:

10

Я не знаю, как лучше всего хранить его, но есть хотя бы лучший вариант, чем использовать varchar(39)(или, varchar(40)если вам нужно, подпись); вместо этого используйте decimal(39,0). Из документации MySQL :

Типы с фиксированной точкой (точное значение)

Типы DECIMAL и NUMERIC хранят точные числовые значения данных. Эти типы используются, когда важно сохранить точную точность, например, с денежными данными. В MySQL NUMERIC реализован как DECIMAL, поэтому следующие замечания о DECIMAL в равной степени применимы к NUMERIC.

MySQL 5.1 сохраняет значения DECIMAL в двоичном формате. До MySQL 5.0.3 они хранились как строки. См. Раздел 11.18, «Точная математика».

В объявлении столбца DECIMAL могут быть (и обычно) указываются точность и масштаб; например:

salary DECIMAL(5,2)

В этом примере 5 - это точность, а 2 - это масштаб. Точность представляет количество значащих цифр, которые сохраняются для значений, а шкала представляет количество цифр, которые можно сохранить после десятичной точки.

Стандартный SQL требует, чтобы DECIMAL (5,2) мог хранить любое значение с пятью цифрами и двумя десятичными знаками, поэтому значения, которые можно хранить в столбце зарплаты, варьируются от -999,99 до 999,99.

В стандартном SQL синтаксис DECIMAL (M) эквивалентен DECIMAL (M, 0). Аналогично, синтаксис DECIMAL эквивалентен DECIMAL (M, 0), где реализации разрешается определять значение M. MySQL поддерживает обе эти вариантные формы синтаксиса DECIMAL. Значение по умолчанию M составляет 10.

Если масштаб равен 0, значения DECIMAL не содержат десятичной точки или дробной части.

Максимальное количество цифр для DECIMAL составляет 65, но фактический диапазон для данного столбца DECIMAL может быть ограничен точностью или масштабом для данного столбца. Когда такому столбцу присваивается значение с большим количеством цифр после десятичной запятой, чем разрешено указанным масштабом, значение преобразуется в этот масштаб. (Точное поведение зависит от операционной системы, но обычно результатом является усечение до допустимого количества цифр.)

Он хранится в упакованном виде, поэтому он займет меньше места, чем varchar ( 18 байт, если я правильно делаю свою математику ), и я надеюсь, что вы сможете сделать математику непосредственно, но я никогда не пытался с таким большим числом, чтобы увидеть, что происходит.

Джо
источник
8

Я обнаружил, что задаю этот вопрос, и из всех прочитанных постов я не нашел ни одного сравнения производительности. Итак, вот моя попытка.

Я создал следующие таблицы, заполненные 2 000 000 случайных IP-адресов из 100 случайных сетей.

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

Затем я выбираю все IP-адреса для каждой сети и записываю время отклика. Среднее время отклика в таблице с двумя значениями составляет около 1 секунды, в то время как в двоичной таблице оно составляет около одной сотой секунды.

Вот вопросы.

Замечания:

X_ [HIGH / LOW] является наиболее / наименее значимым 64-разрядным из X

когда NETMASK_LOW равен 0, условие AND опускается, поскольку оно всегда возвращает true. не сильно влияет на производительность.

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

Среднее время отклика:

Среднее время отклика

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

Я считаю, что единственный другой вариант - хранить его в varchar(39)поле.

BENV
источник
2
Я думаю, что это будет работать, если вы хотите сохранить данные.
Eiefai
1
@eiefai: не об этом ли он спрашивает? «Мне нужно хранить целые беззнаковые 128 битов»
BenV
О да, это хороший совет, я просто прокомментировал, чтобы убедиться, что он хочет только хранить, а не делать некоторые кальки.
Eiefai
@eiefai: ну ладно, я не понял. Вы абсолютно правы, значение должно быть приведено, прежде чем его можно будет рассматривать как число.
BenV