Menu

Klucz główny w SQLite: INTEGER, złożony i AUTOINCREMENT

Jak działają klucze główne w SQLite: wyjątkowy INTEGER PRIMARY KEY, klucze złożone, AUTOINCREMENT i dziwactwa, które zaskakują początkujących.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Co właściwie robi klucz główny

Klucz główny to kolumna (lub kombinacja kolumn), która jednoznacznie identyfikuje każdy wiersz tabeli. Dwa wiersze nie mogą mieć tej samej wartości klucza głównego. SQLite pilnuje tego za ciebie i używa klucza do szybkiego wyszukiwania wierszy.

Najprostsza forma to zapis bezpośrednio przy kolumnie:

Nie podajesz id, a SQLite i tak je uzupełnia. To nie magia, tylko szczególny przypadek INTEGER PRIMARY KEY, który warto zrozumieć, zanim napiszesz cokolwiek innego.

INTEGER PRIMARY KEY jest wyjątkowy

W większości baz klucz główny to po prostu indeks unikalny. W SQLite każda zwykła tabela ma już ukrytą 64-bitową liczbę całkowitą o nazwie rowid, która wewnętrznie identyfikuje wiersze. Gdy deklarujesz kolumnę dokładnie jako INTEGER PRIMARY KEY, ta kolumna staje się rowid. Bez dodatkowego indeksu i dodatkowego miejsca: twoje id i fizyczne położenie wiersza to jedno i to samo.

id i rowid to ta sama kolumna pod dwiema nazwami. Wyszukiwanie po id trafia prosto do wiersza, bez przechodzenia przez drugie drzewo. Dlatego standardowa rada dla SQLite brzmi: jeśli chcesz liczbowy klucz główny, napisz dokładnie INTEGER PRIMARY KEY. Nie INT, nie BIGINT, nie INTEGER NOT NULL PRIMARY KEY (no dobrze, ten zadziała, ale typem musi być INTEGER).

Inne typy też działają, tylko dostają osobny indeks unikalny. To w porządku, po prostu mniej zwarte.

AUTOINCREMENT zwykle jest zbędny

Częsty odruch przeniesiony z innych baz to pisanie id INTEGER PRIMARY KEY AUTOINCREMENT. W SQLite słowo kluczowe AUTOINCREMENT robi coś węższego, niż sugeruje nazwa, i w większości przypadków go nie potrzebujesz.

Bez AUTOINCREMENT kolumna INTEGER PRIMARY KEY wypełnia się automatycznie wartością o jeden większą od największego istniejącego rowid. Jeśli usuniesz ostatni wiersz, następne wstawienie może użyć tego id ponownie.

Z AUTOINCREMENT SQLite zapisuje najwyższe kiedykolwiek użyte id w pomocniczej tabeli sqlite_sequence i nigdy nie używa wartości ponownie, nawet po usunięciu.

Tabela plain ponownie użyła id 3. Tabela z AUTOINCREMENT przeskoczyła do 4. Jeśli nie masz prawdziwego powodu, by zabronić ponownego użycia id (audyt, zewnętrzne odwołania, które zostają po usunięciu), pomiń AUTOINCREMENT. Kosztuje dodatkowy zapis przy każdym wstawieniu i osobną tabelę pomocniczą.

Złożone klucze główne

Czasem jedna kolumna nie wystarcza. Na przykład tabela łącząca, która przypisuje użytkownikom role, jest jednoznacznie identyfikowana przez parę (user_id, role_id). W takim przypadku deklarujesz klucz na poziomie tabeli:

Para musi być unikalna w całej tabeli: (1, 10) może pojawić się tylko raz. Każda z kolumn osobno może się dowolnie powtarzać. O to właśnie chodzi: każdy użytkownik może mieć wiele ról, każda rola wielu użytkowników, ale dana para użytkownik i rola istnieje najwyżej raz.

Złożony klucz główny tworzy osobny indeks obejmujący podane kolumny. Nie staje się rowid: takie traktowanie dostaje tylko pojedynczy INTEGER PRIMARY KEY.

Pułapka z NULL w kluczu głównym

Oto dziwactwo, które zaskakuje osoby przychodzące z PostgreSQL czy MySQL: w zwykłej tabeli SQLite kolumna klucza głównego inna niż INTEGER PRIMARY KEY może zawierać NULL. To stary błąd, który autorzy SQLite zachowali dla zgodności wstecznej.

Dwa wiersze z NULL prześlizgnęły się obok klucza głównego. Rozwiązanie to jawne dodanie NOT NULL przy każdej kolumnie klucza głównego, która nie jest liczbą całkowitą:

Albo użyj tabeli STRICT, w której błąd z NULL w kluczu głównym jest poprawiony. Nawyk pisania NOT NULL przy każdej kolumnie klucza głównego to tanie ubezpieczenie.

Klucz główny a UNIQUE

Oba zapobiegają duplikatom. Różnice:

  • Tabela ma najwyżej jeden klucz główny, ale może mieć wiele ograniczeń UNIQUE.
  • Klucz główny to "główny" identyfikator tabeli: klucze obce domyślnie na niego wskazują.
  • INTEGER PRIMARY KEY staje się rowid, a kolumna liczbowa z UNIQUE nie.
  • Kolumny UNIQUE spokojnie przyjmują wiele wartości NULL (każdy NULL jest uznawany za różny).

id to tożsamość wiersza. email i username też są unikalne, ale to atrybuty biznesowe: mogą się zmienić, a id nie powinno.

Dodawanie klucza głównego później (w skrócie: nie rób tego)

ALTER TABLE w SQLite ma ograniczenia. Nie da się uruchomić ALTER TABLE ... ADD PRIMARY KEY, bo taka instrukcja nie istnieje. Jeśli zapomnisz o kluczu głównym, a tabela ma już dane, trzeba ją odtworzyć:

To standardowy taniec migracji w SQLite. W prawdziwym kodzie opakuj go w transakcję i na chwilę wyłącz klucze obce, jeśli inne tabele odwołują się do tej. Wniosek: ustal klucz główny poprawnie już przy CREATE TABLE.

Krótka lista kontrolna

Pisząc nową tabelę, zadaj sobie pytania:

  • Czy ten wiersz ma naturalny unikalny identyfikator? Jeśli to pojedyncza liczba całkowita, użyj INTEGER PRIMARY KEY.
  • Czy tożsamość to w rzeczywistości kombinacja kolumn (tabela łącząca)? Użyj PRIMARY KEY (col_a, col_b) na poziomie tabeli.
  • Czy klucz jest tekstem lub innym typem niż liczba całkowita? Dodaj jawnie NOT NULL.
  • Czy naprawdę potrzebujesz AUTOINCREMENT? Prawdopodobnie nie.
  • Czy tabela jest mała, głównie czytana i ma klucz główny inny niż liczbowy? Rozważ WITHOUT ROWID (opisane na stronie o rowid).

Dalej: rowid

INTEGER PRIMARY KEY pojawił się tu na chwilę jako "alias rowid", ale rowid jest fundamentem każdej zwykłej tabeli SQLite i warto go poznać bezpośrednio. O tym jest następna strona.

Najczęściej zadawane pytania

Jak zdefiniować klucz główny w SQLite?

Dodaj PRIMARY KEY do kolumny w instrukcji CREATE TABLE, np. id INTEGER PRIMARY KEY. Dla klucza obejmującego kilka kolumn użyj ograniczenia na poziomie tabeli: PRIMARY KEY (col_a, col_b). Kolumna lub kombinacja musi być unikalna we wszystkich wierszach.

Czym INTEGER PRIMARY KEY różni się od innych kluczy głównych w SQLite?

INTEGER PRIMARY KEY jest wyjątkowy: staje się aliasem wbudowanego rowid tabeli, więc jest przechowywany bezpośrednio w B-drzewie bez dodatkowego indeksu. Każdy inny typ albo klucz złożony dostaje osobny indeks unikalny. Dla jednokolumnowych identyfikatorów liczbowych INTEGER PRIMARY KEY jest szybszy i mniejszy.

Czy klucz główny w SQLite potrzebuje AUTOINCREMENT?

Zwykle nie. INTEGER PRIMARY KEY i tak automatycznie przydziela unikalny rowid, gdy wstawiasz NULL. AUTOINCREMENT dodaje jedynie gwarancję, że identyfikatory nigdy nie zostaną użyte ponownie po usunięciu, kosztem dodatkowej tabeli sqlite_sequence. Pomiń go, chyba że konkretnie potrzebujesz stale rosnących identyfikatorów.

Dlaczego mój klucz główny w SQLite dopuszcza wartości NULL?

To historyczny błąd zachowany dla zgodności: w zwykłych tabelach kolumna klucza głównego innego niż INTEGER może przyjmować NULL, jeśli nie dodasz jawnie NOT NULL. Wyjątkiem jest kolumna INTEGER PRIMARY KEY, która nigdy nie dopuszcza NULL. Dla bezpieczeństwa pisz NOT NULL przy każdej kolumnie klucza głównego albo używaj tabeli STRICT, w której ta zasada jest egzekwowana poprawnie.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ