17

Announcing Hibernate 6 the Hibernate team claims that by switching from read-by-name to read-by-position in JDBC ResultSet they gain a performance benefit.

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.

Does that mean they are changing calls from getString(String columnLabel) to getString(int columnIndex)?

Why is this faster?

As ResultSet is an interface doesn't performance gain depend on the JDBC driver implementing it?

How big are the gains?

4

1 回答 1

17

作为 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()可能相当高。

但是,即使该成本可以忽略不计(例如,从数据库服务器准备元数据的语句包括列标签),将列标签映射到索引然后按索引检索的开销明显高于直接按索引检索。

驱动程序甚至可以每次循环遍历结果集元数据并使用标签匹配的第一个;这可能比为具有少量列的结果集构建和访问哈希映射便宜,但成本仍然高于通过索引直接访问。

正如我所说,这是一个全面的概括,但如果这(按名称查找索引,然后按索引检索)不是它在大多数 JDBC 驱动程序中的工作方式,我会感到惊讶,这意味着我希望按索引查找一般会更快。

快速浏览一些驱动程序,情况如下:

  • Firebird(Jaybird,披露:我维护这个驱动程序)
  • MySQL (MySQL 连接器/J)
  • PostgreSQL
  • 甲骨文
  • 数据库
  • SQL Server(用于 SQL Server 的 Microsoft JDBC 驱动程序)

我不知道按列名检索的 JDBC 驱动程序在成本上是等价的,甚至更便宜。

于 2019-04-05T09:19:33.163 回答