為什麼需要了解這三種資料儲存技術?
在現代應用開發中,資料儲存策略直接影響系統效能、用戶體驗和開發成本。選擇適當的儲存技術能夠:
- 提升效能:根據存取模式選擇最佳儲存方案,降低延遲
- 降低成本:避免過度配置伺服器資源或頻寬
- 改善用戶體驗:實現離線功能、快速回應、流暢互動
- 簡化架構:選對工具可減少系統複雜度
Redis、SQLite 與 IndexedDB 分別代表三種不同的儲存場景:伺服器端快取、本地端資料庫、瀏覽器端儲存。了解三者的差異與適用情境,能幫助工程師做出正確的技術決策。
三種技術的核心特性
Redis:高效能記憶體資料庫
技術背景:
Redis(Remote Dictionary Server)是開源的記憶體鍵值資料庫,以其極高的讀寫效能聞名。所有資料存放在記憶體中,支援可選的磁碟持久化機制。
核心特性:
- 多樣資料結構:支援 String、Hash、List、Set、Sorted Set 等
- 原子操作:所有操作都是原子性的,確保資料一致性
- 高效能:讀寫速度可達每秒數萬至數十萬次操作
- 持久化選項:RDB 快照與 AOF 日誌兩種機制
- 主從複製:支援資料複製與高可用性配置
- Pub/Sub 訊息:內建發布/訂閱機制
適用場景:
- Session 管理:儲存用戶登入狀態
- 快取層:減少資料庫查詢負擔
- 排行榜:使用 Sorted Set 實現即時排名
- 計數器:網頁瀏覽次數、API 呼叫限流
- 即時訊息:聊天室、通知推送
限制與注意事項:
- 記憶體成本:所有資料存於記憶體,成本較磁碟高
- 單執行緒:雖然效能優異,但單一指令執行時間過長會阻塞其他請求
- 資料量限制:受限於伺服器記憶體容量
- 持久化取捨:RDB 可能遺失最近幾分鐘的資料,AOF 會影響寫入效能
SQLite:輕量級嵌入式資料庫
技術背景:
SQLite 是完全嵌入式的關聯式資料庫,資料儲存在單一檔案中,不需要獨立的資料庫伺服器。支援完整的 SQL 語法,廣泛應用於行動應用與桌面軟體。
核心特性:
- 零配置:無需安裝或設定,直接使用
- 完整 SQL 支援:支援 JOIN、Transaction、View、Trigger 等
- ACID 保證:確保交易的原子性、一致性、隔離性、持久性
- 跨平台:支援 Windows、macOS、Linux、iOS、Android
- 小巧輕量:函式庫大小僅數百 KB
- 可靠穩定:經過大量測試,廣泛應用於生產環境
適用場景:
- 行動應用:iOS、Android App 的本地資料儲存
- 桌面軟體:配置檔案、用戶資料管理
- 嵌入式系統:IoT 裝置、車載系統
- 原型開發:快速驗證資料模型
- 小型網站:低流量網站的資料庫
限制與注意事項:
- 並行寫入:同時間只允許一個寫入操作
- 資料量限制:建議單一資料庫不超過數 GB(理論上限 281 TB)
- 網路存取:不適合用於網路檔案系統(NFS)
- 複雜查詢:大量 JOIN 操作效能不如專業資料庫
IndexedDB:瀏覽器端結構化儲存
技術背景:
IndexedDB 是瀏覽器提供的客戶端資料庫 API,支援儲存大量結構化資料,並提供索引功能以實現高效查詢。採用非同步 API 設計,不會阻塞主執行緒。
核心特性:
- 大容量儲存:通常可儲存數百 MB 至數 GB 資料
- 索引支援:可建立多個索引加速查詢
- 交易機制:確保資料操作的一致性
- 非同步 API:避免阻塞 UI 渲染
- 跨分頁共享:同源的多個分頁可存取相同資料
- 鍵值與物件儲存:支援 JavaScript 物件直接儲存
適用場景:
- 離線優先應用:Progressive Web App (PWA) 的資料快取
- 大型表單:暫存草稿,避免資料遺失
- 資料同步:本地快取伺服器資料,減少網路請求
- 多媒體內容:儲存圖片、音訊的元資料與索引
- 遊戲狀態:瀏覽器遊戲的存檔功能
限制與注意事項:
- 瀏覽器相容性:需檢查目標瀏覽器支援度
- API 複雜度:使用較 localStorage 複雜,需處理回呼或 Promise
- 安全性:受同源政策限制,但仍可能被 XSS 攻擊存取
- 容量限制:各瀏覽器實作不同,可能在低儲存空間時被清除
- 無 SQL 支援:查詢功能較關聯式資料庫簡單
詳細比較表格
| 比較項目 | Redis | SQLite | IndexedDB |
|---|---|---|---|
| 資料模型 | 鍵值對 + 多種資料結構 | 關聯式(表格、欄位、索引) | 鍵值對 + 物件儲存 + 索引 |
| 查詢語言 | Redis 指令集 | 標準 SQL | JavaScript API(無 SQL) |
| 交易支援 | 有(MULTI/EXEC) | 完整 ACID 交易 | 有(Transaction API) |
| 持久化 | 可選(RDB、AOF) | 預設持久化至檔案 | 預設持久化至瀏覽器儲存 |
| 並行處理 | 單執行緒 + 多工處理 | 多讀單寫 | 依瀏覽器實作 |
| 典型容量 | 數 GB(記憶體限制) | 數 GB ~ 數十 GB | 50MB ~ 數 GB(依瀏覽器) |
| 讀取效能 | 極高(微秒等級) | 高(毫秒等級) | 中等(依資料量與索引) |
| 寫入效能 | 極高 | 中等(受鎖定機制影響) | 中等 |
| 資料安全性 | 網路傳輸需加密 | 檔案權限保護 | 同源政策隔離 |
| 部署複雜度 | 需獨立伺服器 | 無需部署(嵌入式) | 無需部署(瀏覽器內建) |
| 開發難度 | 中等 | 低(熟悉 SQL 即可) | 中高(API 較複雜) |
| 維護成本 | 需監控與調校 | 幾乎無維護成本 | 無維護成本 |
實務應用案例
案例一:電商網站的 Session 管理(Redis)
需求:
電商平台需要管理數萬個同時在線用戶的 Session,包含購物車、登入狀態、瀏覽紀錄等。
為何選擇 Redis:
- 高並發讀寫能力,應對促銷活動的流量尖峰
- 支援 Session 自動過期(TTL 機制)
- 主從複製確保高可用性
- 跨伺服器共享 Session,支援水平擴展
實作重點:
# 設定 Session(30 分鐘過期)
SET session:user123 "{"cart":[1,2,3],"logged_in":true}" EX 1800
# 讀取 Session
GET session:user123
# 延長 Session 時效
EXPIRE session:user123 1800
案例二:筆記 App 的離線儲存(SQLite)
需求:
行動筆記應用需要在離線狀態下正常運作,儲存筆記內容、分類、標籤、附件等結構化資料。
為何選擇 SQLite:
- 完整的關聯式資料庫功能,支援複雜查詢
- ACID 保證,確保資料不會因 App 崩潰而損毀
- 跨平台支援,iOS 與 Android 共用相同程式碼
- 無需網路連線,完全本地運作
實作重點:
-- 建立筆記表
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 建立標籤表
CREATE TABLE tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL
);
-- 建立筆記-標籤關聯表
CREATE TABLE note_tags (
note_id INTEGER,
tag_id INTEGER,
FOREIGN KEY (note_id) REFERENCES notes(id),
FOREIGN KEY (tag_id) REFERENCES tags(id),
PRIMARY KEY (note_id, tag_id)
);
-- 查詢包含特定標籤的筆記
SELECT n.* FROM notes n
JOIN note_tags nt ON n.id = nt.note_id
JOIN tags t ON nt.tag_id = t.id
WHERE t.name = '工作';
案例三:PWA 離線地圖應用(IndexedDB)
需求:
Progressive Web App 地圖服務需要快取地圖圖磚、地點資訊、使用者標記,實現離線瀏覽功能。
為何選擇 IndexedDB:
- 可儲存大量二進制資料(地圖圖片)
- 索引功能支援快速查詢特定地理範圍的資料
- 非同步 API 不影響地圖互動流暢度
- 無需伺服器端支援,完全在瀏覽器運作
實作重點:
// 開啟資料庫
const request = indexedDB.open('MapDatabase', 1);
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 建立圖磚儲存區
const tileStore = db.createObjectStore('tiles', { keyPath: 'id' });
tileStore.createIndex('zoom', 'zoom', { unique: false });
tileStore.createIndex('coordinates', ['x', 'y'], { unique: false });
// 建立地點儲存區
const placeStore = db.createObjectStore('places', { keyPath: 'id' });
placeStore.createIndex('category', 'category', { unique: false });
};
// 儲存地圖圖磚
function saveTile(db, tile) {
const transaction = db.transaction(['tiles'], 'readwrite');
const store = transaction.objectStore('tiles');
store.put(tile);
}
// 查詢特定縮放等級的圖磚
function getTilesByZoom(db, zoom) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['tiles'], 'readonly');
const store = transaction.objectStore('tiles');
const index = store.index('zoom');
const request = index.getAll(zoom);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
選擇決策流程圖
快速決策步驟:
- 確認運行環境
- 伺服器端 → 考慮 Redis 或其他伺服器資料庫
- 客戶端應用(App)→ 考慮 SQLite
- 瀏覽器端 → 考慮 IndexedDB
- 評估資料特性
- 需要超高速讀寫 → Redis
- 需要複雜 SQL 查詢 → SQLite
- 需要大容量瀏覽器儲存 → IndexedDB
- 考量資料持久性
- 臨時資料、快取 → Redis
- 長期儲存、關鍵資料 → SQLite 或後端資料庫
- 離線優先應用 → IndexedDB
- 預估資料量與流量
- 高並發、小資料量 → Redis
- 中等流量、結構化資料 → SQLite
- 前端資料快取 → IndexedDB
最佳實踐建議
Redis 最佳實踐
- 設定適當的過期時間:避免記憶體浪費,使用 EXPIRE 或 SETEX 指令
- 監控記憶體使用:設定 maxmemory 與淘汰策略(如 allkeys-lru)
- 避免大 key:單一鍵值不應超過 10MB,考慮拆分資料
- 使用 Pipeline:批次操作減少網路往返次數
- 正確選擇資料結構:例如計數器用 String,排行榜用 Sorted Set
- 啟用持久化:生產環境建議同時使用 RDB 與 AOF
- 主從複製:至少配置一個從節點,確保高可用性
SQLite 最佳實踐
- 使用 WAL 模式:提升並發讀取效能(PRAGMA journal_mode=WAL)
- 建立適當索引:加速常用查詢,但避免過多索引影響寫入
- 使用交易:批次寫入時使用 BEGIN/COMMIT 包裹,提升效能
- 定期 VACUUM:清理碎片,回收空間
- 避免在 NFS 使用:網路檔案系統可能導致檔案鎖定問題
- 備份策略:定期複製資料庫檔案或使用 .backup 指令
- 限制資料庫大小:單一資料庫建議不超過數 GB
IndexedDB 最佳實踐
- 使用 Promise 包裝:簡化非同步操作,可使用 idb 函式庫
- 建立適當索引:加速查詢,但每個索引都會增加儲存空間
- 處理版本升級:onupgradeneeded 中謹慎處理結構變更
- 錯誤處理:始終處理 onerror 與 onblocked 事件
- 批次操作:使用單一交易處理多筆資料,提升效能
- 清理過期資料:定期刪除不需要的快取資料
- 檢查瀏覽器支援:使用 feature detection 確保相容性
- 考慮容量限制:檢查可用空間,處理 QuotaExceededError
常見問題 FAQ
Q1: Redis 適合當作主要資料庫使用嗎?
A: 通常不建議。Redis 主要設計為快取與高速資料存取層,雖然支援持久化,但以下原因使其較不適合作為主資料庫:
- 記憶體成本高,儲存大量資料不經濟
- 持久化機制有資料遺失風險(RDB 可能遺失數分鐘資料)
- 缺乏複雜查詢能力(無 JOIN、無完整 SQL)
- 單執行緒架構在某些場景可能成為瓶頸
建議搭配傳統關聯式或 NoSQL 資料庫使用,Redis 作為快取層或特定功能(如排行榜、Session)的儲存。
Q2: SQLite 能承受多大的並發量?
A: SQLite 採用檔案鎖定機制,並發寫入能力有限:
- 讀取:支援多個程序同時讀取
- 寫入:同時間只允許一個寫入操作
- WAL 模式:讀寫可同時進行,但寫寫仍互斥
適用場景建議:
- ✅ 讀多寫少的應用(如內容管理系統)
- ✅ 單用戶應用(桌面軟體、行動 App)
- ✅ 低流量網站(每日數千至數萬次請求)
- ❌ 高並發寫入(建議使用 MySQL、PostgreSQL)
- ❌ 多伺服器環境(需要集中式資料庫)
Q3: IndexedDB 的資料會被瀏覽器清除嗎?
A: 可能會,取決於以下因素:
- 儲存空間不足:瀏覽器可能清除 IndexedDB 資料以釋放空間
- 用戶操作:清除瀏覽資料時會一併刪除 IndexedDB
- 持久化儲存 API:可要求瀏覽器不自動清除資料
建議做法:
// 請求持久化儲存權限
if (navigator.storage && navigator.storage.persist) {
navigator.storage.persist().then(granted => {
if (granted) {
console.log('資料將不會被自動清除');
} else {
console.log('瀏覽器可能在空間不足時清除資料');
}
});
}
// 檢查目前儲存狀態
navigator.storage.persisted().then(isPersisted => {
console.log('持久化狀態:', isPersisted);
});
Q4: 如何在 Redis、SQLite 與 IndexedDB 之間選擇?
A: 根據應用場景快速決策:
| 需求 | 建議技術 | 理由 |
|---|---|---|
| Session 管理、API 限流 | Redis | 高並發、支援過期時間 |
| 行動 App 本地資料 | SQLite | 完整 SQL、ACID 保證 |
| PWA 離線功能 | IndexedDB | 大容量、瀏覽器原生支援 |
| 即時排行榜 | Redis | Sorted Set 高效排序 |
| 嵌入式系統資料庫 | SQLite | 輕量級、無需伺服器 |
| 大型表單暫存 | IndexedDB | 避免伺服器頻繁請求 |
| 分散式快取 | Redis | 支援主從複製、Cluster |
Q5: 可以同時使用多種儲存技術嗎?
A: 可以,且這是常見的最佳實踐。混合使用範例:
- 電商平台:
- Redis:Session、購物車、熱門商品快取
- MySQL:訂單、商品、用戶主資料
- IndexedDB:用戶瀏覽紀錄、草稿
- 筆記應用:
- SQLite:App 本地資料庫
- PostgreSQL:雲端同步資料
- Redis:即時協作狀態
- 地圖服務:
- IndexedDB:地圖圖磚快取
- Redis:即時路況資料
- PostgreSQL + PostGIS:地理資料主庫
關鍵是根據資料特性(讀寫頻率、資料量、持久性需求)選擇合適的技術。
Q6: Redis 的記憶體資料遺失時會怎樣?
A: 影響取決於持久化配置:
- 無持久化:重啟後所有資料消失,僅適合純快取場景
- RDB 快照:恢復到最後一次快照時間點,可能遺失數分鐘至數小時資料
- AOF 日誌:
- appendfsync always:幾乎不遺失,但效能最差
- appendfsync everysec:最多遺失1秒資料(建議設定)
- appendfsync no:由作業系統決定,可能遺失較多資料
- RDB + AOF:結合兩者優點,恢復時優先使用 AOF
生產環境建議:
# redis.conf 設定
save 900 1 # 900 秒內至少 1 次變更則快照
save 300 10 # 300 秒內至少 10 次變更則快照
save 60 10000 # 60 秒內至少 10000 次變更則快照
appendonly yes # 啟用 AOF
appendfsync everysec # 每秒同步一次
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
Q7: IndexedDB 與 localStorage 有什麼差別?
A: 兩者都是瀏覽器端儲存,但特性大不相同:
| 特性 | IndexedDB | localStorage |
|---|---|---|
| 儲存容量 | 50MB ~ 數 GB | 5 ~ 10 MB |
| 資料型態 | 物件、陣列、二進制 | 僅字串 |
| 查詢功能 | 索引、範圍查詢 | 僅鍵值查詢 |
| API 設計 | 非同步 | 同步 |
| 交易支援 | 有 | 無 |
| 效能 | 大資料量下較優 | 小資料量下較簡單 |
| 使用難度 | 中高 | 低 |
選擇建議:
- ✅ localStorage:儲存簡單設定、小量使用者偏好
- ✅ IndexedDB:離線資料、大量快取、結構化資料
總結與選擇建議
Redis、SQLite 與 IndexedDB 各有其最佳應用場景,選擇時應考慮:
- 運行環境:伺服器、客戶端應用或瀏覽器
- 資料特性:結構化程度、資料量、存取模式
- 效能需求:並發量、延遲要求、讀寫比例
- 持久性需求:臨時快取或長期儲存
- 開發與維護成本:團隊技術棧、運維能力
核心原則:
- Redis:追求極致效能的伺服器端快取與即時資料處理
- SQLite:需要完整 SQL 功能的本地端、嵌入式場景
- IndexedDB:瀏覽器端大容量資料儲存與離線功能
實務上,多數複雜應用會混合使用多種儲存技術,各司其職,發揮最大效益。正確的技術選擇能顯著提升系統效能、降低成本、改善用戶體驗。
Related Articles
- Data Storage Technologies Comparison: Redis, SQLite, and IndexedDB
- Deep Dive into Redis: Data Structures and CRUD Operations Complete Guide
- Optimize Performance with AWS Cache Solutions: Memcached vs Redis Comparison
- Azure SQL Post-Migration Performance Optimization: Query Statistics, Top SQL Analysis, and Index Tuning Guide
- Quartz Data Persistence Complete Guide: Configuration, Advantages & Best Practices