原文地址:https://github.com/hash-anu/snkv
SNKV --- 无查询处理器的 SQLite 键值存储
概述
SNKV 是一个轻量级、高性能、ACID 兼容的键值存储 ,直接构建在 SQLite B‑Tree 层 之上。
与通过 SQL 查询使用 SQLite 不同,SNKV 绕过了整个 SQL 处理栈 ,直接调用 SQLite 的 生产就绪的 B‑Tree API 来执行键值操作。
其结果是:一个保留了 SQLite 久经考验的可靠性和持久性 的数据库,同时由于开销显著减少,在混合 KV 工作负载(70% 读,20% 写,10% 删除操作) 上性能 提升约 50%。
设计理念
SQLite 是一个优秀的通用数据库,但对于键值工作负载而言,它带来了显著的开销:
- SQL 解析和编译
- 虚拟机执行
- 查询优化和模式管理
SNKV 完全移除了这些层,只保留对键值存储至关重要的部分。
使用方法
SNKV 公开了一个简单的 C API 用于键值操作,完全不涉及任何 SQL。
一个完整的端到端使用示例在 snkv/main.c 中提供。
该文件演示了:
- 打开数据库
- 创建列族
- 插入 / 查询 / 删除操作
- 事务操作
- 正确清理和关闭
请查阅 示例 以获取有关 API 使用的更多信息。
测试
所有单元测试和基准测试都位于 tests/ 目录中。
架构对比图示
我们移除了哪些层
┌─────────────────────────────────────────────────────────────────────────────┐
│ 我们移除的栈 │
└─────────────────────────────────────────────────────────────────────────────┘
从 SQLite 中移除的层 为什么 SNKV 不需要它们
═══════════════════════ ═══════════════════════════
┌──────────────────────────┐
│ SQL 接口层 │ 无 SQL → 不需要
│ - sqlite3_prepare() │
│ - sqlite3_step() │
│ - sqlite3_bind_*() │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ SQL 编译器 │ 无 SQL → 无需解析或代码生成
│ - 分词器 │
│ - 解析器 │
│ - 代码生成器 │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 虚拟机 │ 无字节码执行
│ - VDBE 执行器 │
│ - 操作码解释器 │
│ - 200+ 操作码 │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ 后端层 │ 无模式或查询规划
│ - 查询优化器 │
│ - 索引管理器 │
│ - 模式管理器 │
└──────────────────────────┘
│
▼
═══════════════════════════════════════════════════
SNKV 保留了什么(保持不变)
SNKV 有意地保留了 SQLite 中经受最多实战考验的部分,且未作改动:
┌──────────────────────────┐ ┌──────────────────────────┐
│ B-树引擎 │ ══════════▶ │ B-树引擎 │
│ (SQLite 已验证代码) │ 保留此项 │ (相同的已验证代码) │
└──────────────────────────┘ └──────────────────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ 分页模块 │ ══════════▶ │ 分页模块 │
│ (缓存,日志) │ 保留此项 │ (相同代码) │
└──────────────────────────┘ └──────────────────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ 操作系统接口 │ ══════════▶ │ 操作系统接口 │
│ (文件 I/O,锁) │ 保留此项 │ (相同代码) │
└──────────────────────────┘ └──────────────────────────┘
这意味着 SNKV 受益于:
- 崩溃安全性(回滚日志)
- 原子提交
- 页面缓存和高效 I/O
- 经过实际测试
清晰的架构图
┌────────────────┐
│ 应用程序 │
└────────┬───────┘
│
│ kvstore_put(key, value)
│ kvstore_get(key) → value
│ kvstore_delete(key)
│ kvstore_begin(), kvstore_commit(), kvstore_rollback(), ...
▼
┌────────────────────────────────┐
│ KVStore 层 │
│ (薄封装 - 约 1600 行代码) │
│ │
│ • 简单 API │
│ • 列族 │
│ • 线程安全(互斥锁) │
│ • 验证 │
│ • 统计 │
└────────────┬───────────────────┘
│
│ 直接调用(无 SQL!)
│
▼
┌────────────────────────────────┐
│ B-树引擎 │
│ (SQLite 3.3.0 - 已验证代码) │
│ │
│ • 树操作 │
│ • 键值存储 │
│ • 游标与导航 │
└────────────┬───────────────────┘
│
│
▼
┌────────────────────────────────┐
│ 分页模块 │
│ (SQLite 3.3.0 - 已验证代码) │
│ │
│ • 事务管理 │
│ • 回滚日志 │
│ • ACID 保证 │
└────────────┬───────────────────┘
│
│
▼
┌────────────────────────────────┐
│ 操作系统接口 │
│ (SQLite 3.3.0 - 已验证代码) │
│ │
│ • 文件 I/O │
│ • 文件锁 │
│ • 崩溃恢复 │
└────────────┬───────────────────┘
│
│
▼
┌──────────────┐
│ 磁盘文件 │
│ │
│ • kvstore.db│
│ • journal │
└──────────────┘
结果
相同的可靠性,更少的层,显著更快的 KV 性能。
- 无 SQL 解析或规划
- 无虚拟机执行
- 直接 B‑Tree 访问
典型收益:
- 更低的内存使用量
- 可预测的延迟
与最新 SQLite 的对比
下表显示了在相同工作负载(50,000 条记录)下,SQLite(基于 SQL 的 KV 访问) 和 SNKV(直接 B‑Tree KV 访问) 各 5 次运行的平均性能。
所有数字均为 每秒操作数。
| 基准测试 | SQLite (平均) | SNKV (平均) | 胜出者 |
|---|---|---|---|
| 顺序写入 | 68,503 | 70,888 | SNKV (+3.5%) |
| 随机读取 | 48,206 | 36,210 | SQLite (+33%) |
| 顺序扫描 | 1,089,049 | 2,173,141 | SNKV (约 2 倍) |
| 随机更新 | 47,339 | 47,297 | 持平 |
| 随机删除 | 31,937 | 44,046 | SNKV (+38%) |
| 存在性检查 | 59,884 | 36,041 | SQLite (+66%) |
| 混合工作负载 (70读/20写/10删) | 50,379 | 78,860 | SNKV (+56%) |
| 批量插入(单事务) | 104,526 | 133,566 | SNKV (+28%) |
关键观察
- SNKV 在写密集和混合工作负载中占优,因为零 SQL/VDBE 开销。
- 顺序扫描在 SNKV 中快约 2 倍,得益于直接游标遍历。
- SQLite 在点查询(读取/存在性检查)中胜出,因为它有高度优化的 VDBE 快速路径和语句缓存。
- 更新性能基本持平(相同的 B‑Tree + 分页路径)。
基准测试代码
- SQLite 基准测试源码:https://github.com/hash-anu/sqlite-benchmark-kv
- SNKV 基准测试源码:
snkv/tests/test_benchmark.c
何时使用 SNKV
SNKV 适用于:
- 嵌入式系统
- 低内存环境
- 配置存储
- 元数据库
- 需要快速 KV 访问的 C/C++ 应用
- 不需要 SQL 的系统
- 以及更多场景
如果你需要连接、即席查询或分析功能 --- 使用 SQLite。
如果你需要 快速、可靠的键值存储 --- 使用 SNKV。
总结
SNKV 证明了一个简单的理念:
如果不需要 SQL,就不要为它付出代价。
通过直接建立在 SQLite 的 B‑Tree 引擎之上,SNKV 交付了一个专注、快速且可靠的键值数据库,同时保持了极低的复杂度。