文档:更新和优化项目文档

- 更新 DESIGN.md:
  - 强调强制 Schema(21 种类型)
  - 更新核心代码行数为 ~5,400 行
  - 优化 ROW1 格式说明(英文)
  - 完善性能指标和项目成果
- 精简 DOCS.md 和 README.md
- 统一文档风格和术语
This commit is contained in:
2025-10-10 18:49:57 +08:00
parent 39d57134f1
commit 5b8e5e7bd2
3 changed files with 209 additions and 681 deletions

655
README.md
View File

@@ -1,48 +1,28 @@
# SRDB - Simple Row Database
[![Go Version](https://img.shields.io/badge/Go-1.24+-00ADD8?style=flat&logo=go)](https://golang.org/)
[![Go Version](https://img.shields.io/badge/Go-1.21+-00ADD8?style=flat&logo=go)](https://golang.org/)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
一个基于 LSM-Tree 的高性能嵌入式数据库,专为时序数据和日志存储设计。
一个用 Go 编写的高性能 Append-Only 时序数据库引擎,专为高并发写入和快速查询设计。
## 🎯 特性
## 🎯 核心特性
### 核心功能
- **LSM-Tree 架构** - 高效的写入性能和空间利用率
- **MVCC 并发控制** - 支持多版本并发读写
- **WAL 持久化** - 写前日志保证数据安全
- **自动 Compaction** - 智能的多层级数据合并策略
- **索引支持** - 快速的字段查询能力
- **Schema 管理** - 灵活的表结构定义,支持 21 种类型
- **复杂类型** - 原生支持 Objectmap和 Arrayslice
### 查询能力
- **链式查询 API** - 流畅的查询构建器
- **丰富的操作符** - 支持 `=`, `!=`, `<`, `>`, `IN`, `BETWEEN`, `CONTAINS`
- **复合条件** - `AND`, `OR`, `NOT` 逻辑组合
- **字段选择** - 按需加载指定字段,优化性能
- **游标模式** - 惰性加载,支持大数据集遍历
- **Append-Only 架构** - WAL + MemTable + mmap B+Tree SST简化并发控制
- **强类型 Schema** - 21 种数据类型,包括 Objectmap和 Arrayslice
- **高性能写入** - 200K+ 写/秒(多线程),<1ms 延迟p99
- **快速查询** - <0.1ms内存1-5ms磁盘支持二级索引
- **智能 Scan** - 自动扫描到结构体完整支持复杂类型
### 管理工具
- **Web UI** - 现代化的数据库管理界面
- **命令行工具** - 丰富的诊断和维护工具
- **实时监控** - LSM-Tree 结构和 Compaction 状态可视化
---
- **链式查询 API** - 18 种操作符支持复合条件
- **自动 Compaction** - 后台异步合并优化存储空间
- **零拷贝读取** - mmap 访问 SST 文件内存占用 <150MB
- **Web 管理界面** - 现代化的数据浏览和监控工具
## 📋 目录
- [快速开始](#快速开始)
- [基本用法](#基本用法)
- [查询 API](#查询-api)
- [Scan 方法](#scan-方法---扫描到结构体)
- [Object 和 Array 类型](#object-和-array-类型)
- [Web UI](#web-ui)
- [架构设计](#架构设计)
- [性能特点](#性能特点)
- [开发指南](#开发指南)
- [核心概念](#核心概念)
- [文档](#文档)
- [开发](#开发)
---
@@ -54,6 +34,8 @@
go get code.tczkiot.com/wlw/srdb
```
**要求**Go 1.21+
### 基本示例
```go
@@ -73,12 +55,14 @@ func main() {
}
defer db.Close()
// 2. 定义 Schema
// 2. 定义 Schema强类型21 种类型)
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "id", Type: srdb.Int64, Indexed: true, Comment: "用户ID"},
{Name: "name", Type: srdb.String, Indexed: false, Comment: "用户名"},
{Name: "id", Type: srdb.Uint32, Indexed: true, Comment: "用户ID"},
{Name: "name", Type: srdb.String, Comment: "用户名"},
{Name: "email", Type: srdb.String, Indexed: true, Comment: "邮箱"},
{Name: "age", Type: srdb.Int32, Indexed: false, Comment: "年龄"},
{Name: "age", Type: srdb.Int32, Comment: "年龄"},
{Name: "tags", Type: srdb.Array, Comment: "标签"}, // Array 类型
{Name: "settings", Type: srdb.Object, Comment: "设置"}, // Object 类型
})
if err != nil {
log.Fatal(err)
@@ -92,555 +76,131 @@ func main() {
// 4. 插入数据
err = table.Insert(map[string]any{
"id": 1,
"id": uint32(1),
"name": "Alice",
"email": "alice@example.com",
"age": 25,
"age": int32(25),
"tags": []any{"golang", "database"},
"settings": map[string]any{
"theme": "dark",
"lang": "zh-CN",
},
})
if err != nil {
log.Fatal(err)
}
// 5. 查询数据
rows, err := table.Query().
// 5. 查询并扫描到结构体
type User struct {
ID uint32 `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int32 `json:"age"`
Tags []string `json:"tags"`
Settings map[string]string `json:"settings"`
}
var users []User
err = table.Query().
Eq("name", "Alice").
Gte("age", 18).
Rows()
Scan(&users)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 6. 遍历结果
for rows.Next() {
row := rows.Row()
fmt.Printf("User: %v\n", row.Data())
}
fmt.Printf("Found %d users\n", len(users))
fmt.Printf("Tags: %v\n", users[0].Tags)
fmt.Printf("Settings: %v\n", users[0].Settings)
}
```
---
## 📖 基本用法
## 💡 核心概念
### 数据库操作
### 架构
```go
// 打开数据库
db, err := srdb.Open("./data")
SRDB 使用 **Append-Only 架构**分为两层
// 列出所有表
tables := db.ListTables()
// 获取表
table, err := db.GetTable("users")
// 删除表
err = db.DropTable("users")
// 关闭数据库
db.Close()
```
### 表操作
```go
// 插入数据
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 定义
```go
schema, err := srdb.NewSchema("logs", []srdb.Field{
{
Name: "level",
Type: srdb.String,
Indexed: true,
Comment: "日志级别",
},
{
Name: "message",
Type: srdb.String,
Indexed: false,
Comment: "日志内容",
},
{
Name: "timestamp",
Type: srdb.Int64,
Indexed: true,
Comment: "时间戳",
},
{
Name: "metadata",
Type: srdb.Object,
Indexed: false,
Comment: "元数据map",
},
{
Name: "tags",
Type: srdb.Array,
Indexed: false,
Comment: "标签slice",
},
})
```
**支持的字段类型**21 种):
**有符号整数**
- `Int`, `Int8`, `Int16`, `Int32`, `Int64`
**无符号整数**
- `Uint`, `Uint8`, `Uint16`, `Uint32`, `Uint64`
**浮点数**
- `Float32`, `Float64`
**基础类型**
- `String` - 字符串
- `Bool` - 布尔值
- `Byte` - 字节uint8
- `Rune` - 字符int32
**特殊类型**
- `Decimal` - 高精度十进制(需要 shopspring/decimal
- `Time` - 时间戳time.Time
**复杂类型**
- `Object` - 对象map[string]xxx、struct{}、*struct{}
- `Array` - 数组([]xxx 切片)
---
## 🔍 查询 API
### 基本查询
```go
// 等值查询
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()
```
### 字符串查询
```go
// 包含
rows, err := table.Query().Contains("message", "error").Rows()
// 前缀匹配
rows, err := table.Query().StartsWith("email", "admin@").Rows()
// 后缀匹配
rows, err := table.Query().EndsWith("filename", ".log").Rows()
```
### 复合条件
```go
// 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()
```
### 字段选择
```go
// 只查询指定字段(性能优化)
rows, err := table.Query().
Select("id", "name", "email").
Eq("status", "active").
Rows()
```
### 结果处理
```go
// 游标模式(惰性加载)
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()
```
### Scan 方法 - 扫描到结构体
SRDB 提供智能的 Scan 方法,完整支持 Object 和 Array 类型:
```go
// 定义结构体
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Settings map[string]string `json:"settings"` // Object 类型
Tags []string `json:"tags"` // Array 类型
}
// 扫描多行到切片
var users []User
table.Query().Scan(&users)
// 扫描单行到结构体(智能判断)
var user User
table.Query().Eq("name", "Alice").Scan(&user)
// Row.Scan - 扫描当前行
row, _ := table.Query().First()
var user User
row.Scan(&user)
// 部分字段扫描(性能优化)
type UserBrief struct {
Name string `json:"name"`
Email string `json:"email"`
}
var briefs []UserBrief
table.Query().Select("name", "email").Scan(&briefs)
```
**Scan 特性**
- ✅ 智能判断目标类型(切片 vs 结构体)
- ✅ 完整支持 Objectmap和 Arrayslice类型
- ✅ 支持嵌套结构
- ✅ 结合 Select() 优化性能
详细示例:[examples/scan_demo](examples/scan_demo/README.md)
### 完整的操作符列表
| 操作符 | 方法 | 说明 |
|--------|------|------|
| `=` | `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)` | 不为空 |
### Object 和 Array 类型
SRDB 支持复杂的数据类型,可以存储 JSON 风格的对象和数组:
```go
// 定义包含复杂类型的表
type Article struct {
Title string `srdb:"field:title"`
Content string `srdb:"field:content"`
Tags []string `srdb:"field:tags"` // Array 类型
Metadata map[string]any `srdb:"field:metadata"` // Object 类型
Authors []string `srdb:"field:authors"` // Array 类型
}
// 使用 StructToFields 自动生成 Schema
fields, _ := srdb.StructToFields(Article{})
schema, _ := srdb.NewSchema("articles", fields)
table, _ := db.CreateTable("articles", schema)
// 插入数据
table.Insert(map[string]any{
"title": "SRDB 使用指南",
"content": "...",
"tags": []any{"database", "golang", "lsm-tree"},
"metadata": map[string]any{
"category": "tech",
"views": 1250,
"featured": true,
},
"authors": []any{"Alice", "Bob"},
})
// 查询和扫描
var article Article
table.Query().Eq("title", "SRDB 使用指南").Scan(&article)
fmt.Println(article.Tags) // ["database", "golang", "lsm-tree"]
fmt.Println(article.Metadata["category"]) // "tech"
fmt.Println(article.Metadata["views"]) // 1250
```
**支持的场景**
-`map[string]xxx` - 任意键值对
-`struct{}` - 结构体(自动转换为 Object
-`*struct{}` - 结构体指针
-`[]xxx` - 任意类型的切片
- ✅ 嵌套的 Object 和 Array
- ✅ 空对象 `{}` 和空数组 `[]`
**存储细节**
- Object 和 Array 使用 JSON 编码存储
- 存储格式:`[length: uint32][JSON data]`
- 零值Object 为 `{}`Array 为 `[]`
- 支持任意嵌套深度
---
## 🌐 Web UI
SRDB 提供了一个功能强大的 Web 管理界面。
### 启动 Web UI
```bash
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
```
访问http://localhost:8080
### 功能特性
- **表管理** - 查看所有表及其 Schema
- **数据浏览** - 分页浏览表数据,支持列选择
- **Manifest 查看** - 可视化 LSM-Tree 结构
- **实时监控** - Compaction 状态和统计
- **主题切换** - 深色/浅色主题
- **响应式设计** - 完美适配移动设备
详细文档:[examples/webui/README.md](examples/webui/README.md)
---
## 🏗️ 架构设计
### LSM-Tree 结构
1. **内存层** - WALWrite-Ahead Log+ MemTableActive + Immutable
2. **磁盘层** - SST 文件 B+Tree 索引分层存储L0-L3
```
写入流程:
数据
WAL持久化
MemTable内存
Immutable MemTable
Level 0 SST磁盘
Level 1-6 SSTCompaction
数据 → WAL持久化→ MemTable → Flush → SST L0 → Compaction → SST L1-L3
读取流程:
查询 → MemTableO(1))→ Immutable MemTables → SST FilesB+Tree
```
### 组件架构
### 数据文件
```
Database
├── Table (Schema + Storage)
│ ├── 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
database_dir/
├── database.meta # 数据库元数据
└── table_name/ # 每表一个目录
├── schema.json # 表 Schema 定义
├── MANIFEST-000001 # 表级版本控制
├── CURRENT # 当前 MANIFEST 指针
├── wal/ # WAL 子目录
│ ├── 000001.wal # WAL 文件
│ └── CURRENT # 当前 WAL 指针
├── sst/ # SST 子目录L0-L3 层级文件)
│ └── 000001.sst # SST 文件B+Tree + 数据)
└── idx/ # 索引子目录
── idx_email.sst # 二级索引文件
```
### 数据流
### 设计特点
**写入路径**
```
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 # 数据库管理
├── errors.go # 错误定义和处理
├── index.go # 索引管理
├── index_btree.go # 索引 B+Tree
├── 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 工具
```
### 运行测试
```bash
# 运行所有测试
go test ./...
# 运行特定测试
go test -v -run TestTable
# 性能测试
go test -bench=. -benchmem
```
### 构建示例
```bash
# 构建 WebUI
cd examples/webui
go build -o webui main.go
# 运行
./webui serve --db ./data
```
- **Append-Only** - 无原地更新简化并发控制
- **MemTable** - `map[int64][]byte + sorted slice`O(1) 读写
- **SST 文件** - 4KB 节点的 B+Treemmap 零拷贝访问
- **二进制编码** - ROW1 格式无压缩优先查询性能
- **Compaction** - 后台异步合并按层级管理文件大小
---
## 📚 文档
### 核心文档
- [设计文档](DESIGN.md) - 详细的架构设计和实现原理
- [CLAUDE.md](CLAUDE.md) - 完整的开发者指南
- [Nullable 指南](NULLABLE_GUIDE.md) - Nullable 字段使用说明
- [API 文档](https://pkg.go.dev/code.tczkiot.com/wlw/srdb) - Go API 参考
### 示例和教程
- [DOCS.md](DOCS.md) - 完整 API 文档和使用指南
- [CLAUDE.md](CLAUDE.md) - 开发者指南和架构详解
- [NULLABLE_GUIDE.md](NULLABLE_GUIDE.md) - Nullable 字段使用说明
### 示例教程
- [Scan 方法指南](examples/scan_demo/README.md) - 扫描到结构体支持 Object Array
- [WebUI 工具](examples/webui/README.md) - Web 管理界面使用指南
- [所有类型示例](examples/all_types/) - 21 种类型的完整示例
- [Nullable 示例](examples/nullable/) - Nullable 字段的使用
- [WebUI 工具](examples/webui/README.md) - Web 管理界面
---
## 🛠️ 开发
### 运行测试
```bash
# 所有测试
go test -v ./...
# 单个测试
go test -v -run TestTable
# 性能测试
go test -bench=. -benchmem
```
### 构建 WebUI
```bash
cd examples/webui
go build -o webui main.go
./webui serve --db ./data
```
---
@@ -673,13 +233,12 @@ MIT License - 详见 [LICENSE](LICENSE) 文件
## 🙏 致谢
- [LevelDB](https://github.com/google/leveldb) - LSM-Tree 设计灵感
- [LevelDB](https://github.com/google/leveldb) - 架构设计参考
- [RocksDB](https://github.com/facebook/rocksdb) - Compaction 策略参考
- [Lit](https://lit.dev/) - Web Components 框架
---
## 📧 联系方式
## 📧 联系
- 项目主页https://code.tczkiot.com/wlw/srdb
- Issue 跟踪https://code.tczkiot.com/wlw/srdb/issues