Announcing Hibernate 6 Hibernate 团队声称通过从 在 JDBC 中按名称读取到按位置读取 ResultSet他们获得了性能优势。
High-load performance testing showed that Hibernate’s approach of reading values from ResultSet by name to be its most limiting factor in scaling through-put.
这是否意味着他们正在改变来自 getString(String columnLabel)
的调用至 getString(int columnIndex)
?
为什么这样更快?
由于 ResultSet
是一个接口(interface),性能提升是否取决于实现它的 JDBC 驱动程序?
yield 有多大?
最佳答案
作为 JDBC 驱动程序维护者(并且,我承认,进行了一些不一定适用于所有 JDBC 驱动程序的全面概括),行值通常存储在数组或列表中,因为这最自然地匹配数据的方式从数据库服务器接收。
因此,按索引检索值将是最简单的。它可能像这样简单(忽略实现 JDBC 驱动程序的一些更糟糕的细节):
public Object getObject(int index) throws SQLException {
checkValidRow();
checkValidIndex(index);
return currentRow[index - 1];
}
这已经快到了。
另一方面,按列名查找需要更多工作。列名需要区分大小写,无论您使用小写还是大写进行规范化,或者使用 TreeMap
进行不区分大小写的查找,都会产生额外的成本。
一个简单的实现可能是这样的:
public Object getObject(String columnLabel) throws SQLException {
return getObject(getIndexByLabel(columnLabel));
}
private int getIndexByLabel(String columnLabel) {
Map<String, Integer> indexMap = createOrGetIndexMap();
Integer columnIndex = indexMap.get(columnLabel.toLowerCase());
if (columnIndex == null) {
throw new SQLException("Column label " + columnLabel + " does not exist in the result set");
}
return columnIndex;
}
private Map<String, Integer> createOrGetIndexMap() throws SQLException {
if (this.indexMap != null) {
return this.indexMap;
}
ResultSetMetaData rsmd = getMetaData();
Map<String, Integer> map = new HashMap<>(rsmd.getColumnCount());
// reverse loop to ensure first occurrence of a column label is retained
for (int idx = rsmd.getColumnCount(); idx > 0; idx--) {
String label = rsmd.getColumnLabel(idx).toLowerCase();
map.put(label, idx);
}
return this.indexMap = map;
}
根据数据库的 API 和可用的语句元数据,可能需要额外的处理来确定查询的实际列标签。根据成本,这可能只会在实际需要时才确定(按名称访问列标签时,或检索结果集元数据时)。换句话说,createOrGetIndexMap()
的成本可能相当高。
但即使这个成本可以忽略不计(例如从数据库服务器准备元数据的语句包括列标签),将列标签映射到索引然后通过索引检索的开销明显高于直接通过索引检索。
驱动程序甚至可以每次都循环遍历结果集元数据并使用第一个标签匹配的;这可能比为具有少量列的结果集构建和访问 HashMap 更便宜,但成本仍然高于通过索引直接访问。
正如我所说,这是一个笼统的概括,但如果这(按名称查找索引,然后按索引检索)不是它在大多数 JDBC 驱动程序中的工作方式,我会感到惊讶,这意味着我希望按索引查找通常会更快。
快速浏览一些驱动程序,情况如下:
- Firebird(Jaybird,披露:我维护这个驱动程序)
- MySQL(MySQL 连接器/J)
- PostgreSQL
- 甲骨文
- 数据库
- SQL Server(用于 SQL Server 的 Microsoft JDBC 驱动程序)
我不知道 JDBC 驱动程序在哪些情况下按列名检索在成本上是相同的,甚至更便宜。
关于java - 为什么按位置读取 JDBC 结果集比按名称读取 JDBC 结果集快多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55531375/