2009-10-08 14 views
16

Oto kolejna, o której ostatnio myślałem. Zawarliśmy we wcześniejszych dyskusjach: "naturalne klucze podstawowe są złe, sztuczne klucze podstawowe są dobre". Praca z Hibernate wcześniej Widziałem, że domyślnie Hibernacja tworzy jedną sekwencję dla wszystkich tabel. Na początku byłem zaskoczony tym, dlaczego miałbyś to zrobić. Ale później dostrzegłem przewagę, która sprawia, że ​​łączenie rodziców i dzieci jest dowodem na to, że są głupi. Ponieważ żadna z tabel nie ma tej samej wartości klucza podstawowego, przypadkowe powiązanie elementu nadrzędnego z tabelą, która nie jest elementem podrzędnym, nie daje wyników.Pytanie o opinie: Jedna sekwencja dla wszystkich tabel

Czy ktoś widzi jakiekolwiek wady tego podejścia? Widzę tylko jeden: nie możesz mieć więcej niż 999999999999999999999999999 rekordów w bazie danych.

+0

"zawarliśmy we wcześniejszych dyskusjach" - wewnętrznej dyskusji, czy coś na SO? – Kev

+0

Kilka dyskusji na temat SO. A "my" oznacza "mnie" ;-) –

+1

Naturalne klucze nie są "złe". Są niezbędne z punktu widzenia integralności danych. Pozwalają użytkownikom identyfikować rzeczy rzeczywiste zidentyfikowane w bazie danych. Zasadniczo sekwencja może być naturalnym kluczem. Właściwie zdecydowanie wolę termin "klucz biznesowy", ale oznacza to samo co "klucz naturalny" - tj. Klucz używany do identyfikacji informacji poza bazą danych (na przykład przez użytkowników biznesowych). – sqlvogel

Odpowiedz

7

W zależności od tego, w jaki sposób sekwencje są zaimplementowane w bazie danych, zawsze trafianie w tę samą sekwencję może być lepsze lub gorsze. Gdy tylko kilka lub tylko jeden wątek zażąda nowych wartości, nie będzie problemów z blokowaniem. Ale złe wdrożenie może spowodować zatory.

Kolejnym problemem jest wycofywanie transakcji: Sekwencje nie są wycofywane (ponieważ ktoś już prosił o wyższą wartość), więc możesz mieć duże luki, które zjedzą twoją przestrzeń numerów znacznie szybciej niż można by się spodziewać . OTOH, zajmie to trochę czasu, aby zjeść 2 lub 4 miliardy identyfikatorów (jeśli "tylko" używasz 32-bitowych (podpisanych) int), więc rzadko jest to problem w praktyce.

Na koniec nie można łatwo zresetować sekwencji, jeśli zajdzie taka potrzeba. Ale jeśli potrzebujesz sekwencji restartowania (powiedzmy, liczby rekordów od północy), możesz powiedzieć Hibernate, aby utworzyć/użyć drugiej sekwencji.

Główną zaletą jest to, że można jednoznacznie identyfikować obiekty w dowolnym miejscu w DB tylko po identyfikatorze. Oznacza to, że możesz poważnie ograniczyć informacje o logu, które piszesz w systemie produkcyjnym, i nadal coś znaleźć, jeśli masz tylko identyfikator.

+2

Ref: "2 lub 4 miliardy identyfikatorów (jeśli używasz 32-bitowych (podpisanych)"), maksymalna wartość dla sekwencji Oracle wynosi w rzeczywistości 10^27, a typ Oracle NUMBER będzie przechowywać liczby całkowite do 38 cyfr precyzji. Powinno nas trochę uspokoić. –

+0

Mam na myśli "nawet jeśli używałeś tylko 32-bitowych liczb" dla identyfikatora. Większość ludzi używa dzisiaj 64-bitowych (LONG lub BIGNUM) lub więcej lub nawet UUID. –

+0

Rzeczywiście. Moim komentarzem było podkreślenie, że typy danych liczbowych Oracle różnią się od innych systemów. Dokumenty referencyjne tutaj: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#SQLRF00222 –

11

Mogą występować problemy z wydajnością, gdy cały kod otrzymuje wartości z pojedynczej sekwencji - patrz this Ask Tom thread.

+0

+1 Naprawdę użyteczne łącze dzięki –

+0

W naszym przypadku, gdy zwiększyliśmy znacząco pamięć podręczną, wydajność pojedynczej sekwencji i wielu sekwencji była podobna. – Edwards

+5

Ahh możesz również chcieć przewinąć w dół na ten wątek i spojrzeć na Pana Marka Bobaksa odpowiedź odzwierciedla moje doświadczenia. – Edwards

2

Istnieje kilka wad korzystania z pojedynczą sekwencję: -

  • zmniejszona współbieżności. Przekazywanie następnej wartości sekwencji wymaga synchronizacji. W praktyce, nie sądzę, że będzie to duży problem. Oracle zachowuje specjalny kod podczas utrzymywania indeksów btree w celu wykrycia monotonicznie rosnących wartości i odpowiedniego zbilansowania drzewa.
  • CBO może mieć lepszy czas na szacowanie zapytań dotyczących zakresu indeks (jeśli kiedykolwiek to zrobiłeś), jeśli większość wartości została wypełniona

Korzyścią może być to, że możesz określić kolejność wstawień między różnymi tabelami.

5

Wolę jedną sekwencję w jednej tabeli. Wynika to z jednej ogólnej obserwacji: Niektóre tabele ("tabele główne") mają stosunkowo małą liczbę wierszy i muszą być przechowywane "na zawsze". Na przykład tabela klientów w systemie ERP.

W innych tabelach ("tabele transakcji") wiele wierszy jest generowanych wiecznie, ale po pewnym czasie wiersze te mogą być archiwizowane (lub po prostu usuwane). Najbardziej ekstremalnym przykładem jest tabela śledzenia używana do celów debugowania; może wzrosnąć o setki rzędów na sekundę, ale po kilku dniach każdy wiersz jest przestarzały.

Małe identyfikatory w tabelach głównych ułatwiają pracę bezpośrednio w bazie danych, np.do celów debugowania.

select * from orders where customerid=415 

vs

select * from orders where customerid=89461836571 

Ale to tylko drobny problem. Większym problemem jest jazda na rowerze. Jeśli użyjesz jednej sekwencji dla wszystkich tabel, po prostu nie możesz jej ponownie uruchomić. Po jednej sekwencji na tabelę można ponownie uruchomić sekwencje tabel transakcji po zarchiwizowaniu lub usunięciu starych danych. Tabele mistrzowskie prawie nigdy nie mają tego problemu, ponieważ rosną znacznie wolniej.

Widzę małą wartość w posiadaniu tylko jednej sekwencji dla wszystkich tabel. Argumenty do tej pory nie przekonują mnie.

1

Z pewnością istnieją zalety i wady w podejściu jednosekwencyjnym w stosunku do jednej sekwencji na stół. Osobiście znajduję możliwość przypisania prawdziwie unikalnego identyfikatora do wiersza, co sprawia, że ​​każda kolumna identyfikatora jest uuid, aby uzyskać wystarczającą przewagę nad innymi wadami. Jak Aaron D. zwięźle pisze:

można jednoznacznie zidentyfikować obiekty nigdzie w DB tylko przez ID

A dla większości zastosowań, ze względu na sposób partie Hibernate3 import wypowiedzi, to nie będzie być wąskim gardłem wydajności, chyba że ogromne ilości rekordów rywalizują o ten sam zasób db (SELECT hibernate_sequence.nextval FROM dual).

Mapowanie sekwencji nie jest obsługiwane w najnowszym wydaniu (1.2) Grails. Chociaż był obsługiwany w Grails 1.1 (!). Teraz wymaga podklasowania jednej z klas dialektowych Hibernuj jako obejścia.

Dla tych użyciu Grails/Gorm, rzucić okiem na tego wpisu JIRA:

Oracle Sequence mappings ignored

+0

Sposób obejścia (i kod Java) są tutaj zestawione -> http://stackoverflow.com/questions/2564491/does-overloading-grails-static-mapping-property-to-bolt-on-onabase-objects-vio – mikesalera