Menu

SQLite vs PostgreSQL: kiedy wybrać którą bazę danych

Czym naprawdę różnią się SQLite i PostgreSQL: architekturą, współbieżnością, typami i rodzajem projektów, do których każda z nich pasuje najlepiej.

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

Dwie bazy, dwa różne kształty

SQLite i PostgreSQL mówią w SQL, obie przechowują dane relacyjne i obie mogą napędzać prawdziwe aplikacje. Poza tym powstały dla różnych światów.

  • SQLite to biblioteka. Działa wewnątrz procesu aplikacji i czyta z jednego pliku .db na dysku. Bez serwera, bez portu, bez użytkowników do skonfigurowania.
  • PostgreSQL to serwer. Działa jako osobny proces, nasłuchuje na porcie sieciowym, a aplikacja łączy się z nim jako klient.

Niemal każda inna różnica między nimi (współbieżność, wdrożenie, ścisłość typów, wydajność) wynika z tego jednego podziału architektonicznego. Pamiętaj o nim w dalszej części.

Architektura: w procesie kontra klient-serwer

Otwarcie bazy SQLite to otwarcie pliku:

Nie ma demona do uruchomienia, pg_hba.conf do edycji ani portu do wystawienia. Aplikacja ładuje bibliotekę SQLite, otwiera notes.db i zaczyna wykonywać zapytania. Wdrożenie to "skopiuj plik".

Postgres wygląda raczej tak:

# Uruchom serwer (raz, jako administrator):
sudo systemctl start postgresql

# Potem połącz się z aplikacji:
psql -h localhost -U alice -d mydb

Aplikacja rozmawia z osobnym procesem, zwykle przez TCP, czasem przez gniazdo Unix. Ta dodatkowa warstwa kosztuje czas konfiguracji i jedno przejście przez połączenie na każde zapytanie, ale w zamian daje dostęp sieciowy, uwierzytelnianie wielu użytkowników i prawdziwie współbieżnych piszących.

Współbieżność to najważniejsza kwestia

Zwykle to ona przesądza o wyborze. SQLite szereguje zapisy: w każdej chwili jeden piszący trzyma blokadę pliku bazy, a pozostali czekają. Odczyty mogą odbywać się równolegle (zwłaszcza w trybie WAL), ale zapisy idą jeden po drugim.

Postgres używa MVCC (multi-version concurrency control, wielowersyjnej kontroli współbieżności) i blokowania na poziomie wierszy. Wiele transakcji może jednocześnie zapisywać różne wiersze, nie blokując się nawzajem.

W praktyce:

  • Blog z 50 czytelnikami na sekundę i jednym autorem, który od czasu do czasu coś pisze? SQLite wystarczy.
  • Kasa w sklepie internetowym, gdzie setki użytkowników naraz aktualizują stany magazynowe? Postgres.
  • Lokalna pamięć podręczna aplikacji mobilnej? SQLite, bez dyskusji.
  • Backend SaaS dla wielu klientów z dziesiątkami procesów działających w tle? Postgres.

Tryb WAL (PRAGMA journal_mode = WAL;) znacznie poprawia współbieżność w SQLite, bo czytający nie blokują piszących, ale nie zmienia zasady jednego piszącego naraz.

Systemy typów: luźny kontra ścisły

Postgres jest ścisły. Kolumna zadeklarowana jako INTEGER odrzuca tekst i koniec:

-- Postgres
CREATE TABLE t (n INTEGER);
INSERT INTO t (n) VALUES ('not a number');
-- ERROR: invalid input syntax for type integer

SQLite domyślnie używa powinowactwa typów (type affinity), czyli sugestii, a nie reguły. To samo wstawienie się udaje:

Tekst siedzi w kolumnie INTEGER. SQLite zapisał go jako tekst. Ta elastyczność była świadomą decyzją projektową: przydatną przy szybkich prototypach, niebezpieczną przy długo żyjących schematach.

Nowoczesne SQLite (3.37+) obsługuje tabele STRICT, które zachowują się bardziej jak Postgres:

Jeśli zaczynasz nowy projekt na SQLite, używaj STRICT. Usuwa to całą klasę niespodzianek w stylu "skąd w mojej kolumnie liczbowej wziął się tekst".

Zakres funkcji

Postgres ma więcej prawie wszystkiego: typów danych (tablice, zakresy, typy geometryczne, sieciowe, własne enumy), języków proceduralnych (PL/pgSQL, PL/Python), wyszukiwania pełnotekstowego z rankingiem, widoków zmaterializowanych, partycjonowania tabel, replikacji, zabezpieczeń opartych na rolach i bogatego ekosystemu rozszerzeń (PostGIS, TimescaleDB, pgvector).

SQLite pokrywa podstawy i dodaje kilka przydatnych funkcji na swoją skalę: funkcje JSON, wyszukiwanie pełnotekstowe przez FTS5, indeksy R-Tree, funkcje okna, CTE, kolumny generowane. Pomija wszystko, co zakłada istnienie serwera: użytkowników, role, replikację, dostęp sieciowy.

Z grubsza:

  • Potrzebujesz GIS, wyszukiwania wektorowego albo replikacji? Postgres.
  • Musisz dostarczyć bazę wewnątrz aplikacji na iOS? SQLite.
  • Potrzebujesz obu? Wiele zespołów rozwija i testuje na SQLite, a wdraża na Postgres, choć takie połączenie potrafi dać się we znaki przez różnice w składni (patrz niżej).

Różnice w składni, na które faktycznie trafisz

Większość codziennego SQL jest identyczna. Różnice skupiają się wokół schematu, typów i kilku wbudowanych funkcji:

-- Automatycznie rosnący klucz główny
-- SQLite:
CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);
-- Postgres:
CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
-- albo w nowoczesnym Postgres:
CREATE TABLE users (id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT);

-- Bieżący znacznik czasu
-- SQLite:  CURRENT_TIMESTAMP   (zwraca tekst)
-- Postgres: NOW()              (zwraca timestamp)

-- Typ logiczny
-- SQLite:  brak prawdziwego BOOLEAN; używaj INTEGER 0/1
-- Postgres: BOOLEAN z TRUE/FALSE

Jeśli rozwijasz na SQLite, a wdrażasz na Postgres, opłaca się trzymać ORM lub narzędzie do migracji między sobą a surowym SQL. Inaczej te różnice przeciekają do aplikacji.

Wydajność, uczciwie

"Szybsze" zależy od pytania. Dla jednego procesu wykonującego odczyty i małe zapisy SQLite trudno pobić: nie ma przejścia przez sieć, parsowania protokołu ani połączenia klienta. W benchmarkach z jednym klientem SQLite często wyprzedza Postgres przy prostych zapytaniach.

Dodaj współbieżnych piszących, duże zbiory danych wymagające równoległego wykonywania zapytań albo złożone plany, które korzystają z dojrzałego planera Postgres, a Postgres obejmuje prowadzenie. Postgres skaluje się też pionowo (większe maszyny, więcej rdzeni) w sposób, do którego SQLite po prostu nie został zaprojektowany.

Uczciwe podsumowanie: SQLite jest szybki w tym, do czego służy. Postgres jest szybki w tym, do czego służy. Wybieraj według kształtu obciążenia, a nie nagłówków benchmarków.

Krótki przewodnik decyzyjny

Sięgnij po SQLite, gdy:

  • Dane działają obok jednej aplikacji: desktopowej, mobilnej, wbudowanej, narzędzia CLI.
  • Zapisy pochodzą z jednego procesu lub kilku procesów.
  • Chcesz wdrożenia bez żadnej konfiguracji.
  • Prototypujesz i chcesz skupić się na schemacie, a nie na infrastrukturze.

Sięgnij po Postgres, gdy:

  • Do bazy zapisuje wiele serwerów aplikacji lub procesów roboczych.
  • Potrzebujesz dostępu sieciowego z wielu klientów.
  • Potrzebujesz zaawansowanych funkcji: ról, replikacji, GIS, własnych typów, procedur składowanych.
  • Dane to trwały, centralny magazyn usługi produkcyjnej.

Częsta ścieżka: zacznij mały projekt na SQLite i przejdź na Postgres, jeśli i kiedy wymusi to charakter ruchu. Migracja nie jest darmowa, ale to znana operacja, a większość projektów nigdy jej nie potrzebuje.

Dalej: kiedy SQLite to właściwy wybór

Powyższe porównanie pokazuje kompromisy. Następna strona dokładniej omawia argumenty za SQLite: obciążenia, przy których jest nie tylko wystarczająco dobry, ale wręcz lepszy, oraz sygnały ostrzegawcze, że już z niego wyrastasz.

Najczęściej zadawane pytania

Jaka jest główna różnica między SQLite a Postgres?

SQLite to wbudowana biblioteka, która czyta i zapisuje jeden plik w procesie twojej aplikacji. PostgreSQL to osobny serwer, z którym łączysz się przez sieć. Ta jedna różnica architektoniczna napędza niemal każde inne porównanie: współbieżność, wdrożenie, typy i narzędzia wynikają właśnie z niej.

Czy SQLite jest szybszy niż Postgres?

Przy odczytach i małych zapisach w jednym procesie często tak: SQLite nie ma przejścia przez sieć ani narzutu protokołu klient-serwer. Przy współbieżnych zapisach od wielu klientów Postgres wychodzi na prowadzenie dzięki blokowaniu na poziomie wierszy i MVCC. To, co jest 'szybsze', zależy od obciążenia, a nie od silnika.

Czy mogę używać SQLite na produkcji?

Tak, przy odpowiednim kształcie obciążenia. SQLite bez problemu obsługuje na produkcji strony internetowe, aplikacje desktopowe i urządzenia wbudowane. Granicą są współbieżni piszący: jeśli wiele procesów musi zapisywać w tym samym czasie, Postgres obsługuje to natywnie, a SQLite szereguje zapisy. Tryb WAL pomaga, ale nie znosi tego ograniczenia.

Jak przenieść się z SQLite na Postgres?

Wyeksportuj schemat i dane przez sqlite3 mydb.db .dump, a potem popraw SQL: AUTOINCREMENT zmienia się w SERIAL lub GENERATED AS IDENTITY, zmieniają się nazwy typów, a kilka dziwactw SQLite, takich jak luźne typowanie, wymaga uporządkowania. Narzędzia takie jak pgloader automatyzują większość pracy. Przygotuj się na przepisanie wszystkiego, co opierało się na elastycznym typowaniu SQLite.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ