Оригинальная статья называется «10 ошибок SQL, которые допускают Java-разработчики», но, по большому счету, представленные в ней принципы можно применить к любому языку.
Java-программисты смешивают объектно-ориентированное и императивное мышление в зависимости от своего уровня:
- мастерство (каждый может программировать императивно)
- догма (шаблон для применения шаблонов где угодно и их именования)
— настроения (применить истинно-объектный подход немного сложнее, чем императивно)
Но все меняется, когда разработчики Java пишут код SQL.
SQL — декларативный язык и не имеет ничего общего с объектно-ориентированным или императивным мышлением.
Выразить запрос в SQ очень легко, но правильно и оптимально выразить его достаточно сложно.
Разработчикам необходимо не только переосмыслить свою парадигму программирования, но и мыслить в рамках теории множеств.
Ниже перечислены распространенные ошибки, которые допускают разработчики Java при использовании SQL в JDBC или jOOQ (в произвольном порядке).
Для еще 10 ошибок смотрите в этой статье .
1. Забыли про NULL
Непонимание NULL — это, вероятно, самая большая ошибка, которую может совершить Java-разработчик при написании SQL. Возможно, это связано с тем, что NULL также называется UNKNOWN. Если бы оно называлось просто НЕИЗВЕСТНО, его было бы легче понять.Другая причина заключается в том, что при получении данных и переменных привязки JDBC преобразует значение SQL NULL в значение Java null. Это может привести к тому, что NULL = NULL (SQL) будет вести себя так же, как null == null (JAVA).
Одним из наиболее ярких примеров ошибки NULL является ситуация, когда Предикаты NULL используются с выражением значения строки.
.
Другая, более конкретная проблема возникает, когда отсутствует понимание Значения NULL в антиобъединениях NOT IN .
Лекарство: Тренируй себя.
Это несложно — при написании SQL всегда думайте о NULL:
— Верен ли этот предикат относительно NULL?
— Влияет ли NULL на результат этой функции?
2. Обработка данных в памяти Java
Немногие Java-программисты хорошо знают SQL. Случайное СОЕДИНЕНИЕ, странный СОЮЗ и ок.А как насчет оконных функций? Группировать наборы? Многие Java-разработчики загружают данные SQL в память, преобразуют их в некую подходящую коллекцию и выполняют над этими коллекциями необходимые вычисления с помощью многословных циклических структур (по крайней мере, до улучшения коллекций в JAVA 8 ).
Но некоторые базы данных SQL поддерживают дополнительные (стандарт SQL!) OLAP-функции, которые лучше для этого подходят и их легче писать.
Один пример (не стандартный) отлично Оператор MODEL от Oracle .
Просто позвольте базе данных выполнить обработку и перенести результаты в память Java. Потому что ведь какой-то умник уже оптимизировал эти дорогие продукты.
Итак, используя OLAP в базе данных, вы получаете две вещи: - Простота.
Вероятно, проще правильно писать на SQL, чем на Java. - Производительность.
БД, скорее всего, будут быстрее вашего алгоритма.
И, что еще более важно, вам не придется передавать по сети миллионы записей.
Лекарство:
Каждый раз, когда вы пишете алгоритм, ориентированный на данные, с использованием Java, спросите себя: «Можно ли переложить эту работу на базу данныхЭ»
3. Использование UNION вместо UNION ALL
Жаль, что UNION ALL требует дополнительного слова относительно UNION. Было бы намного лучше, если бы стандарт SQL был определен для поддержки: — UNION (допускает дублирование) — UNION DISTINCT (удаляет дублирование) Удаление дубликатов не только используется реже, но и довольно медленно работает при работе с большими выборками, поскольку два подзапроса необходимо упорядочить и каждый кортеж необходимо сравнить с последующим кортежем.Помните, что хотя стандарт SQL определяет INTERSECT ALL и EXCEPT ALL, не каждая база данных может реализовать эти малоиспользуемые наборы операций.
Лекарство:
Подумайте, хотите ли вы писать UNION ALL каждый раз, когда пишете UNION.
4. Использование JDBC для разбивки на страницы большой выборки
Большинство баз данных поддерживают некоторые средства для постраничного просмотра операторов LIMIT. OFFSET, TOP. START AT, OFFSET. FETCH. При отсутствии поддержки со стороны этих операторов все еще возможно иметь РАУНУМ (Оракул) или Фильтрация ROW_NUMBER() OVER() (DB2, SQL Server 2008 и другие) , что намного быстрее, чем секционирование в памяти.В основном это касается больших смещений! Лекарство: Просто используйте эти операторы или инструмент (например, jOOQ), который может эмулировать эти операторы за вас.
5. Подключение памяти Java
С первых дней существования SQL и по сей день некоторые Java-программисты пишут JOIN с тяжелым сердцем.У них есть устаревшее опасение, что соединения JOIN работают медленно.
Это может быть в том случае, если оптимизатор накладных расходов решает выполнить вложенный цикл, загружая целые таблицы в память перед созданием ячеек таблицы соединения.
Но это случается редко.
С обычными предикатами, ограничениями, индексами операции MERGE JOIN или HASH JOIN выполняются очень быстро — все зависит от правильных метаданных ( Том Кайт хорошо об этом написал ).
Однако, вероятно, еще осталось несколько Java-разработчиков, которые загружают две таблицы двумя отдельными запросами и тем или иным образом соединяют их в памяти Java. Лекарство: Если на разных этапах вы выбирали из разных таблиц, подумайте еще раз, возможно, вам удастся выразить свои запросы в одной.
6. Использование DISTINCT или UNION для удаления дубликатов из случайного декартова произведения
Из-за сложных соединений JOIN любой разработчик может потерять значимые связи в SQL-запросе.Точнее, при использовании отношений с составными внешними ключами вы можете забыть добавить осмысленные предикаты к операторам JOIN.ON. Это может привести к появлению повторяющихся строк всегда или только в исключительных ситуациях.
Затем некоторые разработчики могут добавить оператор DISTINCT, чтобы предотвратить дублирование данных.
Это неправильно по трем причинам: «Это может излечить последствия, но не причину».
И это может не решить последствия в граничных условиях.
- Это медленно для больших выборок.
DISTINCT выполняет операцию ORDER BY для удаления дубликатов.
- Это медленно для больших декартовых произведений, которые все равно будут загружены в память.
Лекарство: Как правило, если вы получаете нежелательные дубликаты, пересмотрите предикаты JOIN. Вероятно, где-то там образовалось небольшое декартово произведение.
7. Как избежать оператора MERGE
На самом деле это не ошибка, но, возможно, это недостаток знаний или опасения.Некоторые базы данных знают другие формы оператора UPSERT, например MySQL ON DUPLICATE KEY UPDATE. На самом деле MERGE является очень мощным инструментом, особенно в базах данных, которые значительно расширяют стандарт SQL, таких как SQL-сервер .
Лекарство: Если вы выполняете UPSERT, выстраивая цепочку INSERT и UPDATE или SELECT. FOR UPDATE и INSERT/UPDATE, подумайте еще раз.
Вместо того, чтобы рисковать гонкой ресурсов, вы можете написать более простой запрос MERGE.
8. Использование агрегатных функций вместо оконных функций
До появления оконных функций единственным способом агрегирования данных в SQL было использование GROUP BY вместе с агрегатными функциями в проекции.В большинстве случаев это работает хорошо, а если агрегированные данные необходимо заполнить обычными данными, то сгруппированный запрос можно записать в виде добавленного подзапроса.
Но SQL:2003 определяет оконные функции, которые реализованы многими поставщиками баз данных.
Оконные функции могут агрегировать данные по несгруппированным выборкам.
Фактически, каждая оконная функция поддерживает свою собственную независимую операцию PARTITION BY, которая является отличным инструментом создания отчетов.
Использование оконных функций позволит вам: — Создайте более читаемый SQL (меньше выделенных выражений GROUP BY в подзапросах).
— Повышение производительности, поскольку СУБД упрощает оптимизацию оконных функций.
Лекарство:
Когда вы пишете выражение GROUP BY в подзапросе, подумайте, можно ли его выразить с помощью оконной функции?
9. Использование сортировки в памяти по разным параметрам
Предложение ORDER BY поддерживает многие типы выражений, включая CASE, которые могут быть очень полезны при определении параметров сортировки.Никогда не следует сортировать данные в памяти Java только потому, что: - Сортировка SQL выполняется слишком медленно.
- SQL-сортировка не может этого сделать.
Лекарство: Если вы сортируете какие-то SQL-данные в памяти Java, подумайте, можно ли перенести эту сортировку в базу данных? Это хорошо сочетается с нумерацией страниц базы данных.
10. Последовательная вставка нескольких записей
JDBC знает, что такое пакет, и вам следует его использовать.Не вставляйте тысячи записей одну за другой, создавая каждый раз новый подготовленный оператор.
Если все ваши записи помещены в одну таблицу, создайте пакет запросов INSERT с одним запросом SQL и несколькими наборами данных, которые нужно связать.
В зависимости от вашей базы данных и ее конфигурации, чтобы поддерживать чистоту журнала UNDO, вам может потребоваться выполнить фиксацию после определенного количества вставленных записей.
Лекарство: Всегда используйте пакетные вставки для больших наборов данных.
Несколько интересных книг по теме
— Антипаттерны SQL Билла Карвина — Производительность SQL, объясненная Маркусом Винандом В опросе могут участвовать только зарегистрированные пользователи.Войти , Пожалуйста.
Хотите увидеть перевод продолжения статьи? 75,4% Да 564 24,6% Нет 184 748 пользователей проголосовали.
159 пользователей воздержались.
Теги: #sql #java #Jdbc #jooq #errors #programming #java #sql
-
Фромм, Эрих
19 Oct, 24 -
Я.болтун
19 Oct, 24 -
Мысли О Свободе
19 Oct, 24 -
Электронная Почта
19 Oct, 24