Czy powinienem poświęcić czas na zmianę typu kolumny z CHAR (36) na UUID?

14

Mam już kilka milionów wierszy w mojej bazie danych. Nie wiedziałem o typie danych UUID PostgreSQL podczas projektowania mojego schematu.

Jedna z tabel ma 16 mln wierszy (około 3,5 mln do 4 mln rekordów na odłamek), rosnąc przy około 500 000 rekordów dziennie. Nadal mam luksus wyłączania systemu produkcyjnego na kilka godzin w razie potrzeby. Nie będę miał tego luksusu za tydzień lub dwa.

Moje pytanie brzmi: czy warto to zrobić? Zastanawiam się nad wydajnością JOIN, wykorzystaniem miejsca na dysku (pełny zrzut gzip'd to 1,25 GiB), tego typu rzeczy.

Schemat tabeli to:

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)
François Beausoleil
źródło

Odpowiedzi:

13

Rozważę zmianę na typ UUID. char(36)zajmuje 40 bajtów, uuidzajmuje 16, więc zaoszczędzisz 24 bajty na wiersz, co dla ciebie będzie równe 12 MB dziennie, 4 GB po roku. Plus indeksy. W zależności od posiadanego sprzętu to niewiele, ale może być. I to sumuje się, jeśli masz więcej możliwości poprawy tego typu.

Ponadto nie widzę żadnego ograniczenia w twoim schemacie, który zapewnia, że interaction_idfaktycznie ma on odpowiedni format. Użycie odpowiedniego typu również ci to zapewni.

Jeśli jednak ci się to podoba, korzystanie z niego bigintpozwoli zaoszczędzić jeszcze więcej i mieć jeszcze lepszą wydajność. Jest bardzo mało prawdopodobne, że Twoja aplikacja jest tak duża, że bigintkolumna z identyfikatorem nie będzie działać.

Peter Eisentraut
źródło
Mam system rozproszony: wiele źródeł danych generuje identyfikatory dla interakcji, dlatego nie mogę użyć zwykłego BIGINT, chyba że zarezerwuję N bitów dla identyfikatora węzła.
François Beausoleil
3
@ FrançoisBeausoleil, zarezerwowanie N bitów dla identyfikatora węzła jest równoznaczne z użyciem każdej N-tej liczby w sekwencji (i dlatego jest łatwe do wdrożenia). Możesz także rozważyć użycie kluczy kompozytowych.
Nieuzasadniony
1
Koordynacja wielu sekwencji (z identyfikatorem węzła) jest w praktyce kłopotem administracyjnym i podatna na błędy ludzkie. Nie widzę powodu, aby nie używać identyfikatorów UUID w tym scenariuszu, zwłaszcza że bity są obecnie tanie (zarówno pamięć, jak i pamięć masowa). Rzeczywiście, ten scenariusz jest jednym z powodów, dla których identyfikatory UUID zostały wymyślone kilkadziesiąt lat temu: w celu udostępniania danych między systemami rozproszonymi bez scentralizowanej koordynacji .
Basil Bourque,
6

Nie jestem postgresową postacią wyobraźni, ale w oparciu o to, co wiem z SQL Server, im więcej wierszy możesz zmieścić na stronie danych, tym lepsza wydajność będziesz mieć (odczyt danych z dysku jest zwykle najdroższa operacja). Tak więc, idąc od 36 owski 1 bajt szerokim zakresie do 16 bajtów GUID wydaje się proste oszczędności. Im mniej odczytów możesz ponieść, tym szybciej możesz zwrócić wyniki. Wszystko to oczywiście zakłada, że ​​GUID / UUID spełnia potrzeby biznesowe tabeli. Jeśli UUID to spełni, czy bigint ? To jeszcze bardziej zmniejszy koszty przechowywania o kolejne 8 bajtów na wiersz.

Edytuj 1

Dane postaci w Postgres wiążą się z dodatkowymi kosztami przechowywania. Krótkie ciągi, poniżej 127 bajtów, mają narzut 1 bajt, podczas gdy cokolwiek dłuższego ma 4 bajty, tak więc drugi respondent wymyślił koszt 40 bajtów dla pola 36 bajtów. Ale jest też opcja kompresji ciągów, więc być może nie będzie to kosztować pełnych 40. Nie mogę powiedzieć, jaki byłby ostateczny koszt, ale fundamenty pozostają: wszystko, co przekracza 16 bajtów, zwiększy koszt pamięci, odczytywanie jej dłużej i zużywają więcej pamięci.

Wymaganie dotyczące przechowywania krótkiego ciągu (do 126 bajtów) wynosi 1 bajt plus rzeczywisty ciąg, który obejmuje dopełnianie spacji w przypadku znaku. Dłuższe łańcuchy mają narzut 4 bajty zamiast 1. Długie łańcuchy są automatycznie kompresowane przez system, więc wymagania fizyczne na dysku mogą być mniejsze.

billinkc
źródło
3

Oprócz problemu z przestrzenią pamiętaj, że musisz zmienić każdą tabelę, aby użyć poprawnego typu danych, w przeciwnym razie wydajność łączenia znacznie spadnie.

mrdenny
źródło
To było pewne, ale dziękuję za przypomnienie.
François Beausoleil
3
Kiedy dokonuję tak poważnych zmian, stwierdzam, że zapisywanie wszystkiego (bez względu na to, jak proste jest zapamiętanie) zwykle się opłaca.
mrdenny
3

Oprócz oszczędności wielkości danych i indeksów (jak powiedzieli inni), co przekłada się na oszczędności we / wy, należy wziąć pod uwagę, w jaki sposób wygenerować nowe wartości interaction_idi jaki będzie wpływ na indeksy i warunki zapytania (złączenia).

W przypadku indeksu - będzie mniejszy, jednak jeśli wiele zapytań korzysta ze skanów indeksów, przejście na UUID może uniemożliwić skanowanie indeksów (w zależności od sposobu generowania UUID) i bigintmoże być znacznie lepszym wyborem.

Wreszcie, ponieważ faktyczny wpływ na wydajność zależy również od wzorców użytkowania i dystrybucji danych, należy uruchomić testy i mieć środowisko programistyczne i testowe, w którym można przetestować zmiany.

To da ci znacznie dokładniejszą odpowiedź na temat wpływu na wydajność.

Nieuzasadniony
źródło
Dziękujemy za użyteczny wkład i witamy na stronie :)
Jack mówi, spróbuj wypróbować topanswers.xyz
Moje wzorce dostępu obejmują zakresy dat, ŁĄCZENIE za pomocą nazwy ekranowej lub UUID. Nie przewiduje się skanowania zakresu unikalnego identyfikatora. Dziękuję za odpowiedź, bardzo pouczająca.
François Beausoleil