PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przegląd szeregowych pseudotypów danych dla PostgreSQL

Wprowadzenie

PostgreSQL natywnie dostarcza bogatą różnorodność typów danych, wspierając wiele praktycznych przypadków użycia. Ten artykuł przedstawia specjalną implementację szeregowych typów danych zwykle używanych do tworzenia syntetycznych kluczy podstawowych.

Unikalne klawisze

Podstawową zasadą teorii projektowania baz danych jest to, że każda krotka (tj. wiersz) relacji (tj. tabela) musi być jednoznacznie identyfikowana z innych krotek. Atrybuty lub kolumny, które razem wyraźnie identyfikują jedną krotkę spośród wszystkich innych, nazywane są „kluczem”. Niektórzy puryści utrzymują, że każdy modelowany obiekt lub koncepcja z natury posiada atrybut lub zestaw atrybutów, które mogą służyć jako klucz i że ważne jest, aby zidentyfikować ten zestaw kluczowych atrybutów i wykorzystać je do unikalnego wyboru krotek.

Jednak z praktycznego punktu widzenia identyfikacja wystarczająco dużego zestawu atrybutów zapewniających niepowtarzalność modelowanego obiektu może być niepraktyczna, dlatego w przypadku rzeczywistych implementacji programiści często zwracają się do kluczy syntetycznych jako zastępstwa. Oznacza to, że zamiast polegać na jakiejś kombinacji rzeczywistych atrybutów, jako klucz definiuje się wartość wewnętrzną w bazie danych, zwykle zwiększaną wartość całkowitą, która nie ma żadnego fizycznego znaczenia. Oprócz prostoty klucza jednokolumnowego fakt, że nie ma zależności w świecie rzeczywistym, oznacza, że ​​czynniki zewnętrzne nigdy nie mogą wymusić potrzeby zmiany wartości, na przykład może to mieć miejsce w przypadku użycia imienia i nazwiska osoby jako klucz ... a następnie osoba wyszła za mąż lub przystąpiła do federalnego programu ochrony świadków i zmieniła nazwisko. Nawet niektóre wartości powszechnie uważane przez laików za unikalne i niezmienne, takie jak amerykański numer ubezpieczenia społecznego, nie są takie same:osoba może uzyskać nowy SSN, a czasami SSN są ponownie wykorzystywane.

Deklarowanie typu danych szeregowych

PostgreSQL zapewnia specjalną deklarację typu danych, aby zaspokoić tę potrzebę kluczy syntetycznych. Zadeklarowanie kolumny tabeli bazy danych jako typu SERIAL spełnia wymagania dotyczące kluczy syntetycznych, dostarczając unikatowe liczby całkowite podczas wstawiania nowych krotek. Ten pseudotyp danych implementuje kolumnę typu danych całkowitych ze skojarzoną wartością domyślną uzyskaną za pomocą wywołania funkcji, która dostarcza zwiększone wartości całkowite. Wykonanie następującego kodu w celu utworzenia prostej tabeli z kolumną identyfikatora typu serial:

CREATE TABLE person (id serial, full_name text);
actually executes the following DDL
CREATE TABLE person (
    id integer NOT NULL,
    full_name text
);

CREATE SEQUENCE person_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;
ALTER SEQUENCE person_id_seq OWNED BY person.id;
ALTER TABLE ONLY person
    ALTER COLUMN id
    SET DEFAULT nextval('person_id_seq'::regclass);

Oznacza to, że słowo kluczowe „serial” jako specyfikacja typu danych implikuje wykonanie instrukcji DDL tworzących kolumnę typu integer z ograniczeniem NOT NULL, SEQUENCE, a następnie domyślna kolumna jest ZMIENIONA, aby wywołać wbudowaną funkcję uzyskującą dostęp do tej SEQUENCE.

Wbudowana funkcja nextval wykonuje usługę autoinkrementacji:za każdym razem, gdy zostanie wywołana nextval, zwiększa określony licznik sekwencji i zwraca nowo powiększoną wartość.

Możesz zobaczyć wynik tego efektu, sprawdzając definicję tabeli:

postgres=# \d person
                   Table "public.person"
  Column   |  Type   |         Modifiers
-----------+---------+-----------------------------------------
 Id        | integer | not null default nextval('person_id_seq'::regclass)
 full_name | text    |

Wstawianie wartości seryjnych

Aby skorzystać z funkcji automatycznego przyrostu, po prostu wstawiamy wiersze, opierając się na domyślnej wartości dla kolumny szeregowej:

INSERT INTO person (full_name) VALUES ('Alice');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
(1 row)

Widzimy, że wartość dla kolumny id odpowiadająca nowemu wierszowi „Alice” została wygenerowana automatycznie. Alternatywnie można użyć słowa kluczowego DEFAULT, jeśli pożądane jest wyraźne wymienienie wszystkich nazw kolumn:

INSERT INTO person (id, full_name) VALUES (DEFAULT, 'Bob');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
(2 rows)

gdzie widzimy bardziej widoczną funkcję automatycznego zwiększania, przypisując kolejną wartość szeregowo do nowego wiersza dla drugiego wstawienia „Bob”.

Wstawianie wielu wierszy nawet działa:

INSERT INTO person (full_name) VALUES ('Cathy'), ('David');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  3 | Cathy
  4 | David
(4 rows)
Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokument

Brakujące wartości szeregowe

Wbudowana funkcja nextval jest zoptymalizowana pod kątem nieblokujących aplikacji o wysokiej współbieżności i dlatego nie uwzględnia wycofywania. W konsekwencji oznacza to, że w sekwencji mogą brakować wartości. Poniżej wycofujemy wstawkę, ale potem widzimy, że kolejna wstawka otrzymuje nową wartość, która pomija wartość, która byłaby powiązana z przerwaną transakcją:

BEGIN TRANSACTION;
INSERT INTO person (full_name) VALUES ('Eve');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  3 | Cathy
  4 | David
  5 | Eve
(5 rows)
ROLLBACK;
INSERT INTO person (full_name) VALUES ('Fred');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  3 | Cathy
  4 | David
  6 | Fred
(5 rows)

Zaletą nierespektowania wycofywania zmian jest to, że inne sesje próbujące równoczesnego wstawiania nie są blokowane przez inne sesje wstawiania.

Innym sposobem uzyskania brakujących wartości jest usunięcie wierszy:

DELETE FROM person WHERE full_name = 'Cathy';
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  4 | David
  6 | Fred
(4 rows)

Zwróć uwagę, że nawet po usunięciu ostatnio wstawionego wiersza odpowiadającego największej wartości kolumny id autoinkrementacji, licznik sekwencji nie powraca, tj. nawet jeśli po usunięciu wiersza odpowiadającego „Fred”, dla kolejnych wstawień licznik sekwencji nadal zachowuje poprzednio znana największa wartość i przyrosty stamtąd:

DELETE FROM person WHERE full_name = 'Fred';
INSERT INTO person (full_name) VALUES ('Gina');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  4 | David
  7 | Gina
(4 rows)

Luki lub brakujące wartości, jak pokazano powyżej, są podobno postrzegane jako problem przez niektórych programistów aplikacji, ponieważ na liście dyskusyjnej PostgreSQL General powoli, ale stale powtarza się pytanie, jak uniknąć przerw w sekwencji podczas korzystania z szeregowego pseudotypu danych. Czasami nie ma rzeczywistego podstawowego wymogu biznesowego, jest to po prostu kwestia osobistej niechęci do brakujących wartości. Ale są okoliczności, w których zapobieganie brakującym numerom jest prawdziwą potrzebą i jest to temat na kolejny artykuł.

NIE, NIE MOŻESZ - TAK, MOŻESZ!

Ograniczenie NOT NULL przypisane przez pseudotyp danych serial chroni przed wstawieniem wartości NULL dla kolumny id poprzez odrzucenie takich prób wstawienia:

INSERT INTO person (id, full_name) VALUES (NULL, 'Henry');
ERROR:  null value in column "id" violates not-null constraint
DETAIL:  Failing row contains (null, Henry).

W ten sposób mamy pewność, że posiadamy wartość tego atrybutu.

Jednak problemem, z którym spotykają się niektórzy, jest to, że, jak zadeklarowano powyżej, nic nie stoi na przeszkodzie jawnemu wstawianiu wartości, z pominięciem domyślnej wartości autoinkrementacji uzyskanej przez wywołanie funkcji nextval:

INSERT INTO person (id, full_name) VALUES (9, 'Ingrid');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  4 | David
  7 | Gina
  9 | Ingrid
(5 rows)

Ale potem dwa wstawienia później przy użyciu wartości domyślnej dają zduplikowaną wartość dla kolumny id, jeśli nie ma ograniczenia sprawdzania wartości kolumny względem wartości sekwencji:

INSERT INTO person (full_name) VALUES ('James');
INSERT INTO person (full_name) VALUES ('Karen');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  4 | David
  7 | Gina
  9 | Ingrid
  8 | James
  9 | Karen
(7 rows)

Gdybyśmy faktycznie używali kolumny identyfikatora seryjnego jako klucza, zadeklarowalibyśmy go jako KLUCZ PODSTAWOWY lub przynajmniej stworzylibyśmy UNIKALNY INDEKS. Gdybyśmy to zrobili, powyższa wstawka „Karen” zakończyłaby się niepowodzeniem z błędem zduplikowanego klucza. Najnowsza wersja PostgreSQL zawiera nową składnię deklaracji ograniczeń 'generowaną domyślnie jako tożsamość', która pozwala uniknąć tej pułapki i innych starszych problemów związanych z szeregowym pseudotypem danych.

Funkcje manipulacji sekwencjami

Oprócz wspomnianej już funkcji nextval, która przyspiesza sekwencję i zwraca nową wartość, istnieje kilka innych funkcji do odpytywania i ustawiania wartości sekwencji:funkcja currval zwraca wartość ostatnio uzyskaną z nextval dla określonej sekwencji, funkcja lastval zwraca wartość ostatnio uzyskaną z nextval dla dowolnej sekwencji, a funkcja setval ustawia bieżącą wartość sekwencji. Funkcje te są wywoływane za pomocą prostych zapytań, na przykład

SELECT currval('person_id_seq');
 currval
---------
       9
(1 row)

I zauważ, że jeśli wywołanie jest wykonywane do funkcji nextval niezależnie od faktycznego wykonania wstawiania, powoduje to zwiększenie sekwencji, co zostanie odzwierciedlone w kolejnych wstawkach:

SELECT nextval('person_id_seq');
 nextval
---------
      10
(1 row)
INSERT INTO person (full_name) VALUES ('Larry');
SELECT * FROM person;
 id | full_name
----+-----------
  1 | Alice
  2 | Bob
  4 | David
  7 | Gina
  9 | Ingrid
  8 | James
  9 | Karen
 11 | Larry
(8 rows)

Wniosek

Wprowadziliśmy podstawową wiedzę na temat pseudo-typu danych PostgreSQL SERIAL dla kluczy syntetycznych z automatycznym przyrostem. Dla ilustracji w tym artykule użyliśmy deklaracji typu SERIAL, która tworzy 4-bajtową kolumnę całkowitą. PostgreSQL spełnia różne potrzeby w zakresie zakresów dzięki pseudotypom danych SMALLSERIAL i BIGSERIAL dla, odpowiednio, 2-bajtowych i 8-bajtowych rozmiarów kolumn. Poszukaj przyszłego artykułu na temat jednego ze sposobów zaspokojenia zapotrzebowania na sekwencje bez brakujących wartości.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak wykonać transakcje bazy danych za pomocą psycopg2/python db api?

  2. PostgreSQL wybiera najnowszy wpis dla danego identyfikatora

  3. Jak zmienić ustawienia regionalne podczas formatowania liczb w PostgreSQL?

  4. Drukowanie na ekranie w pliku .sql postgres

  5. Utwórz unikalne ograniczenie z pustymi kolumnami