Почему чтение JDBC ResultSet по позиции быстрее, чем по имени и насколько быстрее? - PullRequest
15 голосов
/ 05 апреля 2019

Объявляя об Hibernate 6 , команда Hibernate утверждает, что, переключившись с чтение по имени для чтения по позиции в JDBC ResultSet они получают выигрыш в производительности.

Высокопроизводительное тестирование производительности показало, что подход Hibernate чтение значений из ResultSet по имени, чтобы быть его наиболее ограничивающим фактором в масштабном проходе.

Означает ли это, что они меняют вызовы с getString(String columnLabel) на getString(int columnIndex)?

Почему это быстрее?

Поскольку ResultSet не является ли интерфейс повышением производительности, зависит от реализующего его драйвера JDBC?

Насколько велики выгоды?

1 Ответ

12 голосов
/ 05 апреля 2019

Говоря как сопровождающий драйвера 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() может быть довольно высокой.

Но даже если эта стоимость незначительна (например, оператор подготовки метаданных с сервера базы данных включает в себя метки столбцов), затраты на сопоставление метки столбца с индексом и последующий поиск по индексу, очевидно, выше, чем прямой поиск поindex.

Драйверы могут даже просто зацикливаться на метаданных набора результатов каждый раз и использовать первый, чья метка совпадает;это может быть дешевле, чем создание и доступ к хэш-карте для наборов результатов с небольшим числом столбцов, но стоимость все равно выше, чем прямой доступ по индексу.

Как я уже сказал, это общее обобщение, ноЯ был бы удивлен, если это (поиск по индексу, а затем поиск по индексу) не так, как это работает в большинстве драйверов JDBC, а это значит, что я ожидаю, что поиск по индексу, как правило, будет быстрее.

Если взглянуть на ряд драйверов, это относится к:

  • Firebird (Jaybird, раскрытие: я поддерживаю этот драйвер)
  • MySQL (MySQL Connector / J)
  • PostgreSQL
  • Oracle
  • HSQLDB
  • SQL Server (драйвер Microsoft JDBC для SQL Server)

Я не в курседрайверов JDBC, где поиск по имени столбца будет эквивалентен по стоимости или даже дешевле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...