23843493b87c071ac67bef4ac979eefa145c3bdf
主要改动: - 重构目录结构:合并子目录到根目录,简化项目结构 - 添加完整的查询 API:支持复杂条件查询、字段选择、游标模式 - 实现 LSM-Tree Compaction:7层结构、Score-based策略、后台异步合并 - 添加 Web UI:基于 Lit 的现代化管理界面,支持数据浏览和 Manifest 查看 - 完善文档:添加 README.md 和 examples/webui/README.md 新增功能: - Query Builder:链式查询 API,支持 Eq/Lt/Gt/In/Between/Contains 等操作符 - Web UI 组件:srdb-app、srdb-table-list、srdb-data-view、srdb-manifest-view 等 - 列选择持久化:自动保存到 localStorage - 刷新按钮:一键刷新当前视图 - 主题切换:深色/浅色主题支持 代码优化: - 使用 Go 1.24 新特性:range 7、min()、maps.Copy()、slices.Sort() - 统一组件命名:所有 Web Components 使用 srdb-* 前缀 - CSS 优化:提取共享样式,减少重复代码 - 清理遗留代码:删除未使用的方法和样式
SRDB - Simple Row Database
一个基于 LSM-Tree 的高性能嵌入式数据库,专为时序数据和日志存储设计。
🎯 特性
核心功能
- LSM-Tree 架构 - 高效的写入性能和空间利用率
- MVCC 并发控制 - 支持多版本并发读写
- WAL 持久化 - 写前日志保证数据安全
- 自动 Compaction - 智能的多层级数据合并策略
- 索引支持 - 快速的字段查询能力
- Schema 管理 - 灵活的表结构定义
查询能力
- 链式查询 API - 流畅的查询构建器
- 丰富的操作符 - 支持
=,!=,<,>,IN,BETWEEN,CONTAINS等 - 复合条件 -
AND,OR,NOT逻辑组合 - 字段选择 - 按需加载指定字段,优化性能
- 游标模式 - 惰性加载,支持大数据集遍历
管理工具
- Web UI - 现代化的数据库管理界面
- 命令行工具 - 丰富的诊断和维护工具
- 实时监控 - LSM-Tree 结构和 Compaction 状态可视化
📋 目录
🚀 快速开始
安装
go get code.tczkiot.com/srdb
基本示例
package main
import (
"fmt"
"log"
"code.tczkiot.com/srdb"
)
func main() {
// 1. 打开数据库
db, err := srdb.Open("./data")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 2. 定义 Schema
schema := srdb.NewSchema("users", []srdb.Field{
{Name: "id", Type: srdb.FieldTypeInt64, Indexed: true, Comment: "用户ID"},
{Name: "name", Type: srdb.FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "email", Type: srdb.FieldTypeString, Indexed: true, Comment: "邮箱"},
{Name: "age", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
// 3. 创建表
table, err := db.CreateTable("users", schema)
if err != nil {
log.Fatal(err)
}
// 4. 插入数据
err = table.Insert(map[string]any{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"age": 25,
})
if err != nil {
log.Fatal(err)
}
// 5. 查询数据
rows, err := table.Query().
Eq("name", "Alice").
Gte("age", 18).
Rows()
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 6. 遍历结果
for rows.Next() {
row := rows.Row()
fmt.Printf("User: %v\n", row.Data())
}
}
📖 基本用法
数据库操作
// 打开数据库
db, err := srdb.Open("./data")
// 列出所有表
tables := db.ListTables()
// 获取表
table, err := db.GetTable("users")
// 删除表
err = db.DropTable("users")
// 关闭数据库
db.Close()
表操作
// 插入数据
err := table.Insert(map[string]any{
"name": "Bob",
"age": 30,
})
// 获取单条数据(通过序列号)
row, err := table.Get(seq)
// 删除数据
err := table.Delete(seq)
// 更新数据
err := table.Update(seq, map[string]any{
"age": 31,
})
Schema 定义
schema := srdb.NewSchema("logs", []srdb.Field{
{
Name: "group",
Type: srdb.FieldTypeString,
Indexed: true,
Comment: "日志分组",
},
{
Name: "message",
Type: srdb.FieldTypeString,
Indexed: false,
Comment: "日志内容",
},
{
Name: "timestamp",
Type: srdb.FieldTypeInt64,
Indexed: true,
Comment: "时间戳",
},
})
支持的字段类型:
FieldTypeString- 字符串FieldTypeInt64- 64位整数FieldTypeBool- 布尔值FieldTypeFloat64- 64位浮点数
🔍 查询 API
基本查询
// 等值查询
rows, err := table.Query().Eq("name", "Alice").Rows()
// 范围查询
rows, err := table.Query().
Gte("age", 18).
Lt("age", 60).
Rows()
// IN 查询
rows, err := table.Query().
In("status", []any{"active", "pending"}).
Rows()
// BETWEEN 查询
rows, err := table.Query().
Between("age", 18, 60).
Rows()
字符串查询
// 包含
rows, err := table.Query().Contains("message", "error").Rows()
// 前缀匹配
rows, err := table.Query().StartsWith("email", "admin@").Rows()
// 后缀匹配
rows, err := table.Query().EndsWith("filename", ".log").Rows()
复合条件
// AND 条件
rows, err := table.Query().
Eq("status", "active").
Gte("age", 18).
Rows()
// OR 条件
rows, err := table.Query().
Where(srdb.Or(
srdb.Eq("role", "admin"),
srdb.Eq("role", "moderator"),
)).
Rows()
// 复杂组合
rows, err := table.Query().
Where(srdb.And(
srdb.Eq("status", "active"),
srdb.Or(
srdb.Gte("age", 18),
srdb.Eq("verified", true),
),
)).
Rows()
字段选择
// 只查询指定字段(性能优化)
rows, err := table.Query().
Select("id", "name", "email").
Eq("status", "active").
Rows()
结果处理
// 游标模式(惰性加载)
rows, err := table.Query().Rows()
defer rows.Close()
for rows.Next() {
row := rows.Row()
fmt.Println(row.Data())
}
// 获取第一条
row, err := table.Query().First()
// 获取最后一条
row, err := table.Query().Last()
// 收集所有结果
data := rows.Collect()
// 获取总数
count := rows.Count()
// 扫描到结构体
var users []User
err := rows.Scan(&users)
完整的操作符列表
| 操作符 | 方法 | 说明 |
|---|---|---|
= |
Eq(field, value) |
等于 |
!= |
NotEq(field, value) |
不等于 |
< |
Lt(field, value) |
小于 |
> |
Gt(field, value) |
大于 |
<= |
Lte(field, value) |
小于等于 |
>= |
Gte(field, value) |
大于等于 |
IN |
In(field, values) |
在列表中 |
NOT IN |
NotIn(field, values) |
不在列表中 |
BETWEEN |
Between(field, min, max) |
在范围内 |
NOT BETWEEN |
NotBetween(field, min, max) |
不在范围内 |
CONTAINS |
Contains(field, pattern) |
包含子串 |
NOT CONTAINS |
NotContains(field, pattern) |
不包含子串 |
STARTS WITH |
StartsWith(field, prefix) |
以...开头 |
NOT STARTS WITH |
NotStartsWith(field, prefix) |
不以...开头 |
ENDS WITH |
EndsWith(field, suffix) |
以...结尾 |
NOT ENDS WITH |
NotEndsWith(field, suffix) |
不以...结尾 |
IS NULL |
IsNull(field) |
为空 |
IS NOT NULL |
NotNull(field) |
不为空 |
🌐 Web UI
SRDB 提供了一个功能强大的 Web 管理界面。
启动 Web UI
cd examples/webui
# 基本启动
go run main.go serve
# 自定义配置
go run main.go serve --db /path/to/database --port 3000
# 启用自动数据插入(演示模式)
go run main.go serve --auto-insert
功能特性
- 表管理 - 查看所有表及其 Schema
- 数据浏览 - 分页浏览表数据,支持列选择
- Manifest 查看 - 可视化 LSM-Tree 结构
- 实时监控 - Compaction 状态和统计
- 主题切换 - 深色/浅色主题
- 响应式设计 - 完美适配移动设备
🏗️ 架构设计
LSM-Tree 结构
写入流程:
数据
↓
WAL(持久化)
↓
MemTable(内存)
↓
Immutable MemTable
↓
Level 0 SST(磁盘)
↓
Level 1-6 SST(Compaction)
组件架构
Database
├── Table
│ ├── Schema(表结构)
│ └── Engine(存储引擎)
│ ├── MemTable Manager
│ │ ├── Active MemTable
│ │ └── Immutable MemTables
│ ├── SSTable Manager
│ │ └── SST Files (Level 0-6)
│ ├── WAL Manager
│ │ └── Write-Ahead Log
│ ├── Version Manager
│ │ └── MVCC Versions
│ └── Compaction Manager
│ ├── Picker(选择策略)
│ └── Worker(执行合并)
└── Query Builder
└── Expression Engine
数据流
写入路径:
Insert → WAL → MemTable → Flush → SST Level 0 → Compaction → SST Level 1-6
读取路径:
Query → MemTable → Immutable MemTables → SST Files (Level 0-6)
Compaction 触发:
- Level 0:文件数量 ≥ 4
- Level 1-6:总大小超过阈值
- Score 计算:
size / max_size或file_count / max_files
⚡ 性能特点
写入性能
- 顺序写入 - WAL 和 MemTable 顺序写入,性能极高
- 批量刷盘 - MemTable 达到阈值后批量刷盘
- 异步 Compaction - 后台异步执行,不阻塞写入
读取性能
- 内存优先 - 优先从 MemTable 读取
- Bloom Filter - 快速判断 key 是否存在(TODO)
- 索引加速 - 索引字段快速定位
- 按需加载 - 游标模式惰性加载,节省内存
空间优化
- Snappy 压缩 - SST 文件自动压缩
- 增量合并 - Compaction 只合并必要的文件
- 垃圾回收 - 自动清理过期版本
性能指标(参考)
| 操作 | 性能 |
|---|---|
| 顺序写入 | ~100K ops/s |
| 随机写入 | ~50K ops/s |
| 点查询 | ~10K ops/s |
| 范围扫描 | ~1M rows/s |
注:实际性能取决于硬件配置和数据特征
🛠️ 开发指南
项目结构
srdb/
├── btree.go # B-Tree 索引实现
├── compaction.go # Compaction 管理器
├── database.go # 数据库管理
├── engine.go # 存储引擎核心
├── index.go # 索引管理
├── memtable.go # 内存表
├── query.go # 查询构建器
├── schema.go # Schema 定义
├── sstable.go # SSTable 文件
├── table.go # 表管理
├── version.go # 版本管理(MVCC)
├── wal.go # Write-Ahead Log
├── webui/ # Web UI
│ ├── webui.go # HTTP 服务器
│ └── static/ # 前端资源
└── examples/ # 示例程序
└── webui/ # Web UI 工具
运行测试
# 运行所有测试
go test ./...
# 运行特定测试
go test -v -run TestEngine
# 性能测试
go test -bench=. -benchmem
构建示例
# 构建 WebUI
cd examples/webui
go build -o webui main.go
# 运行
./webui serve --db ./data
📚 文档
🤝 贡献
欢迎提交 Issue 和 Pull Request!
开发流程
- Fork 项目
- 创建特性分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 提交 Pull Request
代码规范
- 遵循 Go 官方代码风格
- 添加必要的注释和文档
- 编写单元测试
- 确保所有测试通过
📝 许可证
MIT License - 详见 LICENSE 文件
🙏 致谢
📧 联系方式
SRDB - 简单、高效、可靠的嵌入式数据库 🚀
Languages
Go
85.2%
JavaScript
13.2%
Makefile
0.8%
CSS
0.6%
HTML
0.2%