不妨大膽一點:SQLite 或許是你下一個 SaaS 專案的最佳資料庫選擇。沒錯,真的。支援瀏覽器歷史記錄的資料庫,甚至比你正在考慮的那個過度設計的 Postgres 集群,更能處理你的生產工作負載。
在你厭惡地關閉這個標籤頁之前,先聽我說完。我見過無數開發者將 SQLite 視為“玩具資料庫”,同時還要應對連接池、複製延遲以及每月 500 美元的資料庫帳單。與此同時,像 Expensify 這樣的公司正在使用 SQLite 處理價值 100 億美元的交易。
問題不在於 SQLite,而是我們對它的理解完全錯誤。
讓我們來談談這個顯而易見的問題:名字裡那個令人遺憾的「lite」。這就像把一輛跑車命名為「Slow McLaren」——從某種狹義上講,技術上準確,但對其實際性能完全誤導。
SQLite 並非“Postgres Lite”或“MySQL 入門版”,而是完全不同的另一類資料庫。 Postgres 是為客戶端-伺服器架建置構的,具有網路協定和連接管理功能,而 SQLite 是一個嵌入式資料庫引擎。它並非因為功能更少而更輕,而是因為它不需要完整的伺服器程序、網路堆疊和身份驗證系統。
SQLite 實際上是這樣的:
世界上部署最多的資料庫引擎(數十億個實例)
經過處理數百萬請求的公司在生產環境中的實戰測試
對於許多工作負載來說,速度比客戶端-伺服器資料庫更快
符合 ACID 規範並支援完整事務
能夠處理高達 281TB 的資料庫
但當然,因為這個名字,我們繼續稱它為玩具。
這就是傳統觀點的反面。 SQLite 不僅僅是在某些用例下「足夠好」——實際上,它是許多生產場景的更好選擇:
如果您的應用程式 95% 都用於讀取(就像大多數 SaaS 應用程式一樣),那麼 SQLite 將使您的 Postgres 設定黯然失色。無需網路往返,沒有連線開銷。只需使用智慧型頁面快取直接讀取磁碟即可。我親眼見證過,光是從 Postgres 切換到 SQLite,查詢時間就從 50 毫秒縮短到了 0.5 毫秒。
把所有東西都放在一台強大的伺服器上? SQLite 可以解決一系列問題:
連接池沒有耗盡
無網路延遲
無腦裂場景
無複製滯後
備份實際上只是複製一個文件
部署到多個區域?每個邊緣位置都可以擁有自己的 SQLite 資料庫。 Cloudflare Workers、Fly.io 和類似平台讓這一切變得輕而易舉。您的用戶將獲得低於 10 毫秒的回應時間,而您則擁有簡潔的架構。
需要對使用者資料進行數字運算? SQLite 可以處理 GB 層級資料的複雜分析查詢。視窗函數、CTE、JSON 操作——應有盡有。而且速度很快,因為沒有網路開銷。
讓我們坦誠地談談 SQLite 的困難之處,因為它並不像大多數人想像的那樣:
SQLite 使用單寫入模型,即每次只寫入一個資料。但反對者們沒有告訴你的是:自從引入預寫日誌 (WAL) 模式以來,SQLite 可以在寫入的同時處理並發讀取。寫入期間不再阻塞讀取。
在 WAL 模式下:
作家不會阻礙讀者
讀者不會阻礙作者
多個讀取器同時工作
寫入效能大幅提升
-- Enable WAL mode (do this once)
PRAGMA journal_mode=WAL;
在啟用 WAL 並進行適當配置的情況下,我發現 SQLite 在現代硬體上每秒可以處理 500-1000 次以上的寫入操作,同時還能處理數千次並發讀取。沒錯,Postgres 可以透過多個寫入器來實現更高的寫入速度,但問問自己:你的 SaaS 每秒真的能處理超過 1000 次寫入操作嗎? (劇透:沒有。)
需要跨多台伺服器進行水平擴展,並存取同一個資料庫嗎? SQLite 並非為此而生。您需要 Postgres 或 MySQL。 (不過,像 LiteFS 和 rqlite 這樣的解決方案正在改變這一現狀。)
SQLite 沒有使用者、角色或行級安全性。您的應用程式處理所有授權。對於 99% 的 SaaS 應用程式來說,這實際上沒有問題,因為這些應用程式無論如何都會在程式碼中檢查權限。
「SQLite 無法處理並發讀取」—錯誤。它可以處理無限的並發讀取。
「SQLite 不支援 JSON」——錯誤。自 2015 年起全面支持 JSON。
「SQLite 無法進行全文搜尋」——錯了。 FTS5非常出色。
「SQLite 資料庫很容易損壞」—錯了。它是迄今為止最可靠的儲存格式之一。
以下是在生產環境中考慮 SQLite 的方法:
Traditional Architecture:
App Server → Network → Database Server → Disk
SQLite Architecture:
App Server → Disk
就是這樣。你的資料庫查詢現在是函數呼叫。你的「連線」是一個檔案句柄。你的備份系統是cp database.db backup.db
。
這種簡潔並非限制,而是一種超能力。您移除的每個元件都不會發生故障,不會發生設定錯誤,也無需監控。
讓我們來討論一些能讓您的 DevOps 團隊喜極而泣的事情:SQLite 操作。
# Your entire backup strategy
cp production.db backup-$(date +%Y%m%d).db
# Or get fancy with point-in-time recovery using Litestream
# Streams every change to S3 automatically
litestream replicate production.db s3://mybucket/db
就是這樣。無需 pg_dump。無需協調副本。無需擔心備份一致性。使用 Litestream,您可以持續複製到 S3,並支援時間點恢復。只需 5 分鐘即可完成設置,無需再操心。
# Restore from yesterday
cp backup-20250115.db production.db
# Or restore from S3 with Litestream
litestream restore -o production.db s3://mybucket/db
這與恢復 50GB 的 Postgres 資料庫相比,我還是會等待。
# Clone prod for testing
cp production.db test.db
# Done. Full production dataset. Zero config.
無需清理連接字串。無需管理測試資料庫伺服器。無需向財務部門解釋為什麼需要另一個 RDS 實例進行暫存。
沒有連接池指標
無複製滯後
沒有長時間執行的查詢警報
無吸塵時間表
無磁碟空間警報
只是真正重要的應用指標。
// Instead of complex Redis + Postgres setups
async function getUser(userId: string) {
return db.get("SELECT * FROM users WHERE id = ?", userId);
// SQLite *is* your cache with 0ms latency
}
// Each customer gets their own SQLite database
function getCustomerDb(customerId: string) {
return new Database(`./data/customers/${customerId}.db`);
// Perfect isolation, easy backups, simple compliance
}
// SQLite for reads, Postgres for writes
// Stream changes from Postgres to SQLite replicas
// 99% of queries hit SQLite, 1% hit Postgres
const read = async (query: string) => sqlite.get(query);
const write = async (query: string) => postgres.execute(query);
在以下情況下使用 SQLite:
你閱讀量很大(閱讀量>90%)
您可以在一台伺服器上安裝(現在最多 100GB RAM 和 1TB 儲存空間很便宜)
您重視簡單性和可靠性
您希望最大限度地減少營運開銷
您正在建立嵌入式或邊緣應用程式
您需要一致的亞毫秒查詢時間
在以下情況下不要使用 SQLite:
您需要較高的寫入並發性(持續每秒寫入次數 >1000 次)
您需要來自不同伺服器的多個寫入器
您需要內建複製(儘管存在 LiteFS)
您需要資料庫級存取控制
有個不為人知的秘密:大多數使用 Postgres 的新創公司都更傾向於使用 SQLite。他們為不必要的分散式系統複雜性付出了代價,而效能卻比簡單的 SQLite 設定更差。
我已經將幾個生產系統從 Postgres 遷移到 SQLite。結果:
查詢速度提高 10 倍(無網路跳躍)
操作複雜度降低 90%
每月節省 500 美元的託管資料庫成本
備份/恢復時間從幾小時縮短至幾秒鐘
連接池問題導致零停機
最大的思維轉變是:別再把 SQLite 想成一個資料庫伺服器了。它不是。它只是一個恰好實作了 SQL 資料庫的函式庫。一旦你了解這一點,一切都會水到渠成。
你不會為 JSON 解析器搭建單獨的伺服器,也不會為正規表示式引擎建立連線池。既然 SQLite 可以當作一個函式庫來處理你的工作負載,為什麼還要為資料庫建立連線池呢?
各大平台都大力支持 SQLite:
Cloudflare 的 Durable Objects 使用 SQLite
Fly.io 的 LiteFS 支援分散式 SQLite
Turso 正在建立分散式 SQLite 平台
甚至 Rails 也力推 SQLite 作為生產預設語言
這些不是玩具專案。它們是服務於數十億請求的生產基礎設施。
在將下一個專案預設使用 Postgres 之前,請問自己:
您每秒真的會有 >1000 次持續寫入嗎?
您是否確實需要多個應用程式伺服器寫入同一個資料庫?
對於您的用例來說,操作複雜性是否值得?
如果你對其中任何一個問題的答案是“否”,那麼請認真考慮 SQLite。它不是作為「真正」資料庫的墊腳石,而是作為你的生產資料庫。
SQLite 中的「精簡」並不意味著它功能不足,而是指它負擔更少。在生產環境中,更少的負擔意味著更快的速度、更高的可靠性和更多的睡眠。
別想太多了。先從 SQLite 開始吧。以後如果真的需要,可以隨時加入複雜性。但很可能你不會這麼做。
我建置了UserJot ,一個回饋管理平台。我們使用 Postgres,原因很簡單:我們需要多伺服器可擴展性,大量依賴 pgvector 進行語義搜尋,使用 LISTEN/NOTIFY 進行即時更新,並跨數百萬個資料點執行複雜的分析查詢。
但我也完全基於 SQLite 建立了一個部落格平台。單一二進位部署,Litestream 複製到 S3,在每月 5 美元的 VPS 上實現了完美的擴展。操作起來非常愉快,正是因為 SQLite 消除了所有的複雜性。
教訓是什麼?我為UserJot選擇了 Postgres,因為我們的具體需求決定了它。對於部落格平台來說,SQLite 顯然是最佳選擇。大多數專案都更像部落格平台,而不是UserJot 。
選擇無趣的技術,但要慎重選擇。
原文出處:https://dev.to/shayy/everyone-is-wrong-about-sqlite-4gjf