Powodem, dla którego wydaje ci się to dziwne, jest to, że myślisz o zwiększaniu licznika jako części operacji wstawiania, a zatem „NIC NIC” powinno oznaczać „nie zwiększaj niczego”. Wyobrażasz sobie to:
- Sprawdź wartości do wstawienia względem ograniczenia
- Jeśli wykryto duplikat, przerwij
- Sekwencja przyrostu
- Wstaw dane
Ale w rzeczywistości przyrost musi nastąpić przed próbą wstawienia . SERIAL
kolumna w Postgresie jest zaimplementowana jako DEFAULT
który wykonuje nextval()
funkcja na powiązanej SEQUENCE
. Zanim DBMS będzie mógł cokolwiek zrobić z danymi, musi mieć kompletny zestaw kolumn, więc kolejność operacji jest następująca:
- Rozwiąż wartości domyślne, w tym inkrementację sekwencji
- Sprawdź wartości do wstawienia względem ograniczenia
- Jeśli wykryto duplikat, przerwij
- Wstaw dane
Można to intuicyjnie zobaczyć, jeśli zduplikowany klucz znajduje się w samym polu autoinkrementacji:
CREATE TABLE foo ( id SERIAL NOT NULL PRIMARY KEY, bar text );
-- Insert row 1
INSERT INTO foo ( bar ) VALUES ( 'test' );
-- Reset the sequence
SELECT setval(pg_get_serial_sequence('foo', 'id'), 0, true);
-- Attempt to insert row 1 again
INSERT INTO foo ( bar ) VALUES ( 'test 2' )
ON CONFLICT (id) DO NOTHING;
Oczywiście nie można stwierdzić, czy istnieje konflikt bez zwiększania sekwencji, więc „nic nie rób” musi nastąpić po ten przyrost.