2013-08-22 8 views
12

Mam tabelę postgres z identyfikatorem SERIAL.Czy urządzenie Postgresql SERIAL działa inaczej?

id (serial) name age 

Wstawianie zwykle odbywa się z poziomu aplikacji internetowej.

włożeniu ręcznie dwa nowe rekordy Ustawianie identyfikatora jako max (id) +1 ****

Po tych 2 wkładki po internecie wkładki App 2 rekordowe daje błąd duplikat klucza.

Tylko dla 2 rekordów. Potem wszystko działa dobrze.

Pytanie brzmi - dlaczego mój wkład ręczny nie zwiększył numeru seryjnego?

Czy automatyczne inkrementowanie i numer seryjny są różne?

Czego mi tu brakuje? Czy MySQL lub jakikolwiek inny SQL mają ten sam problem?

+1

Serial to PostgreSQL to autoinkrementująca czterobajtowa liczba całkowita, NIE należy generować własnych liczb, jeśli id ​​jest numerem seryjnym. w MySQL jest to kolumna AUTO_INCREMENT mniej więcej .. –

Odpowiedz

39

Po utworzeniu kolumny serial or bigserial, PostgreSQL faktycznie robi trzy rzeczy:

  1. tworzy kolumnę int lub bigint.
  2. Tworzy sekwencję (posiadaną przez kolumnę), aby wygenerować wartości dla kolumny.
  3. Ustawia domyślną wartość kolumny na sekwencję nextval().

Po wstawieniu wartości bez określania kolumnę serial (lub jeśli jawnie określić DEFAULT jako jego wartość), nextval zostanie wywołana na sekwencji:

  1. Return kolejną dostępną wartość dla kolumna.
  2. Zwiększ wartość sekwencji.

Jeśli ręcznie dostarczyć niż domyślna wartość dla kolumny serial następnie sekwencja nie zostanie zaktualizowany i nextval może zwracać wartości, że kolumna serial już zastosowania. Więc jeśli robisz tego typu rzeczy, będziesz musiał ręcznie naprawić sekwencję dzwoniąc pod numer nextval or setval.

Należy również pamiętać, że zapisy można usunąć, więc luki w kolumnach serial można się spodziewać, więc używanie max(id) + 1 nie jest dobrym pomysłem, nawet jeśli nie występują problemy z współbieżnością.

Jeśli używasz serial lub bigserial, najlepiej jest pozwolić PostgreSQL zadbać o przypisanie wartości dla Ciebie i udawać, że są nieprzejrzystymi liczbami, które akurat pojawiają się w określonej kolejności: nie przypisz je sobie i nie zakładaj nic na ich temat poza wyjątkowością. Zasada ta dotyczy wszystkich baz danych IMO.


Nie jestem pewien, jak MySQL auto_increment współpracuje ze wszystkimi różnymi typami baz danych, ale może the fine manual pomoże.

+0

dzięki. Myślę, że nie ma dodatkowej sekwencji w mysql. jest to po prostu identyfikator automatycznej inkrementacji. więc max (id) +1 będzie działało w mysql, ale nie w postgresie! – zod

+0

, ale powinien mieć wyzwalacz seryjny sequesnce inkrementacji? jaka jest Twoja sugestia? wiem, że to nie tak. po prostu prosząc o propozycję – zod

+2

Moja sugestia jest w mojej odpowiedzi: pozostaw wartości 'serial' i' auto_increment' do bazy danych. Nie zadzieraj z nimi w ogóle. Jeśli pozwolisz, aby baza danych przydzieliła wartość "serial", sekwencja zostanie zaktualizowana i wszystko będzie dobrze; jeśli ręcznie przypiszesz wartość, musisz ręcznie zaktualizować sekwencję. –

7

Jeśli chcesz wstawić rekord do tabeli z kolumną serial - po prostu ommit to z zapytania - zostanie automatycznie wygenerowany.

Albo można wstawić jego wartość defaul z czymś takim:

insert into your_table(id, val) 
values (default, '123'); 

Trzecia opcja to malually przyjmować wartości z sekwencji szeregowego bezpośrednio:

insert into your_table(id, val) 
values (nextval(pg_get_serial_sequence('your_table','id')), '123'); 
+0

dzięki ... więc różni się od mysql..is to? czy sekwencja działa tak samo na oracle i serwerze sql? – zod

+0

@zod To samo w Oracle, ale nie mam żadnych expiriens z MS SQL Server. –

+0

Doskonała odpowiedź na domyślne wstawianie wartości dla typu SERIAL, gdy kolumny nie są określone. Szukałem odpowiednika "zerowej" PostgreSa dla AUTO_INCREMENT w MySQL. Dzięki. – Morey

2

włożeniu ręcznie dwóch nowych rekordów ustawienie identyfikator jako max (id) + 1 * *

To podejście jest całkowicie błędne i nie będzie działało w dowolnej bazie danych. Do tej pory działało to tylko dla ciebie w MySQL dzięki zwykłemu szczęściu.

Jeśli dwa połączenia jednocześnie uruchomią to, otrzymają ten sam identyfikator. Może działać niezawodnie tylko wtedy, gdy blokujesz tabelę przed równoczesnymi odczytami, dzięki czemu tylko jedno połączenie może uzyskać identyfikator w tym samym czasie.

Jest to również wyjątkowo nieefektywne.

Dlatego właśnie istnieją sekwencje, dzięki czemu można niezawodnie uzyskiwać identyfikatory w obecności współbieżnych insertera.

Wystarczy użyć:

INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id; 

lub:

INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id; 

DEFAULT jest miejscem szczególnym posiadacza powiedzieć, że bazy danych, aby uzyskać wartość domyślną dla danej kolumny z definicji tabeli. Wartość domyślna to nextval('my_table_id_seq'), więc zostanie wprowadzona kolejna wartość sekwencji.

Ponieważ zadajesz podstawowe pytania o sekwencje, polecam ci również, aby uważać, że sekwencje nie są bez przerwy. To normalne, że sekwencje mają "dziury", w których wartości w tabelach wynoszą 1, 3, 4, 5, 9, 10, ....

Powiązane problemy