SQLite w programowaniu mobilnym: co to jest i jak działa

Autor: IT Sectr Opublikowano: 2026-03-11 Czas czytania: 10 min

SQLite to wbudowana relacyjna baza danych, która działa bez osobnego procesu serwerowego i przechowuje całą bazę w jednym pliku na urządzeniu. Dzięki zerowej konfiguracji, niewielkiemu rozmiarowi biblioteki i pełnemu wsparciu SQL, SQLite stała się standardem lokalnego przechowywania danych w aplikacjach mobilnych. Według danych SQLite Consortium (2025), ta SGBD jest używana w ponad 4 miliardach urządzeń, w tym w każdym smartfonie na iOS i Android.

Najważniejsze

  • SQLite — wbudowana relacyjna SGBD z zerową konfiguracją i przechowywaniem danych w jednym pliku.
  • Transakcje ACID — gwarantują integralność danych nawet przy awarii zasilania lub crashu aplikacji.
  • Typowanie danych — dynamiczne: SQLite nie wymaga ścisłego określenia typu kolumny podczas tworzenia tabeli.
  • Room — biblioteka ORM dla Androida, upraszczająca pracę z SQLite przez DAO i adnotacje.
  • CoreData może używać SQLite jako Persistent Store na iOS, ale dodaje warstwę zarządzania obiektami.

Czym jest SQLite?

SQLite to biblioteka w języku C implementująca relacyjną SGBD bez wydzielonego serwera. Jest wbudowywana bezpośrednio w aplikację, odczytuje i zapisuje dane w zwykłym pliku w systemie plików urządzenia. Rozmiar biblioteki wynosi około 600 KB, co czyni SQLite najlżejszą w pełni funkcjonalną bazą SQL.

SQLite obsługuje większą część standardu SQL:1999, w tym JOIN, podzapytania, triggery, widoki, indeksy i funkcje okienne. Ograniczenia dotyczą ALTER TABLE (ograniczone wsparcie) i pełnych RIGHT/FULL OUTER JOIN. Niemniej jednak dla aplikacji mobilnych funkcjonalność SQLite jest wystarczająca w 99% przypadków lokalnego przechowywania.

Według ankiety wśród programistów Stack Overflow (2025), SQLite jest najpopularniejszą bazą danych dla rozwiązań wbudowanych i zajmuje trzecie miejsce pod względem popularności wśród wszystkich SGBD po MySQL i PostgreSQL. W programowaniu mobilnym SQLite jest używana w każdej aplikacji — bezpośrednio lub przez nakładki.

Kluczowe cechy SQLite

Zero-configuration — SQLite nie wymaga instalacji, konfiguracji uprawnień, tworzenia użytkowników ani uruchamiania usługi. Biblioteka jest podłączana do projektu, a baza danych jest tworzona przez wywołanie jednej funkcji. To radykalnie upraszcza wdrożenie w porównaniu z SGBD klient-serwer, gdzie wymagana jest instalacja serwera, konfiguracja portów i użytkowników.

Plik bazy danych SQLite to zwykły międzyplatformowy plik, który można skopiować, przeanalizować, wysłać przez sieć lub przywrócić z kopii zapasowej. Format pliku jest stabilny na poziomie API: pliki SQLite 3 utworzone w 2004 roku otwierają się w bieżącej wersji biblioteki, co gwarantuje długoterminową kompatybilność danych.

Jak działa SQLite: architektura i przechowywanie

Architektura SQLite składa się z ośmiu maszyn wirtualnych: Tokenizer, Parser, Code Generator, VM, B-Tree, Pager, OS Interface i Utilities. Zapytanie SQL przechodzi przez Tokenizer (podział na tokeny), Parser (budowa AST), Code Generator (konwersja na kod bajtowy) i jest wykonywane na maszynie wirtualnej, która odczytuje strony danych przez B-Tree i Pager.

SQLite używa B-Tree do przechowywania tabel i indeksów. Każda tabela jest przechowywana jako osobne B-Tree, gdzie węzły liści zawierają wiersze danych. Indeksy również są przechowywane jako B-Tree, ale z kluczami w liściach. Pager zarządza ładowaniem stron (domyślnie 4096 bajtów) z pliku do pamięci, zapewniając transakcje ACID poprzez dziennik lub WAL.

Tryby dziennikowania

WAL (Write-Ahead Logging) — zalecany tryb dla aplikacji mobilnych. Zmiany są najpierw zapisywane do osobnego pliku WAL, a następnie okresowo przenoszone do głównej bazy danych. WAL umożliwia jednoczesne odczytywanie z bazy (stare dane) i zapisywanie do niej (przez WAL), co zwiększa wydajność aplikacji wielowątkowych. Standardowy dziennik (rollback journal) blokuje odczyt podczas zapisu.

ParametrRollback JournalWAL (Write-Ahead Logging)
Odczyt podczas zapisuBlokowanyDozwolony (odczytuje stare dane)
Wydajność zapisuŚredniaWysoka (sekwencyjny zapis do WAL)
Zużycie dyskuMniejsze (tylko dziennik wycofania)Większe (WAL + główna baza danych)
Odzyskiwanie po awariiWycofanie do ostatniego punktu kontrolnegoOdzyskiwanie z WAL (dane nie są tracone)
ZalecenieDla scenariuszy jednowątkowychDla typowych aplikacji mobilnych

Przełączanie między trybami wykonuje się jednym zapytaniem SQL: PRAGMA journal_mode=WAL. Dla aplikacji mobilnych z synchronizacją w tle i wątkiem UI jednocześnie odczytującym dane, WAL zapewnia lepszą wydajność i brak blokowania interfejsu.

SQLite vs inne bazy danych w programowaniu mobilnym

SQLite to nie jedyna opcja lokalnego przechowywania danych, ale najbardziej uniwersalna. Realm oferuje wyższą szybkość bezpośredniego dostępu do obiektów w pamięci, ale używa własnego formatu NoSQL i ma większy rozmiar biblioteki. Core Data na iOS to warstwa ORM na SQLite, która dodaje zarządzanie grafem obiektów i cofanie operacji.

Dla większości aplikacji SQLite pozostaje optymalnym wyborem dzięki przewidywalnej wydajności, zerowemu uzależnieniu od dostawcy i sprawdzonej stabilności. Realm i Core Data są uzasadnione w projektach ze złożonymi grafami obiektów, reaktywnymi zapytaniami lub wymaganiem synchronizacji między urządzeniami.

CechaSQLiteRealmCore Data
Typ bazy danychRelacyjna (SQL)NoSQL (obiektowa)ORM (na SQLite)
Rozmiar biblioteki~600 KB~4 MBWbudowany w SDK Apple
WydajnośćŚredniaWysoka (obiekty w pamięci)Średnia (narzut ORM)
PlatformyiOS, Android, Web, DesktopiOS, Android, Node.jsiOS, macOS
Uzależnienie od dostawcyBrak (otwarty standard)Średnie (własny format)Wysokie (tylko Apple)

Wybór między SQLite, Realm i Core Data zależy od platformy, wymagań dotyczących modelu obiektowego i strategii synchronizacji. Dla projektów międzyplatformowych (KMP, Flutter) SQLite pozostaje jedynym uniwersalnym wyborem działającym na wszystkich docelowych platformach bez zmian w modelu danych.

SQLite na Android: Room i SQLiteOpenHelper

Room — biblioteka z Android Jetpack, zapewniająca warstwę ORM na SQLite. Room automatycznie generuje zapytania SQL z adnotowanych interfejsów DAO, sprawdza poprawność zapytań na etapie kompilacji i obsługuje migracje bazy danych przy zmianie schematu. Room to zalecany sposób pracy z SQLite na Android.

SQLiteOpenHelper — niskopoziomowe API do bezpośredniego zarządzania SQLite bez ORM. Klasa zarządza tworzeniem, otwieraniem i aktualizowaniem bazy danych. SQLiteOpenHelper nadaje się do projektów z prostymi zapytaniami SQL lub gdy potrzebna jest pełna kontrola nad logiką SQL bez abstrakcji Room.

Przykład encji i DAO dla Room

Encja w Room jest adnotowana @Entity, a DAO — @Dao. Room tłumaczy adnotowane metody na zapytania SQL: @Insert generuje INSERT, @Query — SELECT z podanym SQL. Migracje są dodawane przez Migration z określeniem starej i nowej wersji schematu. Room sprawdza SQL na etapie kompilacji, co eliminuje błędy składniowe w produkcji.

kotlin
@Entity
data class User(
    @PrimaryKey val id: Long,
    val name: String,
    @ColumnInfo(name = "created_at")
    val createdAt: Long
)

@Dao
interface UserDao {
    @Query("SELECT * FROM user ORDER BY name ASC")
    suspend fun getAllUsers(): List<User>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("DELETE FROM user WHERE id = :id")
    suspend fun deleteUser(id: Long)
}

Room automatycznie generuje implementację UserDao_Impl, która zawiera zapytania w czasie wykonania do SQLite przez wewnętrzny RoomDatabase. Dzięki corutinom (suspend) metody DAO są wykonywane asynchronicznie w wątku tła, nie blokując UI. Typy zwracane Flow w @Query automatycznie aktualizują wynik przy zmianie tabeli.

SQLite na iOS: FMDB i GRDB

FMDB — nakładka Objective-C na C API SQLite, historycznie pierwsza popularna biblioteka dla iOS. Udostępnia obiekty FMDatabase i FMResultSet do wykonywania zapytań i pobierania wyników. FMDB jest prosta i minimalistyczna, ale nie obsługuje konstrukcji specyficznych dla Swift — opcjonali, Codable, async/await.

GRDB — nowoczesna biblioteka Swift do pracy z SQLite. Zapewnia type-safe API, obsługę Codable, Combine Publishers, async/await, migracje i obserwację zmian w czasie rzeczywistym. GRDB jest preferowana dla nowych projektów w Swift dzięki pełnej integracji ze Swift Concurrency i lepszej czytelności kodu.

Przykład GRDB w Swift

GRDB definiuje tabele przez klasy Record, zgodne z protokołami FetchableRecord i TableRecord. Zapytania są pisane w Swift z type-safe składnią, a nie surowym SQL. GRDB obsługuje również DatabaseMigrator do wersjonowania schematu i migracji między wersjami aplikacji.

swift
struct User: Codable, FetchableRecord, TableRecord {
    var id: Int64
    var name: String
    var createdAt: Date
}

let dbPool = try DatabasePool(path: dbPath)
var migrator = DatabaseMigrator()
migrator.registerMigration("v1") { db in
    try db.create(table: "user") { t in
        t.autoIncrementedPrimaryKey("id")
        t.column("name", .text).notNull()
        t.column("createdAt", .datetime).notNull()
    }
}

let users = try await dbPool.read { db in
    try User.order(Column("name")).fetchAll(db)
}

DatabasePool używa trybu WAL SQLite do współbieżnego odczytu. Wielu czytelników może jednocześnie uzyskiwać dostęp do bazy, podczas gdy jeden pisarz aktualizuje dane przez WAL. GRDB automatycznie zarządza połączeniami i transakcjami, zapewniając thread-safe dostęp do bazy z dowolnego wątku bez ręcznej synchronizacji.

Optymalizacja wydajności SQLite

Indeksy — najskuteczniejszy sposób przyspieszenia zapytań SQLite. Indeks jest tworzony na kolumnach uczestniczących w WHERE, JOIN i ORDER BY. Dla tabeli ze 100 000 rekordów wyszukiwanie po indeksowanej kolumnie zajmuje milisekundy zamiast sekund. Jednak indeksy spowalniają INSERT i UPDATE, dlatego ich liczba powinna być zbilansowana z częstotliwością zapisu.

Wstawianie wsadowe (batch insert) w ramach jednej transakcji radykalnie przyspiesza masowe ładowanie danych. Wstawienie 1000 rekordów pojedynczo daje narzut około 1 sekundy. Te same 1000 rekordów w jednej transakcji — około 5–10 milisekund. Różnica wynika z tego, że każdy osobny INSERT tworzy nową transakcję z synchronicznym zapisem na dysk.

Pragmy wydajności

PRAGMA — polecenia SQLite do konfiguracji zachowania biblioteki. Kluczowe pragmy optymalizacyjne: PRAGMA synchronous=NORMAL (zmniejsza częstotliwość fsync), PRAGMA cache_size=-8000 (przydziela 8 MB pamięci podręcznej), PRAGMA temp_store=MEMORY (tabele tymczasowe w pamięci). Dla aplikacji mobilnych z dużymi ilościami danych kombinacja tych pragm przyspiesza zapytania 2–3 razy.

Kolejną ważną optymalizacją jest wstępna kompilacja zapytań SQL (prepared statements). Jeśli zapytanie jest wykonywane wielokrotnie (na przykład wstawianie 10 000 wierszy), kompilacja SQL raz, a następnie użycie statement zmniejsza obciążenie CPU o 30–50%. Room i GRDB automatycznie buforują prepared statements, ale przy bezpośrednim użyciu C API SQLite kompilację trzeba wykonać ręcznie.

kotlin
class UserRepository(private val db: RoomDatabase) {

    suspend fun insertBatch(users: List<User>) {
        db.withTransaction {
            users.chunked(500).forEach { batch ->
                batch.forEach { user ->
                    insertUser(user)
                }
            }
        }
    }
}

Wstawianie wsadowe z withTransaction gwarantuje, że wszystkie INSERT są wykonywane w ramach jednej transakcji. Podział na podbatch (chunked) zapobiega zbyt dużemu rozmiarowi jednej transakcji, która mogłaby zablokować inne wątki na dłuższy czas. Dla synchronizacji w tle rozmiar podbatcha 500 rekordów daje optymalną równowagę szybkości i responsywności UI.

Często zadawane pytania

Czy można używać SQLite na wielu wątkach?

Tak, SQLite obsługuje dostęp wielowątkowy w trybie WAL. Wiele wątków może jednocześnie odczytywać dane, ale zapisywać może tylko jeden. Room i GRDB zarządzają synchronizacją automatycznie. W trybie rollback journal (domyślnym) baza jest całkowicie blokowana przy każdym zapisie.

Jaki jest maksymalny rozmiar bazy SQLite na urządzeniu mobilnym?

Ograniczenie SQLite — 281 TB (teoretyczne maksimum). W praktyce rozmiar bazy jest ograniczony dostępną pamięcią urządzenia. Dla aplikacji mobilnych komfortowy rozmiar to do 1–2 GB. Bazy większe niż 2 GB spowalniają tworzenie kopii zapasowej, aktualizację przez App Store i zwiększają zużycie pamięci RAM.

Czy dane w SQLite są bezpieczne?

SQLite nie szyfruje danych domyślnie — każdy proces z dostępem do pliku może je odczytać. Do szyfrowania używaj SQLCipher (rozszerzenie z AES-256), Room z EncryptedDatabase (Android) lub Encrypted Core Data na iOS. Szyfrowanie dodaje 5–15% narzutu na odczyt i zapis danych.

Czym różni się SQLite od MySQL?

SQLite to wbudowana (embedded) biblioteka, nie wymagająca procesu serwerowego. MySQL to SGBD klient-serwer z osobnym serwerem, użytkownikami, prawami dostępu i protokołem sieciowym. SQLite przechowuje bazę w jednym pliku, MySQL — w wielu plikach zarządzanych przez serwer. SQLite jest prostsza i lżejsza, MySQL potężniejsza i bardziej skalowalna.

Jak zaktualizować schemat SQLite bez utraty danych?

Do migracji SQLite używaj ALTER TABLE (dodawanie kolumn) lub tworzenia nowej tabeli z przeniesieniem danych i usunięciem starej. Room automatyzuje ten proces przez klasy Migration: podaj startVersion, endVersion i zapytania SQL do zmiany schematu. GRDB i FMDB zapewniają podobne DatabaseMigrator.

Podsumowanie

  • SQLite — wbudowana relacyjna SGBD z zerową konfiguracją, używana w każdej aplikacji mobilnej na iOS i Android do lokalnego przechowywania danych.
  • Transakcje ACID i tryb WAL zapewniają integralność danych i współbieżny dostęp z wielu wątków aplikacji.
  • Room (Android) i GRDB (iOS) — nowoczesne nakładki na SQLite, upraszczające pracę z bazą przez type-safe API i automatyczne migracje.
  • B-Tree architektura SQLite zapewnia efektywne wyszukiwanie po indeksach, a transakcje wsadowe i prepared statements — wysoką wydajność zapisu.
  • SQLite przewyższa Realm i Core Data pod względem uniwersalności (wszystkie platformy), rozmiaru biblioteki i braku uzależnienia od dostawcy.
  • Optymalizacja przez indeksy, tryb WAL i ustawienia PRAGMA przyspiesza zapytania 2–3 razy przy typowych obciążeniach mobilnych.
  • Zalecenie — używaj SQLite jako głównego magazynu danych lokalnych aplikacji mobilnej przez Room na Android i GRDB na iOS.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również