执行过程先分析select语句的解析过程:
select语句的解析集中在ParserDQL类的XreadQueryExpression方法中,其中XreadQueryExpressionBody select除了limit,offset,fetch关键字外的其他条件解析,XreadOrderByExpression是limit,offset,fetch,ordre by的解析,我们分析简单的select * from user where * order by * limit 2 offset 5 这种语句,对于嵌套子查询和联合查询待会简单过下。
QueryExpression queryExpression = XreadQueryExpressionBody(); SortAndSlice sortAndSlice = XreadOrderByExpression(); if (queryExpression.sortAndSlice == null) { queryExpression.addSortAndSlice(sortAndSlice); } else { if (queryExpression.sortAndSlice.hasLimit()) { if (sortAndSlice.hasLimit()) { throw Error.error(ErrorCode.X_42549); } for (int i = 0; i < sortAndSlice.exprList.size(); i++) { Expression e = (Expression) sortAndSlice.exprList.get(i); queryExpression.sortAndSlice.addOrderExpression(e); } } else { queryExpression.addSortAndSlice(sortAndSlice); } }
selelct top 20 和limit 20这种条件先查询,XreadTopOrLimit读取top和limit的值并作为一个条件放到SortAndSlice对象中,XreadFromClause是读取嵌套查询或者联合查询的,readWhereGroupHaving是处理where条件和group by,having的
QuerySpecification XreadQuerySpecification() { QuerySpecification select = XreadSelect(); if (!select.isValueList) { XreadTableExpression(select); } return select; } void XreadTableExpression(QuerySpecification select) { XreadFromClause(select); readWhereGroupHaving(select); }
如果有DISTINCT,则设置isDistinctSelect为true,while 循环处理每个token,XreadValueExpression 是读取对于返回的列名(包括对改列进行的一些加减等计算操作)
QuerySpecification XreadSelect() { QuerySpecification select = new QuerySpecification(compileContext); readThis(Tokens.SELECT); if (token.tokenType == Tokens.TOP || token.tokenType == Tokens.LIMIT) { SortAndSlice sortAndSlice = XreadTopOrLimit(); if (sortAndSlice != null) { select.addSortAndSlice(sortAndSlice); } } if (token.tokenType == Tokens.DISTINCT) { select.isDistinctSelect = true; read(); } else if (token.tokenType == Tokens.ALL) { read(); } while (true) { Expression e = XreadValueExpression(); if (token.tokenType == Tokens.AS) { read(); checkIsNonCoreReservedIdentifier(); } if (isNonCoreReservedIdentifier()) { e.setAlias(HsqlNameManager.getSimpleName(token.tokenString, isDelimitedIdentifier())); read(); } select.addSelectColumnExpression(e); if (token.tokenType == Tokens.FROM) { break; } if (token.tokenType == Tokens.INTO) { break; } if (readIfThis(Tokens.COMMA)) { continue; } if (token.tokenType == Tokens.CLOSEBRACKET || token.tokenType == Tokens.X_ENDPARSE) { if (database.sqlSyntaxMss || database.sqlSyntaxMys || database.sqlSyntaxPgs) { Expression[] exprList = new Expression[select.exprColumnList.size()]; select.exprColumnList.toArray(exprList); Expression valueList = new Expression(OpTypes.VALUELIST, exprList); for (int i = 0; i < valueList.nodes.length; i++) { if (valueList.nodes[i].opType != OpTypes.ROW) { valueList.nodes[i] = new Expression(OpTypes.ROW, new Expression[]{ valueList.nodes[i] }); } } compileContext.incrementDepth(); TableDerived td = prepareSubqueryTable(valueList, OpTypes.VALUELIST); select = new QuerySpecification(session, td, compileContext, true); compileContext.decrementDepth(); return select; } } throw unexpectedToken(); } return select; }
XreadAllTypesCommonValueExpression读取每列的一些四则运算,然后如果有括号还得做优先级处理
Expression XreadValueExpression() { Expression e = XreadAllTypesCommonValueExpression(true); if (token.tokenType == Tokens.LEFTBRACKET) { read(); Expression e1 = XreadNumericValueExpression(); readThis(Tokens.RIGHTBRACKET); e = new ExpressionAccessor(e, e1); } return e; }
这个是先处理加减操作,乘除操作优先级高会在XreadTerm中先封装成一个Expression对象,然后在作为操作放到当前加减操作的Expression中,也就是Expression中可以嵌套多级Expression对象,
Expression XreadNumericValueExpression() { Expression e = XreadTerm(); while (true) { int type; if (token.tokenType == Tokens.PLUS) { type = OpTypes.ADD; } else if (token.tokenType == Tokens.MINUS) { type = OpTypes.SUBTRACT; } else { break; } read(); Expression a = e; e = XreadTerm(); e = new ExpressionArithmetic(type, a, e); } return e; }
XreadFactor读取常量部分
Expression XreadTerm() { Expression e = XreadFactor(); int type; while (true) { if (token.tokenType == Tokens.ASTERISK) { type = OpTypes.MULTIPLY; } else if (token.tokenType == Tokens.DIVIDE) { type = OpTypes.DIVIDE; } else { break; } read(); Expression a = e; e = XreadFactor(); if (e == null) { throw unexpectedToken(); } e = new ExpressionArithmetic(type, a, e); } return e; }
prepareSubqueryTable 子查询就不跟踪了,
预编译就是把sql的解析过程缓存起来,保存在statementManger中,下次就不用再解析编译了。
select的字段内容如下:select atime, adate from dttest where adate < '16:44:31'
返回字段只有atime,别名为adate
我们看看编译后的表达式内容 第一个node表示是where语句第一个条件左边的表达式,adate optype=2表示VALUE,也就是字段值,第一个node的optype为1,表示常量。而整个Expression的optype是44,表示第一个node小于第二个node的值,当然还有每个node的类型
看执行过程了,这sql有点问题把where语句的adate改为atime,要不然报日期格式不对,
metaData表示返回的列类型
回到QuerySpecification类的buildResult(Session session, int[] limits) 返回limits表示limit,offset,top的参数,这里没有指定,则默认取所有记录,isSipleCount是取聚合的而一个值的操作,返回总数之类的操作,
我们这里是执行到这里的查询逻辑,这里取出我们需要的列值
在这里执行索引查询where条件查询it.next()
RangeIterator it = rangeIterators[currentIndex]; if (it.next()) { if (currentIndex < rangeVariables.length - 1) { currentIndex++; continue; } } else { it.reset(); currentIndex--; continue; }
it next方法保存当前indexAVL树中查找到的节点,然后查找下一个满足条件的记录
在RangeVariable执行这个next操作,操作结果就保存在session,后面从session中就能获取数据了。 data[i] = exprColumns[i].getValue(session); 在这里获取下一个数据。
public boolean next() { while (condIndex < conditions.length) { if (isBeforeFirst) { isBeforeFirst = false; initialiseIterator(); } boolean result = findNext(); if (result) { return true; } reset(); condIndex++; } condIndex = 0; return false; }
查询索引的过程 首先在AVL树中查询满足条件的第一个结果节点,然后findnext就在这个节点上查找下一个节点
indexAVL类的findNode
public RowIterator findFirstRow(Session session, PersistentStore store, Object[] rowdata, int matchCount, int distinctCount, int compareType, boolean reversed, boolean[] map) { if (compareType == OpTypes.MAX) { return lastRow(session, store); } NodeAVL node = findNode(session, store, rowdata, defaultColMap, matchCount, compareType, TransactionManager.ACTION_READ, reversed); if (node == null) { return emptyIterator; } return new IndexRowIterator(session, store, this, node, distinctCount, false, reversed); }
/** * Finds a match with a row from a different table * * @param session Session * @param store PersistentStore * @param rowdata array containing data for the index columns * @param rowColMap map of the data to columns * @param fieldCount int * @param compareType int * @param readMode int * @return matching node or null */ NodeAVL findNode(Session session, PersistentStore store, Object[] rowdata, int[] rowColMap, int fieldCount, int compareType, int readMode, boolean reversed) { readLock.lock(); try { NodeAVL x = getAccessor(store); NodeAVL n = null; NodeAVL result = null; Row currentRow = null; if (compareType != OpTypes.EQUAL && compareType != OpTypes.IS_NULL) { fieldCount--; } while (x != null) { currentRow = x.getRow(store); int i = 0; if (fieldCount > 0) { i = compareRowNonUnique(session, currentRow.getData(), rowdata, rowColMap, fieldCount); } if (i == 0) { switch (compareType) { case OpTypes.IS_NULL : case OpTypes.EQUAL : { result = x; n = x.getLeft(store); break; } case OpTypes.NOT : case OpTypes.GREATER : { i = compareObject(session, currentRow.getData(), rowdata, rowColMap, fieldCount); if (i <= 0) { n = x.getRight(store); } else { result = x; n = x.getLeft(store); } break; } case OpTypes.GREATER_EQUAL : { i = compareObject(session, currentRow.getData(), rowdata, rowColMap, fieldCount); if (i < 0) { n = x.getRight(store); } else { result = x; n = x.getLeft(store); } break; } case OpTypes.SMALLER : { i = compareObject(session, currentRow.getData(), rowdata, rowColMap, fieldCount); if (i < 0) { result = x; n = x.getRight(store); } else { n = x.getLeft(store); } break; } case OpTypes.SMALLER_EQUAL : { i = compareObject(session, currentRow.getData(), rowdata, rowColMap, fieldCount); if (i <= 0) { result = x; n = x.getRight(store); } else { n = x.getLeft(store); } break; } default : Error.runtimeError(ErrorCode.U_S0500, "Index"); } } else if (i < 0) { n = x.getRight(store); } else if (i > 0) { n = x.getLeft(store); } if (n == null) { break; } x = n; } // MVCC 190 if (session == null) { return result; } while (result != null) { currentRow = result.getRow(store); if (session.database.txManager.canRead(session, currentRow, readMode, colIndex)) { break; } result = reversed ? last(store, result) : next(store, result); if (result == null) { break; } currentRow = result.getRow(store); if (fieldCount > 0 && compareRowNonUnique( session, currentRow.getData(), rowdata, rowColMap, fieldCount) != 0) { result = null; break; } } return result; } finally { readLock.unlock(); } }
/** * Advances to the next available value. <p> * * @return true if a next value is available upon exit */ private boolean findNext() { boolean result = false; while (true) { currentRow = it.getNextRow(); if (currentRow == null) { break; } currentData = currentRow.getData(); if (conditions[condIndex].terminalCondition != null && !conditions[condIndex].terminalCondition .testCondition(session)) { break; } if (conditions[condIndex].indexEndCondition != null && !conditions[condIndex].indexEndCondition .testCondition(session)) { if (!conditions[condIndex].isJoin) { hasLeftOuterRow = false; } break; } if (joinConditions[condIndex].nonIndexCondition != null && !joinConditions[condIndex].nonIndexCondition .testCondition(session)) { continue; } if (whereConditions[condIndex].nonIndexCondition != null && !whereConditions[condIndex].nonIndexCondition .testCondition(session)) { hasLeftOuterRow = false; addFoundRow(); continue; } Expression e = conditions[condIndex].excludeConditions; if (e != null && e.testCondition(session)) { continue; } addFoundRow(); hasLeftOuterRow = false; return true; } it.release(); currentRow = null; currentData = rangeVar.emptyData; if (hasLeftOuterRow && condIndex == conditions.length - 1) { result = (whereConditions[condIndex].nonIndexCondition == null || whereConditions[condIndex].nonIndexCondition .testCondition(session)); hasLeftOuterRow = false; } return result; } private void addFoundRow() { if (rangeVar.isRightJoin) { lookup.add(currentRow.getPos()); } }
比如一个notequal操作会在这里的testCondition判断是否符合
相关推荐
由于HSQLDB是开源的,开发者可以深入研究其源码,理解数据库的内部工作原理,如查询解析、执行计划生成、事务管理等,这对提升数据库相关的技术能力非常有帮助。 总之,HSQLDB作为一个轻量级、高性能的数据库,广泛...
HSQLDB(HyperSQL Database)是一个轻量级、高性能的关系型数据库引擎,常用于Java应用程序和测试环境中。它的缓存机制和数据存储方式对于理解其性能和操作至关重要。以下是对HSQLDB的缓存分析和调试步骤的详细解释...
HSQldb是一个轻量级的关系型...HSQldb的灵活性和易用性使其成为开发人员的首选数据库之一,特别是在快速迭代和测试环境中。其强大的特性,如内存数据库、自动创建数据库以及内置的管理工具,都极大地简化了数据库管理。
3. **高性能**:HSQldb在处理大量数据时表现出良好的性能,得益于其高效的查询引擎和内存管理机制。 4. **支持SQL标准**:HSQldb兼容大部分SQL92和SQL99标准,提供丰富的SQL语句支持。 5. **嵌入式数据库**:...
**源码分析** HSQLDB是用Java编写的,因此其源码可读性较高,对于学习数据库原理和实现有很高的价值。通过阅读源码,开发者可以深入理解SQL的执行流程、事务管理、索引构建等核心概念。 **工具支持** HSQLDB提供...
### HSQLDB中文帮助文档知识点...综上所述,HSQLDB作为一款功能强大的轻量级数据库管理系统,在许多方面都表现出了优秀的能力,不仅支持标准SQL语法,还具备良好的跨平台特性,是开发和部署Java应用的理想选择之一。
4. **强大的查询能力**:HSQldb支持复杂的SQL查询,包括子查询、联接操作、视图等。 5. **自动备份与恢复**:HSQldb 2.3.4支持定时自动备份,确保数据安全。 6. **嵌入式与独立服务器模式**:HSQldb可以作为Java应用...
- **约束和索引**:详细阐述了如何在HSQLDB中定义和使用主键、唯一性约束、唯一性索引以及外键约束,并分析了这些约束和索引如何影响查询性能。 - **类型和算术操作**:介绍了HSQLDB支持的各种数据类型,包括整型、...
5. 关闭数据库:完成所有操作后,可以通过管理工具或者命令行关闭HSQldb服务器,释放系统资源。 总的来说,HSQldb管理工具以其易用性和灵活性,成为了开发者和数据库管理员的得力助手。无论是小型项目还是大型应用...
《HSQLDB 1.8.0:轻量级数据库引擎的深度剖析》 HSQLDB,全称为HyperSQL Database,是一款开源、轻量级、高性能的关系型数据库管理系统,广泛应用于嵌入式系统和测试环境。HSQLDB 1.8.0是该数据库引擎的一个重要...
总结来说,HSQldb实例源代码为我们提供了学习和实践HSQldb数据库操作的实例,涵盖了数据库的创建、数据操作以及查询等核心功能。通过研究这些代码,开发者可以快速掌握HSQldb的使用,并将其应用于自己的项目中,无论...
HSQLDB的性能可以通过调整内存大小、使用存储引擎类型(内存或文件)、索引策略等方式进行优化。在处理大量数据时,合理设计表结构和索引能显著提升查询效率。 总之,HSQLDB是一款强大且灵活的数据库解决方案,无论...
HSQldb完全用Java编写,因此具有跨平台性,能在任何支持Java的环境中运行,包括Windows操作系统。在你提到的"hsqldb的最新1.9.0版本"中,它可能包含了性能优化、新功能的添加以及已知问题的修复。 HSQldb的1.9.0...
HSQLDB提供了一系列实用工具,如DatabaseManager、TransferTool、QueryTool和SqlTool,分别用于图形界面管理、数据迁移、查询执行和命令行操作,大大简化了数据库的日常管理和维护工作。 #### 七、版权与翻译声明 ...
这两本书籍详尽地介绍了HSQLDB的安装、配置、使用方法以及高级特性,包括数据库创建、表操作、查询语言、事务处理、备份与恢复等内容,是学习和掌握HSQLDB的重要资料。 通过阅读这两份指南,你可以了解到如何创建...
在本压缩包中,提供的HSQldb版本为2.25,特别之处在于它是针对JDK 1.5编译的。由于HSQldb自2.0版本起,官方默认使用JDK 1.6或更高版本进行编译,这可能对仍在使用JDK 1.5的开发者造成兼容性问题。因此,HSQldb 2.25...
HSQldb的一大特点是支持标准SQL语法,这使得开发人员可以使用熟悉的SQL命令进行数据操作,而无需学习新的查询语言。同时,HSQldb提供了丰富的JAVA接口,包括JDBC驱动程序,使得开发者能够轻松地在Java应用程序中集成...
《HSQldb 2.3.3:轻量级数据库引擎深度解析》 HSQldb,全称为HyperSQL Database,是一款开源、纯Java语言编写的轻量级关系型数据库管理系统,广泛应用于测试环境、嵌入式系统以及小型应用中。HSQldb 2.3.3是其稳定...