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


12

Мені потрібно зберігати 128 біт непідписаних цілих чисел у MySQL, і мені було цікаво, який найкращий тип даних для зберігання таких великих чисел.

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

Чи є найкращий тип даних для зберігання 128-бітового цілого числа без підпису?


4
Я не можу не помітити, що це друге питання, коли, схоже, вам потрібно робити дивні речі зі своїм рішенням, щоб мати можливість використовувати MySql. Чи вважали ви більш надійною платформою DB?
Рассел Стін

Я би схильний подивитися, як FORTRAN та інші мови підтримують 64-бітні цілі числа, коли ми ще мали справу з 8 і 16 бітовими системами.
Джо

@Russel Steen, що б ти рекомендував як більш надійну платформу DB?
Камі

Вам все одно потрібно буде упакувати та розпакувати, але 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 може бути обмежений точністю або шкалою для даного стовпця. Коли такому стовпцю присвоюється значення з більшою кількістю цифр після десяткової крапки, ніж дозволено вказаною шкалою, значення перетворюється в цю шкалу. (Точна поведінка залежить від операційної системи, але, як правило, ефектом є усічення до допустимої кількості цифр.)

Він зберігається запаковано, тому він займе менше місця, ніж варчар ( 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 опускається, оскільки він завжди відповідає істині. не дуже впливає на продуктивність.

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)полі.


2
Я думаю, що це спрацює, якщо ви хочете лише зберігати дані.
eiefai

1
@eiefai: Це не те, про що він питає? "Мені потрібно зберегти 128 біт цілих чисел"
BenV

О так, це хороша порада, я просто прокоментував, щоб переконатися, що він хоче лише зберігати, а не робити кальку.
eiefai

@eiefai: ах добре, я неправильно зрозумів. Ви абсолютно праві, значення потрібно було б передати, щоб воно могло розглядатися як число.
BenV
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.