ResultSet: Извлечение значений столбцов по индексу или по метке?
Вопрос о выборе между индексом и меткой для получения значений из ResultSet в JDBC
При использовании JDBC я часто сталкиваюсь со следующими конструкциями:
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
// Другие действия
}
Я задавался вопросом (и задавал его авторам кода), почему не использовать имя колонки для извлечения значений:
int id = rs.getInt("CUSTOMER_ID");
Лучшее объяснение, которое я слышал, связано с производительностью. Но действительно ли это делает обработку значительно быстрее? Я в это не верю, хотя никогда не проводил замеров. Даже если извлечение по метке будет немного медленнее, на мой взгляд, это обеспечивает лучшую читаемость и гибкость кода.
Не могли бы вы предоставить хорошее объяснение, почему стоит избегать получения значений колонок по индексу, а не по метке? Каковы плюсы и минусы обоих подходов (возможно, в зависимости от конкретных СУБД)?
5 ответ(ов)
Предупреждение: Я собираюсь высказываться с достаточно сильной эмоцией, потому что это сводит меня с ума.
99% времени это просто смешная микрооптимизация, о которой у людей есть какое-то смутное представление, что она делает вещи «лучше». Это совершенно игнорирует тот факт, что, если вы не находитесь в крайне жестком и нагруженном цикле обработки миллионов SQL-результатов всегда, что, надеюсь, бывает редко, вы этого никогда не заметите. Для всех, кто не делает этого, затраты времени разработчика на поддержку, обновление и устранение ошибок в индексировании столбцов значительно превышают незначительные затраты на оборудование для вашего незначительно менее производительного приложения.
Не вводите такие оптимизации в код. Пишите его так, чтобы тем, кто будет его поддерживать, было проще. Затем наблюдайте, измеряйте, анализируйте и оптимизируйте. Наблюдайте снова, измеряйте еще раз, анализируйте снова и оптимизируйте снова.
Оптимизация — это, по сути, последний шаг в разработке, а не первый.
- Цифра выдумана.
Вам следует использовать строковые метки по умолчанию.
Плюсы:
- Независимость от порядка столбцов.
- Лучшая читаемость и удобство сопровождения кода.
Минусы:
- Вы не можете контролировать имена столбцов (доступ через хранимые процедуры).
Что бы вы предпочли?
Целые числа?
int i = 1;
customerId = resultSet.getInt(i++);
customerName = resultSet.getString(i++);
customerAddress = resultSet.getString(i++);
Или строки?
customerId = resultSet.getInt("customer_id");
customerName = resultSet.getString("customer_name");
customerAddress = resultSet.getString("customer_address");
А если в таблицу добавят новый столбец на позицию 1? Какой вариант кода вы предпочтете? Или если порядок столбцов изменится, какой код вам нужно будет изменять?
Вот почему вы должны использовать строковые метки по умолчанию.
Ответ принят, однако вот дополнительная информация и личный опыт, которые, на мой взгляд, еще не были озвучены.
В общем случае рекомендуется использовать имена колонок (предпочтительно константы, а не литералы) и, если возможно, это делать. Это делает код более ясным, упрощает его поддержку, а будущие изменения менее вероятно сломают код.
Тем не менее, существуют случаи, когда индексы колонок могут быть полезны. В некоторых случаях они могут быть быстрее, но не настолько, чтобы это перевешивало вышеупомянутые причины для использования имен*. Индексы очень ценные при разработке инструментов и общих методов, работающих с ResultSet
. Наконец, использование индексов может потребоваться в ситуациях, когда колонка не имеет имени (например, анонимный агрегат) или при наличии дублирующихся имен, когда нет простого способа ссылаться на обе.
*Обратите внимание, что я разрабатывал некоторые JDBC-драйверы и изучал внутренности открытых исходников, и в них используются индексы колонок для обращения к результатам. В тех случаях, с которыми я работал, внутренний драйвер сначала сопоставляет имя колонки с индексом. Таким образом, можно с легкостью увидеть, что обращение по имени колонки всегда будет занимать больше времени. Однако это может быть не верно для всех драйверов.
Согласно документации Java:
Интерфейс ResultSet предоставляет методы получения (getBoolean, getLong и т.д.) для извлечения значений столбцов из текущей строки. Значения могут быть извлечены либо по индексу столбца, либо по имени столбца. В общем, использование индекса столбца будет более эффективным. Столбцы нумеруются с 1. Для максимальной переносимости столбцы результата в каждой строке должны читаться слева направо, и каждый столбец следует читать только один раз.
Каждый метод (по имени или по индексу) имеет свое место. Я согласен с тем, что использование именованных столбцов должно быть стандартом. Однако в тех случаях, когда требуется множество циклов, и когда выражение SELECT определяется и поддерживается в одном и том же блоке кода (или классе), использование индексов будет приемлемо. Рекомендуется явно указывать выбираемые столбцы, а не просто использовать "SELECT * FROM...", так как любое изменение в таблице может привести к поломке кода.
Я провёл профилирование производительности по этому вопросу в базе данных Oracle. В нашем коде есть ResultSet с множеством колонок и большим количеством строк. Из 20 секунд (!) времени, необходимого для выполнения запроса, метод oracle.jdbc.driver.ScrollableResultSet.findColumn(String name)
занимает около 4 секунд.
Очевидно, что в общем дизайне есть какие-то проблемы, но, возможно, использование индексов вместо имён колонок поможет избавиться от этих 4 секунд.
Преобразование java.sql.Date в java.util.Date
Можно ли подключиться к SQL Server с использованием Windows Authentication из веб-приложения Java EE?
java.sql.SQLException: Не найден подходящий драйвер для jdbc:mysql://localhost:3306/dbname
Что значит 'synchronized'?
Как объявить массив в одну строку?