数据库索引对于数据查询的重要性不可言喻,所以做者在存储层实现了二级索引,以及利用索引进行扫描的功能。目前仅实现了分区表与非分区表的本地索引(数据与索引共用一个Raft组管理),全局索引及反向索引待之后再实现。数据库
1、存储结构:在介绍索引前先了解一下数据与索引是以何种结构存储于RocksDB内的,每一个节点的RocksDB实例都包含如下两个ColumnFamily,每一个列簇的存储结构以下:api
TableId(with OrderFlag) | EntityId |
---|---|
32bit | 128bit |
Versions | GC Flag | [VersionTS + DataPtr] | [Data [FieldId + Value]] |
---|---|---|---|
15bit | 1 bit | Versions * (64+32bit) | Versions * nbit |
TableId | IndexId | IndexKey Values | None unique index's EntityId |
---|---|---|---|
32bit | 8bit | [FieldId + Value] | 128bit |
与TableCF的Value编码相同。异步
在新建实体模型及修改实体模型时都可添加与删除索引(以下图所示),须要注意的是修改模型时添删索引会启用异步任务变动表结构并重建索引数据(请参考以前的文章:异步结构变动),若是是重建唯一索引可能失败,在实体模型设计器内可查看索引重建状态。在索引重建过程当中或重建失败后利用索引扫描数据会直接报错,告知索引还没有准备好。async
不一样于传统Sql数据库解析Sql后利用索引扫描,服务模型的代码必须明确指定用哪一个索引来查询数据,具体参考如下示例代码如何利用索引扫描数据:ide
public async TaskIndexScan() { //新建索引扫描,范型参数1为实体类型,参数2为索引类型 var q = new IndexScan(); //若是是分区表可经过分区谓词指定分区扫描,非分区表无效 q.Partitions.Equal(t => t.VID, 3); //可指定索引谓词肯定扫描范围 q.Keys.Equal(t => t.VID, 3); //若是是复合索引可指定其余索引谓词 q.Keys.Equal(t => t.Speed, 100); return await q.Take(10).ToListAsync(); }
- 索引谓词目前仅实现了相等性判断,其余如大于、小于等稍后实现
- 索引扫描的附加过滤条件还没有实现
另若是须要插入一批测试数据可参考如下示例代码:工具
public async TaskFillData() { //第一个参数128表示并行任务数,第二个参数表示每一个任务执行次数 //做者虚拟机(I74C8G)执行如下代码约每秒插入13000条记录 return await SimplePerfTest.Run(128, 500, async (i, j) => { var obj = new Entities.VehicleState(i); obj.Speed = j; await EntityStore.SaveAsync(obj); }); }4、本篇小结:
本篇介绍数据及索引的存储结构以及利用索引扫描api来查询数据,下一步做者将实现其余谓词条件,另外实现聚合扫描并优化单分区事务递交。GitHub上的运行时已更新(包括dbscan工具)可供测试。若是您有问题或Bug报告,请留言或提交Issue,另外您的关注与点赞将是做者最大的动力。测试