h2database 是使用Java 编写的开源数据库,兼容ANSI-SQL89。
即实现了常规基于 BTree 的存储引擎,又支持日志结构存储引擎。功能非常丰富(死锁检测机制、事务特性、MVCC、运维工具等),数据库学习非常好的案例。
本文理论结合实践,通过BTree 索引的设计和实现,更好的理解数据库索引相关的知识点以及优化原理。
BTree 实现类
h2database 默认使用的 MVStore 存储引擎,如果要使用 基于 BTree 的存储引擎,需要特别指定(如下示例代码 jdbcUrl)。
以下是常规存储引擎(BTree 结构) 相关的关键类。
-
org.h2.table.RegularTable
-
org.h2.index.PageBtreeIndex (SQL Index 本体实现)
-
org.h2.store.PageStore (存储层,对接逻辑层和文件系统)
BTree 的数据结构可以从网上查到详细的描述和讲解,不做过多赘述。
需要特别说明的是:PageStore。我们数据查询和优化关键的缓存、磁盘读取、undo log都是由 PageStore 完成。可以看到详细的文档和完整的实现。
BTree add index entry 调用链
提供索引数据新增的调用链。同样的,索引的删除和查询都会涉及到,方便 debug 参考。
-
org.h2.command.dml.Insert#insertRows (Insert SQL 触发数据和索引新增)
-
org.h2.mvstore.db.RegularTable#addRow (处理完的数据Row, 执行新增)
-
org.h2.index.PageBtreeIndex#add (逻辑层增加索引数据)
-
org.h2.index.PageDataIndex#addTry (存储层增加索引数据)
-
org.h2.index.PageDataLeaf#addRowTry (存储层新增实现)
// 示例代码
// CREATE TABLE city (id INT(10) NOT NULL AUTO_INCREMENT, code VARCHAR(40) NOT NULL, name VARCHAR(40) NOT NULL);
public static void main(String[] args) throws SQLException {
// 注意:MV_STORE=false,MVStore is used as default storage
Connection conn = DriverManager.getConnection("jdbc:h2:~/test;MV_STORE=false", "sa", "");
Statement statement = conn.createStatement();
// CREATE INDEX IDX_NAME ON city(code); 添加数据触发 BTree 索引新增
// -- SQL 实例化为:IDX_NAME:16:org.h2.index.PageBtreeIndex
statement.executeUpdate("INSERT INTO city(code,name) values('cch','长春')");
statement.close();
conn.close();
}
Code Insight
结合上述的示例代码,从索引新增的流程实现来了解BTree 索引的特性以及使用的注意事项。从底层实现分析索引的运行,对 SQL 索引使用和优化有进一步认识。
表添加数据
public void addRow(Session session, Row row) {
// MVCC 控制机制,记录和比对当前事务的 id
lastModificationId = database.getNextModificationDataId();
if (database.isMultiVersion()) {
row.setSessionId(session.getId())