10 потенциальных SQL ошибок, которые делают программисты

Original author: Lukas Eder
  • Translation
  • Tutorial
Оригинал статьи носит название «10 SQL ошибок, которые делают Java разработчики», но, по большому счёту, приведённые в ней принципы можно отнести к любому языку.



Java программисты мешают объектно-ориентированное и императивное мышление в зависимости от их уровня:
— мастерства (каждый может программировать императивно)
— догмы (шаблон для применения шаблонов где-либо и их именование)
— настроения (применять истинный объектный подход немного сложнее чем императивный)

Но всё меняется, когда Java разработчики пишут SQL код.
SQL — это декларативный язык, который не имеет ничего общего с объектно-ориентированным или императивным мышлением. Очень легко выразить запрос в SQ, но довольно трудно выразить его корректно и оптимально. Разработчикам не только необходимо переосмыслить их парадигму программирования, им нужно ещё и думать в рамках теории множеств (set theory).

Ниже перечислены общие ошибки, которые делают Java разработчики, использующие SQL в JDBC или jOOQ (без определённого порядка). Для других 10 ошибок, смотрите эту статью.

1. Забыл о NULL


Непонимание NULL — это скорее всего самая большая ошибка, которую Java разработчик может сделать, когда пишет SQL. Это может быть потому, что NULL ещё называется UNKNOWN. Если бы он назывался просто UNKNOWN, его было бы проще понять. Другая причина в том, что при получении данных и связывании переменных JDBC отражает SQL NULL в Java null. Это может привести к тому, что NULL = NULL (SQL) будет вести себя так же, как и null == null (JAVA).

Один из самых ярких примеров заблуждения о NULL — это когда NULL предикаты используются со строковым выражением (row value expression).

Другая, более специфическая проблема появляется при отсутствии понимания значения NULL в NOT IN anti-joins.

Лекарство:
Тренируй себя. Ничего сложного — во время написания SQL всегда думай о NULL:
— Этот предикат корректен относительно NULL?
— Влияет ли NULL на результат этой функции?

2. Обработка данных в памяти Java


Не многие Java программисты знают SQL очень хорошо. Случайный JOIN, странный UNION и ладно. А оконные функции? Группирующие наборы? Многие 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 операторов. В отсутствии поддержки этих операторов всё ещё есть возможность наличия ROWNUM (Oracle) или ROW_NUMBER() OVER() фильтрации (DB2, SQL Server 2008 и другие), которые намного быстрее разбивки в памяти. Это относится преимущественно к большим смещениям!

Лекарство:
Просто используйте эти операторы, или инструмент(такой, как jOOQ), который может имитировать эти операторы за вас.

5. Соединение данных в памяти Java


С ранних дней SQL и до сих пор некоторые Java программисты с тяжелым сердцем пишут JOINы. У них есть устаревший страх того, что JOINы выполняются медленно. Это может быть так, если оптимизатор накладных расходов выбирает сделать вложенный цикл, загружая целые таблицы в память перед созданием ячеек присоединённой таблицы. Но это случается редко. С нормальными предикатами, ограничениями, индексами, MERGE JOIN или HASH JOIN операции выполняются очень быстро — всё зависит от корректных метаданных (Tom Kyte хорошо написал об этом). Тем не менее, наверняка ещё остались немногие Java разработчики, которые загружают две таблицы двумя отдельными запросами и соединяют их в памяти Java тем или иным способом.

Лекарство:
Если бы выбираете из разных таблиц на различных этапах, подумайте ещё раз, вдруг вы можете выразить ваши запросы одним.

6. Использование DISTINCT или UNION для удаления дубликатов из случайного декартова произведения


Из-за сложных соединений (JOIN) любой разработчик может потерять след в значащих связях SQL запроса. Если конкретнее, то при использовании связи с составными внешними ключами можно забыть добавить значащие предикаты в JOIN… ON утверждения. Это может привести к дублированию строк всегда или только в исключительных ситуациях. Тогда некоторые разработчики могут добавить оператор DISTINCT для прекращения дублирования данных. Это не правильно по трём причинам:
— Это может излечить последствия, но не причину. А ещё это может не решить последствия при граничных условиях.
— Это медленно для больших выборок. DISTINCT выполняет ORDER BY операцию для удаления дублирования.
— Это медленно для больших декартовых произведений которые всё равно будут загружены в память.

Лекарство:
Как правило, если Вы получаете нежелательные дубликаты, пересмотрите свои JOIN предикаты. Вероятно там где-то образовалось небольшое декартово произведение.

7. Избегание оператора MERGE


На самом деле это не ошибка, но, возможно, это отсутствие знаний или страхи мощного оператора MERGE. Некоторые БД знают другие формы UPSERT оператора, например MySQL ON DUPLICATE KEY UPDATE. На самом деле MERGE очень мощен, особенно в БД, которые сильно расширяют SQL стандарт, таких как SQL Server.

Лекарство:
Если Вы делаете UPSERT, выстраивая цепочку из INSERT и UPDATE или SELECT… FOR UPDATE и INSERT/UPDATE, задумайтесь ещё раз. Вместо риска гонки за ресурсами, вы можете написать более простое MERGE запрос.

8. Использование агрегатных функций вместо оконных функций


Перед появлением оконных функций, единственным средством для агрегации данных в SQL было использование GROUP BY вместе с агрегатными функциями в проекции. Это хорошо работает в большинстве случаев, и если агрегированные данные должны быть наполнены обычными данными, то сгруппированный запрос может быть написан в присоединённом под запросе.
Но SQL:2003 определяет оконные функции, которые реализованы многими поставщиками БД. Оконные функции могут агрегировать данные на не группированных выборках. По факту, каждая оконная функция поддерживает свою собственную, независимую PARTITION BY операцию, которая является отличным инструментом для построения отчётов.

Использование оконных функций позволит:
— Построить более читаемый SQL (меньше выделенных GROUP BY выражений в под запросах)
— Улучшить производительность т.к. RDBMS может легче оптимизировать оконные функции

Лекарство:
Когда вы пишите GROUP BY выражение в под запросе, задумайтесь, может ли он быть выражен оконной функцией?

9. Использование сортировки в памяти при разных параметрах


Оператор ORDER BY поддерживает множество типов выражений, включая CASE, который может быть очень полезен при определении параметра сортировки. Вам никогда не следует сортировать данные в памяти Java только потому, что:
— SQL сортировка слишком медленная.
— SQL сортировка не может сделать этого.

Лекарство:
Если вы сортируете какие-либо SQL данные в памяти Java, задумайтесь, возможно ли перенести эту сортировку в БД? Это отлично сочетается со страничной разбивкой в БД.

10. Поочерёдная вставка множества записей


JDBC знает, что такое пакет (batch), и Вам следует использовать это. Не делайте INSERT тысяч записей одной за другой, создавая новый PreparedStatement каждый раз. Если все ваши записи идут в одну таблицу, создайте партию INSERT запросов с одним SQL запросом и несколькими связываемыми наборами данных. В зависимости от вашей БД и её конфигурации, что бы сохранить UNDO лог чистым, Вам может потребоваться делать commit спустя какое-то количество вставленных записей.

Лекарство:
Всегда используйте пакетную вставку больших наборов данных.

Несколько интересных книг на тему

SQL Antipatterns by Bill Karwin
SQL Performance Explained by Markus Winand

Only registered users can participate in poll. Log in, please.

Хотели бы Вы увидеть перевод продолжения статьи?

  • 75.4%Да564
  • 24.5%Нет184
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 32

    +7
    Почему заголовок такой желтый? Если пишете советы по правильному написанию SQL-запросов, то и статью называйте соответственно. При чем тут вообще Java-программисты?

    Чтобы написать запрос, который «положит» базу, не обязательно быть программистом вообще, достаточно просто иметь доступ к БД. Конечно, программистов, неоптимально использующих ресурсы СУБД немало, но если Вы пишете конкретно про Java, до хотя бы статистику какую-то дайте, что именно на Java косячат больше всех, а Си, PHP, Delphi и остальные белые и пушистые.

    PS Да, я Java-программист, и судя по отсутствию комментариев по поводу заголовка, хаб Java читают в основном не Java-программисты…
      +4
      Это перевод.
      Почему заголовок желтый, если автор даёт советы, опираясь на технологии Java? В нашей профессии не стоит воспринимать каждое «желтое» утверждение на свой счёт.
        –2
        «опираясь на технологии Java»

        Хорошо, давайте пройдемся по конкретике:
        «Обработка данных в памяти Java», «Использование JDBC», «Соединение данных в памяти Java» — в общем-то и всё. В других ЯП нет памяти и коннекторов к БД? Вот скажите, какой именно из 10 пунктов неприменим к другим ЯП?
          +1
          Я с вами согласен, мне не хотелось уходить слишком далеко от оригинала, это ведь перевод.
          Но в целом вы правы, и т.к. хабр — самомодерирующееся сообщество, переименовал статью.
            –4
            Спасибо! Мне, правда, даже как-то легче стало на душе…
              +1
              при чтении статьи, вообще не обращал внимания на слово JAVA. Вы, я так понимаю, ява программист ?;)
                +1
                Да, я Java программист, думаю по комментариям это сразу бросается в глаза :)

                Я считаю, что автор статьи абсолютно неправ, связывая незнание SQL/принципов работы СУБД и какой-либо конкретный язык программирования (а переводчик неправ, защищая его точку зрения).

                Мне не раз встречались, например, системные администраторы, не имеющие никакого отношения к программированию, которые одним простым запросом давали нагрузку на базу в тысячи раз большую, чем любой запрос, отправляемый из ПО. Любимая ошибка многих — в условии ограничения выборки взять в кавычки значение, накладываемое на числовое поле (или наоборот). Результат: мало того, что индексы не работают, так еще и выполняется конвертация значений поля во всех записях таблицы.

                Похожая ошибка у программистов — при накладывании ограничений по дате применять функцию приведения значения не к передаваемому условию, а к полю в БД: вместо "to_date(моё_значение) = поле_таблицы" делать "моё_значение = to_чтонибудь(поле_таблицы)".
      +3
      15 минут рисовал на листочке про NULL. Не понял, в чем тут заблуждение?! В том, что надо понимать приоритет операций? Так они скобками обозначены. Или это перевод такой, а на самом деле это просто ошибка? Как это вообще связано с тем, что кто-то чего-то в Java переносит в SQL? Разорвано повествование. Перевод вообще какой-то странный, я таких терминов нагуглить даже не могу, «со строковым значимым выражением». В общем ужасно, прочитал, ничего нового не узнал, а изломал весь «язык».
        0
        Wikipedia
        При сравнении NULL с любым значением будет получен результат NULL, а не FALSE и не 0. Более того, NULL не равно NULL!
          +1
          Простите, вы читали мой комментарий? И свой перевод? Причем тут вырезка из 3 ресурса? Я про предикаты, если вы не поняли. Как мне кажется, даю это понять указывая слова: приоритет операций, «со строковым значимым выражением».
          А то, что NULL в SQL несколько иной (вернее его поведение) это известно любому, мало-мальски разбирающемуся, человеку в SQL.
            0
            «со строковым значимым выражением»

            Думаю, что имелась ввиду ситуация в Oracle, где пустая строка есть NULL. И этот NULL ведет себя не всегда логично: любая операция с NULL в результате должна давать NULL, но в случае с конкатенацией строк это утверждение неверно. И в то же время функция LENGTH('') вместо 0 выдаст NULL.

            P.S. Последняя используемая мною версия Oracle — 10.x.x.x
              +1
              По ссылке перейдите, там имеется ввиду совершено другое. Там разбирается предикат NOT и IS NOT NULL и IS NULL. Строка как тип тут ни при чем, это видимо автор перевел так Row.
                0
                И в то же время функция LENGTH('') вместо 0 выдаст NULL
                Насколько я помню в Oracle весьма странно реализовано хранение в строке NULL-значения и '', потому и результат такой. Имеющиеся под рукой PostgreSQL и MS SQL дают ожидаемый результат.
                  0
                  На самом деле, то, что пустая строка IS NULL, только сначала доставляет неудобства. Это действительно удобно, т.к. не нужно делать лишние проверки при фильтрации. Если бы ещё таких вот несоответствий не было, вообще была бы лепота.
          +1
          мозгодробительный перевод! «партия (batch)»… общепринято — «пакетный набор» и т. п.
            +3
            > Большинство БД поддерживают какие-то средства для постраничной разбивки через LIMIT
            Ох если бы. Последний раз когда я пытался собрать вариации LIMIT для разных СУБД все крутые и дорогие СУБД заставляли меня рыдать.

            Вот такая вышла подборка (если в чем ошибки — извиняйте, делалось на скорую руку):
            подборка
            # SqLite
            Select * from Table LIMIT {count} OFFSET {offset}
            Select * from Table LIMIT {offset},{count}

            # Hypersonic SQL
            SELECT LIMIT {offset} {limit} * FROM Table

            # MySQL:
            SELECT * FROM Table LIMIT {offset}, {count}

            # Postgree SQL:
            SELECT * FROM Table LIMIT {count} OFFSET {offset}

            # Apache Derby
            SELECT * FROM Table OFFSET {offset} ROWS FETCH NEXT {count} ROWS ONLY;

            # MS SQL 2005+
            SELECT t1.*
            FROM (
            SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
            FROM ( SELECT * from Table ) t1
            ) t2
            WHERE t2.row BETWEEN @offset+1 AND @offset+count;

            # MS SQL 2000:
            SELECT TOP offset *
            FROM Table
            WHERE Id NOT IN (
            SELECT TOP count Id
            FROM Table
            ORDER BY Id
            );

            # Oracle
            select * from
            ( select a.*, ROWNUM rnum from
            ( <your_query_goes_here, with order by> ) a
            where ROWNUM <= :MAX_ROW_TO_FETCH )
            where rnum >= :MIN_ROW_TO_FETCH;

            # IBM DB2, version 1:
            SELECT * FROM (SELECT * FROM Table
            ORDER BY Id DESC FETCH FIRST {offset} ROWS ONLY ) AS t1
            ORDER BY t1.id ASC FETCH FIRST {count} ROWS ONLY

            # IBM DB2, version 2:
            SELECT *
            FROM (
            SELECT row_number() OVER ( ORDER BY Id ) AS rid, *
            FROM Table
            ) AS t
            WHERE t.rid BETWEEN {offset+1} AND {offset}+{count};

            # Sybase:
            * в Sybase нужно провести рисерчь о «set rowcount», зарыдать и сдаться пойти писать эмуляцию rowcount, с которой потом пытаться сделать то же что в Oracle, DB2 и MS SQL *

              0
              Дополню:
              --Firebird
              SELECT FIRST {count} [SKIP {offset}] FROM Table
              

                0
                -- MS SQL 2012+
                SELECT * 
                FROM Table 
                ORDER BY column 
                OFFSET {offset} ROWS FETCH NEXT {count} ROWS ONLY;
                
                  0
                  Sybase разный и это компания была такая. В SQL Anywhere есть нормальное TOP {n} START AT {m} (точно не помню, вроде ещё через LIMIT...OFFSET есть), а вот Enterprise они не любят.
                    0
                    Ваша правда.
                    В тексте же имелся в виду Sybase ASE какой-нибудь средне-бородатой версии.
                      0
                      Полагаю что мало что там изменилось с тех пор, да и IQ вроде как ногами из ASE растёт.
                  +3
                  А может просто почитать книгу про то как писать SQL и не будет тогда проблем с парадигмами программирования?
                    –2
                    Но JOIN'ы в самом деле выполняются медленно. Особенно на больших объёмах данных. Зачастую куда выгоднее отдать соединение на клиентскую (относительно СУБД) часть, чем грузить сервер.
                      0
                      Клиентская часть может быть ещё медленнее.
                      Я придерживаюсь правила что все необходимые данные я должен получить в уже готовом виде и по возможности (даже если данные логически не связаны) единственным запросом. И довольно странно обрабатывать данные на платформе, которая не заточена под обработку больших об'ёмов.
                        +2
                        Клиентская часть почти наверняка будет медленнее в абсолютных значениях, зато она гораздо лучше масштабируется горизонтально (серверов приложений можно наставить сколько угодно, с отдельными клиентскими приложениями ещё проще), в то время как СУБД под тяжёлыми запросами может стать бутылочным горлышком, которое расширить будет существенно сложнее.

                        Из практики, у нас в проекте используется Firebird (архитектура сервера СУБД), в БД есть одна достаточно большая таблица (~100 полей, несколько миллионов записей, постоянно обновляемая, ~3/4 полей — ссылки на другие таблицы-справочники). Поскольку справочники обновляются существенно реже и их величина существенно меньше, их содержимое кэшируется на клиенте, а выборка по большой таблице идёт без объединений. И это на практике работает в разы быстрее, чем с объединениями (в зависимости от количества необходимых для отображения полей).

                        Я понимаю, что это сильно зависит от используемой СУБД, и FB зачастую теряет голову от обилия полей и индексов, но в общем случае объединение операция достаточно накладная и как поведёт себя планировщик запроса, предсказать не всегда возможно (а ещё его поведение может, например, отличаться от версии к версии или измениться после пересчёта статистики индексов по БД). Поэтому если выборка идёт по большому объёму данных, а результатом её является маленький объём данных, то лучше перебдеть, чем в какой-нибудь прекрасный момент повесить СУБД.
                      0
                      11. Если мы говорим о Java, то еще можно добавить избегание всяческих ORM фреймворков. ORM парадигма представляет граф объектов как если бы они лежали в памяти, автоматически запрашивая данные из базы. Соответственно пользователь пишет код, не задумываясь о том, как это реально выполняется. На настольной системе все работает и выглядит красиво. С реальными же объемами данных наступают проблемы.
                      P.S. Недавно открыл для себя jOOQ.

                      > 4. Использование JDBC для постраничной разбивки большой выборки
                      Как правило JDBC драйвер используют нативные средства разбивки предоставленные производителем, которые работают так же эффективно, как и SQL
                        0
                        избегание всяческих ORM фреймворков

                        ORM фреймворки — это лишь инструмент. В умелых руках ORM делает в точности то, что от него требуется, в неумелых же даже чистый SQL может работать хуже ORM. А уж если писать код "не задумываясь о том, как это реально выполняется", то и без СУБД можно такое Г сваять, что мама не горюй…

                        Насчет «реальных» объемов данных: я 10+ лет в Enterprise Java, на всех проектах ORM Hibernate, и мне ни разу не встречались такие объемы данных, при которых проблемы с производительностью возникали бы из-за применения ORM, а не из-за кривых рук программиста. Да, мне не довелось разрабатывать для майл.ру или гугла с их объемами, также, как и 99.9-ти процентам программистов мира. Максимум, с которым довелось поработать — десятки миллионов записей и производительность в десятки миллионов запросов к этим записям в сутки.

                        Так что, Вы, мягко говоря, рано крест ставите на ORM…
                          0
                          Это понятно, что при правильном использовании ORM также эффективен. Но мой опыт работы в реальных проектах показывает, что ORM везде используется неэффективно. Знание принципов работы ORM требует большей подготовки, нежели просто знание SQL, а его использование — меньшей. Поэтому сайтоклепатель или джавист-джуниор с легкостью напишет:
                          for ( Invoice in: em.createQuery(«SELECT i FROM Invoice i»).getResultList() ) {
                          … in.getClient().getName();
                          }
                          Для него это логично, несмотря на то, что клиент лежит в другой талице, и будет запрашиваться для каждого счета. Если Вы работаете в команде над достаточно большим проектом, за этим не уследить. Тем более что сам дизайн ORM всячески агитирует всех так делать.

                          В последнем проекте пришлось работать с относительно небольшим объемом связанных специальным образом данных, для которых приходилось производить процедуру проверки на целостность — много массивных запросов и джоинов. В итоге:
                          — 3 багрепорта в Hibernate JRA: проблемы связаны с compound PK: некорректной генерацией JOIN-ов для H2, некорректным связыванием в IN(), некорректной генерацией UPDATE WHERE x IN(SELECT...)
                          — 2 багрепорта в EclipseLink: неверной генерацией NOT IN(SELECT...), неверной генерацией UPDATE WHERE x IN(SELECT...)
                          При этом использовались последние версии обеих ORM и базы Oracle/H2.
                          — Стандарт ORM сильно ограничивал возможности запросов. В частности не поддерживаются: подзапросы FROM (SELECT), JOIN-ы между любыи сущностями (только те, для которых определено отношение в ORM).
                          — странности в поведении при попытке делать merge сущности с коллекцией элементов, замепленных в другую таблицу (EclipseLink).
                          — непредсказуемость, обусловленная внутренним кешированием объектов: UPDATE не изменяет полей объекта, если он ранее где-то испльзовался и был запрошен. Повторный SELECT и em.find() опять вернет старую версию объекта (тем не менее WHERE будет реагировать на изменения). Единственно верный способ — вызывать em.refresh() для каждого объекта (долго).
                          — сложности в передаче объектов по сети (deproxying, lazy fetch).

                          В итоге я не увидел практически никаких преимуществ использования ORM в проекте перед голым SQL-ем. Автоматический меппинг данных в структуры в состоянии написать любой java-программист. Библиотеки вроде jOOQ и QueryDSL делают код запросов typesafe и независимым от СУБД, полагаясь на SQL.
                            0
                            Согласен, ORM подталкивает к неэффективному использованию ресурсов СУБД. И, да — бывают неявные побочные эффекты и ошибки фреймворков (у себя в блоге не так давно писал об этом). Но, как мне кажется, главная задача ORM — чистота кода, к сожалению, нередко за это приходится платить ресурсами СУБД. Но ведь апгрейд даже фирменного «железа» стоит меньше, чем оплата труда программистов. Я потому и писал про личный опыт с объемами данных — в большинстве случаев (по крайней мере, в моей практике) можно пренебречь двух-трехкратным увеличением нагрузки на СУБД, в угоду чистоте кода, который легче поддерживать.

                            Вообще, насчет производительности СУБД мне понравилась фраза, которую написали в анонсе JBoss DataGrid. Это технология распределенного кеширования данных, и они написали о том, что она может сильно пригодиться тем, у кого нет нормальной СУБД (не дословно, но смысл примерно такой). Я это к тому, что Enterprise проекты (которые очень любят ORM) обычно крутятся на серьезных СУБД, например, Oracle. Я не специалист по СУБД, и ничего не рекламирую, но с Oracle я не включаю даже базовых функций кеширования, встроенных в Hibernate потому, что уверен на 100% в том, что Oracle гораздо лучше знает что и как кешировать.

                            По поводу ваших проблем с джойнами и прочими сложными запросами: лично я никогда не формирую сложные запросы на языке ORM (в моем случае Hibernate-овский HQL). В Hibernate отличная поддержка native query: можно отдать Hibernate-у чистый SQL, а получить в ответ замапленные сущности (т.е., те же, что вернул бы HQL).

                            Насчет Вашего последнего абзаца — очень, очень спорное заявление. То, что "в состоянии написать любой java-программист", должен будет когда-то поддерживать и дорабатывать другой java-программист, и с почти 100% уверенностью можно сказать, что проклятий в сторону первого будет немало. ORM, кроме непосредственно технологий, являются еще и неким подмножеством языка, знакомым большинству программистов в отрасли. Когда приходит новый человек на проект и видит Hibernate, у него вряд ли возникнет вопрос «зачем это здесь», а вот если он видит очередной велосипед… Опять же, на личном опыте: 10 лет назад, когда я был совсем джуниор, старший программист решил внедрить ORM в один из общих модулей проекта. Я тогда разве что головой об стол не бился, пытаясь понять какой велосипедист придумал Hibernate, а потом проникся. Я сейчас даже в микропроектах его использую, очень удобно…
                              0
                              ORM следует использовать ОЧЕНЬ осторожно на больших объемах данных.
                              Да и на маленьких тоже, особенно когда начинаются каскадные операции средствами Hibernate и много-много действий в пределах одной транзакции. Особенно все усугубляется при использовании JPA на кластере.
                              При использовании подобных инструментов сервисы для работы с БД должны быть очень хорошо продуманными, и делать их должен хорошо прокачанный спец. А остальные юзают имеющиеся интерфейсы. Да, и, кстати: долой LAZY-инициализацию! Лучше покрыть код тестами и доставать ровно то, что нужно. Иначе длительные раздумия над неэффективными запросами светят вам до конца проекта. Если он вообще доживет до конца. :-)
                                +1
                                Как ни печально, в наших реалиях лишь 5-10% разработчиков серверного кода понимают и умеют работать с разными типами блокировок и уровнями изоляции транзакций.
                                  +1
                                  "На больших объемах данных" вообще ВСЁ следует делать осторожно, "да и на маленьких тоже" ;) Опять же личный опыт: пару месяцев назад промышленный сервер приложений начал грузить СУБД под 100%, в конце-концов «съев» долгими (от нескольких секунд до 10-20 секунд каждый) запросами все свободные соединения к БД. Когда начали разбираться, оказалось, что один из разработчиков, создав кучу индексов в тестовой базе, забыл добавить в сборку скрипт на создание одного из них. Отсутствие одного только индекса «положило» критичную промышленную Систему, причем на запросах к маленькой по меркам Oracle таблице (200-300 тысяч записей). Имеет ли это какое-то отношение к ORM? Нет, т.к. база нагружалась еще до того, как дело доходило до выборки Hibernate-ом «неоптимальных» каскадных данных.

                                  "усугубляется при использовании JPA на кластере" — даже не знаю, к чему Вы это. Я две легаси Системы переводил на кластерную конфигурацию, и не припомню, чтобы были проблемы с ORM. Вообще, ни одной проблемы, по крайней мере, появившейся именно из-за перехода на кластер. Да, конечно, пришлось менять логику, делать синхронизацию, но подвохов от ORM не было, т.е., если бы Hibernate не применялся в проекте, переход не стал бы проще или быстрее.

                                  "лишь 5-10% разработчиков серверного кода понимают и умеют" — только в этом и кроется главная проблема с производительностью СУБД. Ни конкретный язык программирования, ни применение/отсутствие ORM не играют столь же ощутимой роли, как степень «кривизны рук» разработчика.

                                  PS Насчет широко распространенного мнения о том, что ORM неоптимально выбирает из БД кучу ненужной информации: если ваша бизнес-логика сделана так, что, например, для отображения списка каких-либо документов требуются данные из 10-ти таблиц, то хоть с ORM, хоть без него — вам таки придется вытащить эту «кучу ненужной информации» и показать пользователю. Поэтому, проблемы повышенной нагрузки на СУБД гораздо эффективней решать пересмотром логики/архитектуры Системы, а не плевками в сторону ORM. Если переиначить известную народную мудрость: плохому программисту ORM мешает… ;)

                      Only users with full accounts can post comments. Log in, please.