Typ danych MySQL dla 128-bitowych liczb całkowitych

12

Muszę przechowywać 128 bitów liczb całkowitych bez znaku w MySQL i zastanawiałem się, jaki jest najlepszy typ danych do przechowywania tak dużych liczb.

Obecnie używam, binary(16)ale wymaga to dużej ilości funkcji konwersji pack(/huge number in hex .../).

Czy istnieje najlepszy typ danych do przechowywania 128-bitowej liczby całkowitej bez znaku?

Kami
źródło
4
Nie mogę nie zauważyć, że to drugie pytanie, w którym wydaje się, że musisz robić dziwne rzeczy ze swoim rozwiązaniem, aby móc korzystać z MySql. Czy rozważałeś bardziej niezawodną platformę DB?
Russell Steen,
Byłbym skłonny spojrzeć, jak FORTRAN i inne języki obsługują liczby całkowite 64-bitowe, gdy wciąż mamy do czynienia z systemami 8 i 16 bitowymi.
Joe
@ Russel Steen, co poleciłbyś jako bardziej niezawodną platformę DB?
Kami
Nadal będziesz musiał go spakować i rozpakować, ale Postgres ma natywny typ 128-bitowy .
Gajusz
Właściwie powinien to zrobić typ bigserial Postgres .
Gajusz

Odpowiedzi:

10

Nie wiem, jaki jest najlepszy sposób na przechowywanie go - ale jest co najmniej lepsza opcja niż użycie varchar(39)(lub varchar(40)jeśli potrzebujesz podpisu); zamiast tego użyj decimal(39,0). Z dokumentów mysql :

Typy stałych punktów (dokładna wartość)

Typy DECIMAL i NUMERIC przechowują dokładne wartości danych liczbowych. Te typy są używane, gdy ważne jest zachowanie dokładności, na przykład w przypadku danych pieniężnych. W MySQL, NUMERIC jest zaimplementowany jako DECIMAL, więc poniższe uwagi o DECIMAL dotyczą w równym stopniu NUMERIC.

MySQL 5.1 przechowuje wartości DECIMAL w formacie binarnym. Przed MySQL 5.0.3 były one przechowywane jako ciągi znaków. Patrz rozdział 11.18, „Matematyka precyzyjna”.

W deklaracji kolumny DECIMAL można określić (i zazwyczaj jest) precyzję i skalę; na przykład:

salary DECIMAL(5,2)

W tym przykładzie 5 to precyzja, a 2 to skala. Precyzja reprezentuje liczbę cyfr znaczących, które są przechowywane dla wartości, a skala reprezentuje liczbę cyfr, które mogą być przechowywane po przecinku.

Standardowy SQL wymaga, aby DECIMAL (5,2) mógł przechowywać dowolną wartość z pięcioma cyframi i dwoma miejscami po przecinku, więc wartości, które mogą być przechowywane w przedziale kolumny wynagrodzenia od -999.99 do 999,99.

W standardowym języku SQL składnia DECIMAL (M) jest równoważna DECIMAL (M, 0). Podobnie, składnia DECIMAL jest równoważna DECIMAL (M, 0), gdzie implementacja może decydować o wartości M. MySQL obsługuje obie te warianty form DECIMAL. Domyślna wartość M wynosi 10.

Jeśli skala wynosi 0, wartości dziesiętne nie zawierają kropki dziesiętnej ani części ułamkowej.

Maksymalna liczba cyfr dla DECIMAL to 65, ale rzeczywisty zakres dla danej kolumny DECIMAL może być ograniczony precyzją lub skalą dla danej kolumny. Gdy takiej kolumnie zostanie przypisana wartość z większą liczbą cyfr po przecinku, niż jest to dozwolone przez określoną skalę, wartość jest konwertowana na tę skalę. (Precyzyjne zachowanie jest specyficzne dla systemu operacyjnego, ale ogólnie efektem jest obcięcie do dopuszczalnej liczby cyfr).

Jest zapakowany, więc zajmie mniej miejsca niż varchar ( 18 bajtów, jeśli dobrze wykonuję matematykę), i mam nadzieję, że będziesz w stanie wykonać matematykę bezpośrednio, ale mam nigdy nie próbowałem z tak dużą liczbą, aby zobaczyć, co się stanie.

Joe
źródło
8

Zadałem sobie to pytanie i ze wszystkich przeczytanych postów nigdy nie znalazłem żadnych porównań wydajności. Oto moja próba.

Utworzyłem następujące tabele wypełnione 2 000 000 losowymi adresami IP ze 100 losowych sieci.

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

Następnie wybieram wszystkie adresy IP dla każdej sieci i rejestruję czas odpowiedzi. Średni czas odpowiedzi na tabeli twobigints wynosi około 1 sekundy, podczas gdy na tabeli binarnej jest to około jednej setnej sekundy.

Oto pytania.

Uwaga:

X_ [HIGH / LOW] jest najbardziej / najmniej znaczącym 64-bitowym Xem

gdy NETMASK_LOW wynosi 0, warunek AND jest pomijany, ponieważ zawsze daje true. nie wpływa znacząco na wydajność.

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

Średni czas reakcji:

Średni czas reakcji

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
źródło
2

Uważam, że jedyną inną opcją jest przechowywanie go w varchar(39)polu.

BenV
źródło
2
Myślę, że to zadziała, jeśli chcesz tylko przechowywać dane.
eiefai
1
@eiefai: Czy nie o to pyta? „Muszę przechowywać 128 bitów liczb całkowitych bez znaku”
BenV
O tak, to dobra rada, właśnie skomentowałem, aby upewnić się, że chce tylko przechowywać, a nie robić cielęta.
eiefai
@eiefai: ah ok, źle zrozumiałem. Masz całkowitą rację, wartość musiałaby zostać wyrzucona, zanim będzie mogła być traktowana jako liczba.
BenV