Sekwencyjny identyfikator GUID lub bigint dla „ogromnej” tabeli bazy danych PK

14

Wiem, że tego typu pytania często się pojawiają, ale jeszcze nie przeczytałem żadnych przekonujących argumentów, które pomogłyby mi w podjęciu tej decyzji. Proszę o wyrozumiałość!

Mam ogromną bazę danych - rośnie o około 10 000 000 rekordów dziennie. Dane są relacyjne i ze względu na wydajność ładuję tabelę BULK COPY. Z tego powodu muszę wygenerować klucze do wierszy i nie mogę polegać na kolumnie TOŻSAMOŚCI.

64-bitowa liczba całkowita - bigint - jest na tyle szeroka, że ​​mogę jej używać, ale aby zagwarantować wyjątkowość, potrzebuję scentralizowanego generatora, który utworzy dla mnie moje identyfikatory. Obecnie mam taką usługę generatora, która pozwala usłudze rezerwować numery sekwencyjne X i gwarantuje brak kolizji. Jednak konsekwencją tego jest to, że wszystkie usługi, które mam, zależą od tego jednego scentralizowanego generatora, więc jestem ograniczony w sposobie dystrybucji mojego systemu i nie jestem zadowolony z innych nałożonych zależności (takich jak wymaganie dostępu do sieci) według tego projektu. Czasami był to problem.

Zastanawiam się teraz nad użyciem sekwencyjnych identyfikatorów GUID jako moich kluczy podstawowych (generowanych zewnętrznie w języku SQL). O ile udało mi się ustalić na podstawie własnych testów, jedyną wadą jest narzut miejsca na dysku w szerszym typie danych (co pogarsza ich użycie w indeksach). Nie widziałem żadnego zauważalnego spowolnienia wydajności zapytań w porównaniu do alternatywy Bigint. Ładowanie do stołu BULK COPY jest nieco wolniejsze, ale niewiele. Moje indeksy oparte na GUID nie ulegają fragmentacji dzięki mojej sekwencyjnej implementacji GUID.

Zasadniczo chcę wiedzieć, czy są jakieś inne względy, które mogłem przeoczyć. W tej chwili jestem skłonny zrobić skok i zacząć korzystać z GUID. W żadnym wypadku nie jestem ekspertem od baz danych, więc naprawdę doceniłbym wszelkie wskazówki.

Barguast
źródło
2
Jak wygenerowałbyś „sekwencyjny identyfikator GUID”?
To niestandardowa implementacja. Jest to w zasadzie format typu GUID, w którym 6 bajtów zastąpiono bajtami znaczników czasu, a 2 bajty reprezentują numer kolejny, w którym znacznik czasu jest taki sam. Nie gwarantuje się uzyskania idealnych wartości sekwencyjnych, ale wystarcza, aby fragmentacja indeksu nie była dla mnie problemem.
Czy ładujesz te dane z wielu różnych źródeł? Zakładam również, że indeks, którego martwisz się o fragmentację, to indeks klastrowany?
2
Jeśli korzystasz z sekwencyjnego GUID, powinieneś spojrzeć na NEWSEQUENTIALID (). Powinien robić to, co chcesz (monotonicznie rosnące) i nie opiera się na niestandardowym kodzie.
2
Spójrz na post Jeremiasza Peschki na temat kłopotów z kluczami. Czytam dobrze i wiele razy zajmował się tymi implementacjami.
billinkc

Odpowiedzi:

4

Jestem w podobnej sytuacji. Obecnie używam sekwencyjnego podejścia GUID i nie mam fragmentacji i łatwego generowania klucza.

Zauważyłem dwie wady, które spowodowały, że zacząłem migrować do bigint:

  1. Wykorzystanie przestrzeni . 8 bajtów więcej na indeks. Pomnóż to przez około 10 indeksów, a otrzymasz ogromne marnowanie miejsca.
  2. Indeksy magazynu kolumn nie obsługują identyfikatorów GUID.

(2) Był dla mnie zabójcą.

Teraz wygeneruję moje klucze w następujący sposób:

yyMMddHH1234567890

Będę używał wiodącej daty plus godziny, a potem będę miał sekwencję . To pozwala mi przesyłać zapytania o dane według daty bez żadnego indeksu dodawania. To dla mnie niezły bonus.

Wygeneruję sekwencyjną część biginta przy użyciu algorytmu HiLo , który dobrze nadaje się do dystrybucji .

Mam nadzieję, że niektóre z tych przeniesień do twojej sytuacji. Zdecydowanie polecam użycie biginta.

usr
źródło
1
Oznaczam to jako „odpowiedź”, ponieważ jest to najlepsze dopasowanie (wydaje się, że doceniasz to, o co pytam i dlaczego nie jest to tak proste, jak mogłoby się wydawać na pierwszy rzut oka). Myślę, że wybiorę wspólny generator sekwencji (który będzie działał podobnie do twojej sugestii algorytmu HiLo). Mam to działa na innym systemie z kilkoma problemami, będę musiał znosić dodatkową zależność. No cóż. Dzięki.
Barguast
3

Przy typie INT, zaczynając od 1, otrzymujesz ponad 2 miliardy możliwych wierszy - powinno to być więcej niż wystarczające w zdecydowanej większości przypadków. Dzięki BIGINT, można uzyskać w przybliżeniu 922 biliardów (922 z 15 zerami - 922'000 miliardów) - wystarczy dla ciebie ??

Jeśli użyjesz wartości INT IDENTITYpoczątkowej od 1 i wstawisz wiersz co sekundę, potrzebujesz 66,5 lat, zanim osiągniesz limit 2 miliardów ...

Jeśli użyjesz wartości BIGINT IDENTITYpoczątkowej od 1 i wstawisz tysiąc wierszy co sekundę, potrzebujesz zadziwiającego 292 milionów lat, zanim osiągniesz limit 922 biliardów ...

Używając 10 milionów wierszy dziennie, to zajmie ci wystarczającą liczbę danych na około 1'844'674'407'370 dni ( 1844 miliardów dni lub tyknięcie ponad 5 miliardów lat ) danych - czy to wystarczy dla twoich potrzeb ?

Przeczytaj więcej na ten temat (ze wszystkimi dostępnymi opcjami) w MSDN Books Online .

marc_s
źródło
1
Szybkość wprowadzania 10 milionów wierszy dziennie wyczerpałaby zakres INT w 200 dni.
mceda
@mceda: tak - czy zgłosiłam coś jeszcze? Nie wyczerpuje to jednak BIGINTtak szybko zasięgu ...
marc_s
Dzięki, ale jak powiedziałem w swoim pytaniu, potrzebuję identyfikatorów, zanim zostaną przesłane do bazy danych. Dane są relacyjne, więc muszę przypisać klucz podstawowy i klucz obcy, zanim zostaną skopiowane zbiorczo. Gdyby tak nie było, BIGINT TOŻSAMOŚCI prawdopodobnie byłby idealny.
2
@ Barguast: czy nie można po prostu wstawić danych zbiorczo do tabeli pomostowej (bez tożsamości), a następnie przenieść je stamtąd do rzeczywistych tabel danych za pomocą BIGINT IDENTITY?
marc_s,
@marc_s: tak, podane obliczenia nie były zgodne z pytaniem: „Jeśli używasz INT IDENTITY od 1 i wstawiasz wiersz co sekundę, potrzebujesz 66,5 lat, zanim osiągniesz limit 2 miliardów”.
mceda
2

Zalecam użycie SEQUENCE typu danych BIGINT w SQL 2012. Jest to o wiele bardziej elastyczne niż TOŻSAMOŚĆ z opcjami takimi jak cache / nocache, możesz także przypisać zakres sekwencji dla operacji wsadowej jako sp_sequence_get_range.


źródło
Niestety, SEQUENCE nie jest obsługiwany na Sql Azure.
Timothy Lee Russell
2

Czy nie możesz użyć TOŻSAMOŚCI, ponieważ istnieją już relacje kluczy obcych między ładowanymi oddzielnymi tabelami? I czy nie ma innego naturalnego klucza, aby móc połączyć je w operacji z obszaru przejściowego do obszaru produkcyjnego? Z tego powodu chciałbym dowiedzieć się nieco więcej o tym, jak są one obecnie „połączone” w systemie źródłowym, zanim zaczniesz kopiować zbiorczo? Czy wiele systemów źródłowych po prostu używa własnych sekwencji i ma możliwość wystąpienia sprzecznych sekwencji po wprowadzeniu do wspólnej bazy danych?

Znana mi jest technika COMB ID / sekwencyjny GUID i jest ona wykonalna za każdym razem, gdy efektywnie potrzebujesz globalnej unikalności przypisanej poza bazą danych - jest to faktycznie użyteczna tożsamość wiersza zarówno w bazie danych, jak i poza nią. Z tego powodu w wysoce rozproszonych środowiskach lub rozłączonych scenariuszach jest to dobry wybór

Z wyjątkiem sytuacji, gdy naprawdę tego nie potrzebujesz, ponieważ ta dodatkowa różnica szerokości jest znacząca, gdy rośnie rozmiar danych, a klucze te znajdują się w każdym indeksie i zestawach roboczych dla wielu zapytań.

Ponadto przy rozproszonym generowaniu, jeśli wiersze nie są w rzeczywistości w kolejności w kolumnie GUID, problemy z używaniem tego dla klastrowanego klucza indeksu (wąski, statyczny, rosnący) potencjalnie powoduje pewną fragmentację w porównaniu do klastrowania na TOŻSAMOŚCI pozostawać.

Cade Roux
źródło
0

Ogólnie można użyć OUTPUTklauzuli INSERTpolecenia, aby wstawić dane do obu tabel i powiązane z polem tożsamości.

Identyfikatora opartego na znaczniku czasu nie należy uważać za niezawodny - zależy to od zegara systemowego, który z kolei zależy od wielu rzeczy - od zegara sprzętowego po usługi synchronizacji czasu.

Serg
źródło