原文地址: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 交付了一个专注、快速且可靠的键值数据库,同时保持了极低的复杂度。