SQLite 是全世界部署最廣泛的資料庫引擎——超過 1 兆個資料庫正在運行,比所有其他資料庫加起來還多。它零設定、單一檔案、內建於 Python 標準庫,用一行 import sqlite3 就能開始。 這篇教學帶你從安裝、JSONB、FTS5 全文搜尋到 WAL 併發與 Python 最佳實踐一次學會。
為什麼 SQLite 無所不在?
先看幾個數字(來源:SQLite 官方統計):
- 全球超過 40 億支智慧型手機,每支手機內建並運行數百個 SQLite 資料庫
- 推估全球有超過 1 兆個(1e12)正在運行的 SQLite 資料庫
- 是全球第二廣泛部署的軟體庫,僅次於壓縮庫 zlib
你每天用的東西幾乎都靠它:Android 與 iPhone 的系統儲存、Chrome/Firefox/Safari 的瀏覽器資料、Skype、iTunes、Dropbox 用戶端……連 Python 和 PHP 都直接把 SQLite 內建在標準庫裡。你在商店買到的每一台電視、機上盒、車載導航,裡面也都有 SQLite。
SQLite 是什麼?三個關鍵特性
SQLite 是一個嵌入式(embedded)、單一檔案、零設定的關聯式資料庫。白話說:
| 特性 | 說明 |
|---|---|
| 嵌入式 | 不是獨立的伺服器程式,而是「函式庫」,直接嵌進你的應用程式裡 |
| 單一檔案 | 整個資料庫就是一個 .db 檔案,複製檔案 = 備份資料庫 |
| 零設定 | 不用安裝、不用開 port、不用設帳號密碼,檔案一開就能用 |
flowchart LR
A[你的應用程式] -->|直接呼叫<br/>不用網路| B[(app.db<br/>單一檔案)]
B --> C[零設定<br/>不用伺服器]
B --> D[SQL 標準相容<br/>ACID 交易]
B --> E[內建於<br/>Python/PHP]安裝與基本操作
SQLite 不需要「安裝」——Python 內建、Mac 內建、Linux 套件管理器也有。這裡示範 CLI 工具的用法:
# Linux / macOS
sudo apt install sqlite3 # Debian/Ubuntu
brew install sqlite3 # macOS
# 建立資料庫並進入互動模式
sqlite3 myapp.db
# 互動模式內的操作
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER);
INSERT INTO users (name, age) VALUES ('小明', 28);
SELECT * FROM users;
.headers on # 顯示欄位名稱
.mode column # 表格排版
最新版本是 3.53.1(2026 年 5 月 5 日發布),修復了影響 3.7.0–3.51.2 的 WAL-reset 資料損壞競態漏洞,並新增查詢結果格式化(QRF)、ALTER TABLE 直接增刪 NOT NULL/CHECK 約束等功能。建議所有專案都升級到 3.51.3 以上。
SQLite vs DuckDB:該用哪一個?
很多人會問 SQLite 跟 DuckDB 的差別。一句話:要存應用程式狀態 → SQLite;要分析大量資料、查 Parquet → DuckDB。我們的另一篇文章有完整比較,這裡用表格快速帶過:
| 比較項目 | SQLite | DuckDB |
|---|---|---|
| 定位 | 嵌入式 OLTP(交易處理) | 嵌入式 OLAP(分析查詢) |
| 典型用途 | 應用程式儲存、App 資料 | 資料分析、大查詢、Parquet |
| 寫入能力 | 強(支援併發寫入) | 弱(分析為主) |
| 記憶體資料庫 | 支援 | 支援 |
| 適合情境 | 使用者資料、設定、快取 | 報表、ETL、資料科學 |
JSONB:把 JSON 存成二進位,讀取快 2–3 倍
SQLite 從 3.45 版(2024 年 1 月)開始支援 JSONB——把 JSON 從純文字(TEXT)轉成緊湊的二進位格式(BLOB)儲存。好處是查詢時不需要每次重新解析整個 JSON 字串,讀取密集的應用效能顯著提升,佔用空間也更小。
-- 宣告為 BLOB,用 jsonb() 函數寫入
CREATE TABLE events (
id INTEGER PRIMARY KEY,
payload BLOB NOT NULL
);
INSERT INTO events (payload)
VALUES (jsonb('{"user": {"id": 42}, "action": "login"}'));
-- 查詢完全透明,直接用 json_extract()
SELECT json_extract(payload, '$.user.id') AS user_id
FROM events
WHERE json_extract(payload, '$.action') = 'login';
-- 針對 JSON 內部欄位建立索引,加速搜尋
CREATE INDEX idx_action ON events (json_extract(payload, '$.action'));
💡 什麼時候用 TEXT、什麼時候用 JSONB? 頻繁查詢 JSON 內部值 → 用 BLOB +
jsonb();需要保留原始字串(例如加密簽章、審計日誌要留原始格式)→ 用 TEXT。
FTS5 全文搜尋:告別慢到哭的 LIKE
當資料量變大,LIKE '%關鍵字%' 因為無法用索引而全表掃描,效能直接崩潰。SQLite 內建的 FTS5 虛擬表維護反向索引,支援專業級全文檢索:
-- 建立 FTS5 虛擬表
CREATE VIRTUAL TABLE posts USING fts5(title, body);
INSERT INTO posts (title, body) VALUES
('SQLite full-text search', 'FTS5 is fast and built in.'),
('Indexes in SQLite', 'B-trees power most lookups in SQLite.');
-- 基本搜尋(大小寫無關)
SELECT title FROM posts WHERE posts MATCH 'sqlite';
-- AND / 精確片語 / 前綴 / NOT / 欄位限定
SELECT title FROM posts WHERE posts MATCH 'fts5 AND index';
SELECT title FROM posts WHERE posts MATCH '"full-text search"';
SELECT title FROM posts WHERE posts MATCH 'trig*';
SELECT title FROM posts WHERE posts MATCH 'index NOT trigger';
SELECT title FROM posts WHERE posts MATCH 'title:sqlite';
BM25 相關度排名:每筆結果都有一個隱藏 rank 欄位,分數越低代表相關度越高。也可以自訂欄位權重:
-- 依相關度排序(rank 越低越相關)
SELECT title, rank FROM posts WHERE posts MATCH 'sqlite' ORDER BY rank;
-- 標題權重 10、內文權重 1
SELECT title, bm25(posts, 10.0, 1.0) AS score
FROM posts WHERE posts MATCH 'sqlite' ORDER BY score;
避免重複儲存:用外部內容表(content='實體表名'),FTS 表不存文字本體,再用 Trigger 自動同步索引:
CREATE TABLE articles (id INTEGER PRIMARY KEY, title TEXT, body TEXT);
CREATE VIRTUAL TABLE articles_fts USING fts5(
title, body, content='articles', content_rowid='id'
);
-- 之後建立 INSERT/UPDATE/DELETE 三個 trigger 同步(範例略)
WAL 模式:併發讀寫不卡關
SQLite 從 3.7.0 版(2010 年)支援 WAL(Write-Ahead Logging),把「先寫日誌再改主檔」反轉成「直接 append 到 -wal 檔,之後再 checkpoint 回主檔」:
- ✅ 讀寫並行:寫入時讀取者照常讀,不再互相阻塞
- ✅ 寫入更快:交易只需對 WAL 檔做一次順序寫入
- ✅ fsync 次數大減:對磁碟 I/O 敏感的系統差異明顯
- ⚠️ 不支援 NFS:所有連線必須在同一台主機
- ⚠️ 注意 checkpoint starvation:持續不間斷的讀取者可能讓 WAL 檔無限增長
啟用方式一行搞定(永久生效,重開資料庫依然有效):
PRAGMA journal_mode = WAL; -- 回傳 "wal" 即成功
Python 實戰:五個最佳實踐
Python 的 sqlite3 是標準庫,import sqlite3 即可用。以下是從官方文件與實務整理出的五個關鍵習慣:
1. 用 row_factory 讀取 dict 格式
import sqlite3
conn = sqlite3.connect('app.db', timeout=60.0)
conn.row_factory = sqlite3.Row # 可以用 row['name'] 取值
# 不需要 cursor 物件,直接 conn.execute 並迭代(避免 fetchall 佔記憶體)
for row in conn.execute('SELECT id, email FROM users WHERE age > ?', (20,)):
print(row['id'], row['email'])
2. 永遠用參數化查詢,杜絕 SQL 注入
# ❌ 錯誤示範:f-string 拼接 SQL,等著被注入
# conn.execute(f"SELECT * FROM users WHERE name = '{user_input}'")
# ✅ 正確示範:使用 ? 預留位置
conn.execute("SELECT * FROM users WHERE name = ?", (user_input,))
3. 大量寫入用 executemany
在迴圈裡重複 execute 是最常見的效能殺手。實測寫入 100 萬筆資料:
| 方法 | 耗時 |
|---|---|
迴圈內逐筆 execute | 2.7 秒 |
executemany 批次寫入 | 1.6 秒 |
data = ((i, f"user_{i}") for i in range(100000))
conn.executemany("INSERT INTO users (id, name) VALUES (?, ?)", data)
大規模匯入時延後建索引:先全部寫完再 CREATE INDEX,省去每次插入更新 B-tree 的開銷,效能可以差好幾倍。
4. 併發寫入用 BEGIN IMMEDIATE
SQLite 支援無限多個並行讀取,但同時只能有一個寫入者。預設的 DEFERRED 交易在「先讀後寫」的場景容易撞出 database is locked。解法是一開場就鎖:
try:
with conn: # context manager:成功自動 commit、錯誤自動 rollback
conn.execute("BEGIN IMMEDIATE") # 一開始就取得寫入鎖
exists = conn.execute("SELECT 1 FROM users WHERE id = ?", (1,)).fetchone()
if not exists:
conn.execute("INSERT INTO users (id, email) VALUES (?, ?)", (1, "info@example.com"))
except sqlite3.IntegrityError as e:
print("交易失敗,已自動 rollback:", e)
5. 善用記憶體資料庫
暫時性資料(測試、快取、分析)用 sqlite3.connect(':memory:'),速度極快且不落磁碟。
什麼時候「不要」用 SQLite?
SQLite 不是萬能的,遇到這些情境請改用 PostgreSQL / MySQL:
- 多伺服器架構:SQLite 不能跨機器連線(WAL 也不支援 NFS)
- 高併發寫入:同時多個寫入者,或用戶端直接連資料庫的多人服務
- 需要使用者權限管理:SQLite 沒有帳號/角色系統
- 超大資料庫:超過數百 GB 且持續成長,管理會變吃力
結語
SQLite 是那種「平常不會想到,但其實無所不在」的技術。對個人專案、工具型應用、AI Agent 的記憶儲存來說,它往往是最務實的選擇:零部署成本、單一檔案好備份、效能對單機應用綽綽有餘。而 JSONB、FTS5、WAL 這三件現代功能,讓它足以撐起很多「以為要架資料庫伺服器」的需求。
延伸閱讀
- DuckDB 完整教學 2026:從安裝到查詢 Parquet 實戰,資料分析神器 v2.0 新功能一次看懂
- MCP 完整教學 2026:什麼是 Model Context Protocol?從架構、三大原語到 Python 實作第一個 MCP Server 的權威指南
- Vaultwarden 完整教學 2026:自架 Bitwarden 相容密碼管理器,Rust 實作、66K 星開源、記憶體只要 10MB(Docker 安裝+HTTPS 設定)
資料來源
- SQLite Release 3.53.1 (2026-05-05) | 官方 Release Log
- Write-Ahead Logging | SQLite 官方文件
- Most Widely Deployed SQL Database Engine | SQLite 官方
- Modern SQLite Features You Might Be Missing | OpenReplay Blog
- SQLite Full-Text Search: FTS5 Virtual Tables and MATCH | Coddy Tech
- Your executable is a SQLite database | Simon Willison
