Как стать автором
Обновить
1
0.1
Andriy Slobodyanyk @Slobodator

Java Developer

Отправить сообщение

Если это поле таки прочиталось, то получите бесполезное обновление

Это не так в случае lazy-скаляров. Когда они у вас заработают, посмотрите, как ведёт себя обновление.

Опять же, с Lazy имеем кучу проблем, таких как n+1

Любая Lazy-загрузка -- это потенциальная N+1 проблема. Но одновременно и очевидный прирост производительности. `fetch = FetchType.EAGER` вы же над коллекциями не ставите, верно?

и работа за пределами транзакций

Я не вполне понимаю, что вы имеете в виду, хотя и догадываюсь. Как вы работаете с lazy-коллекциями "за пределами транзакций"? C lazy-скалярами всё то же самое.

пример для h2

БД значения не имеет, lazy-loading делает хибернейт.

без танцев с бубнами

Byte enhancement -- это валидный инструмент, а не танцы с бубном. Поскольку String -- final class, а не интерфейс, по-другому, увы, никак, хотя ещё ленивую загрузку LOB-a можно сымитировать с наследуемым классом (но там свои компромиссы), если byte enhancement почему-то смущает.

Видно, что никакой ленивой загрузки нет

Это пока нет) А внимательно перечитаете мой самый первый комментарий, погуглите -- уверен, заработает. Хинт: IDEA компилирует сама, byte enhancement не делает, поэтому запускайте тест напрямую с maven/gradle, вот "баг" на эту тему https://youtrack.jetbrains.com/issue/IDEA-159903/Hibernate-bytecode-instrumentation-code-is-being-overridden-by-IDEA

Гм, раз вы меня дважды упрекаете, что я невнимательно читаю статью, придётся нарушить правило "overquoting -- зло".

Все примеры проверялись на Oracle и Postgres. Писались только изменённый поля.

Конечно, в любом случае пишутся только изменённые поля. Вопрос в том, что происходит под капотом БД. В случае Postgres мы имеем Vacuum, подробнее https://rbranson.medium.com/10-things-i-hate-about-postgresql-20dbab8c2791 раздел "#4: MVCC Garbage Frequently Painful". Для Oracle это не так, поэтому я и вставил оговорку "скорее всего".

>Во-вторых, "дефолтный" update-запрос по всем полям кешируется, а динамические будут каждый раз парсится

Современные СУБД решают эту проблему

Это очень смелое утверждение. Можете, пожалуйста, привести аргументы/доказательства?

Вы же сами начинаете с

Hibernate генерирует операторы SQL для операций CRUD всех объектов. Эти инструкции SQL генерируются один раз и кэшируются в памяти для повышения производительности.

Мой поинт в том, что "дефолтный" update по всем полям был сделан так именно из кеширования. Более того, даже in-clause (если уж приходится им пользоваться) на разном количество параметров оптимизуют с помощью hibernate.query.in_clause_parameter_padding, подробнее https://vladmihalcea.com/improve-statement-caching-efficiency-in-clause-parameter-padding/

Разница в поведении будет заметна, конечно, только под нагрузкой.

>Если не записывать обновленный LOB -- тогда и читать его не надо

Странное утверждение. 

Вы пишете

...операция обновления может стоить очень дорого... размер полей большой (например, LOB). Решить эту проблему поможет аннотация для сущности @DynamicUpdate.

Действительно, если в сущности есть LOB, он будет а) вычитываться из БД всегда, б) попадать в дефолтный update, даже если не изменился. Это не оптимально. Вы предлагаете @DynamicUpdate , а я предлагаю сделать его LAZY . Для этого не обязательно выносить его в отдельную таблицу.

>Отслеживание изменений полей -- dirty checking -- происходит всегда

Я обратного и не утверждал. 

Тем не менее, в статье есть

Или накладные расходы на отслеживание, или на запрос, содержащий все столбцы. 

Накладные расходы на отслеживание -- dirty checking -- происходит всегда*, @DynamicUpdate на них не влияет.

*всегда -- имеется в виду а) транзакция не read-only, б) сессия не stateless

Я описал ситуации, когда данная технология будет уместна, равно как и проблемы. 

А я пишу возражения к этими ситуациям, что, прежде чем браться за @DynamicUpdate:

  • если поле не обновляется вообще никогда, лучше его аннотировать @Column(updateable = false)

  • если в сущности LOB, есть смысл задуматься, не загружать ли его лениво

  • если в сущности много полей, а в разных бизнес-кейсах обновляются только некоторые из них, возможно, @DynamicUpdate будет оправдан. Осталось разобраться и померять, что такое "много" и "некоторые", и какой такой дизайн и кейсы получились.

я лично встречался с ситуациями, когда @DynamicUpdate резко повышал производительность

При всём уважении к вашему авторитету, ссылка на маленький тест демонстрирующий разницу между обычным обновлением и динамическим, была бы куда более весома. Пока я предполагаю, что таким образом (вместо lazy) боролись с LOB-ами.

Повторюсь,

без измерений под нагрузкой от @DynamicUpdate скорее всего будет псевдо-радость от "оптимизированных" SQL-запросов в логах и незначительная деградация производительности.

С in-clause вообще лучше быть осторожным. В постгресе вроде бы ограничений нет, а в оракле, например, по дефолту не более 1000 аргументов -- соответственно, надо разбивать на чанки и конкатенировать результат.

Если бизнес-логика позволяет (как в данном конкретном случае), имеет смысл предварить в репозитории

interface ArticleRepository extends CrudRepository<Article, UUID> {
  default List<Article> findByPublisherId(List<UUID> ids) {
    if (ids.isEmpty()) {
     return Collections.emtpyList();
    }
    return _findByPublisherId(ids);
  }
  
  @Query("from Article where publisherId in :ids")
  List<Article> _findByPublisherId(List<UUID> ids);
}

Если метод совсем безобразно могут вызывать, ещё и проверку на null добавить.

По поводу @DynamicUpdate -- спорно.

  1. Во-первых, в MVCC базах скорее пишется новое состояние записи целиком, а не отдельные поля.

  2. Во-вторых, "дефолтный" update-запрос по всем полям кешируется, а динамические будут каждый раз парсится -- правда, не уверен, на какой нагрузке это будет актульно.

  3. Если не записывать обновленный LOB -- тогда и читать его не надо, либо вынести его в наследуемый класс, либо `@Basic(fetch = FetchType.LAZY)` c hibernate-enhance-maven-plugin.

  4. Отслеживание изменений полей -- dirty checking -- происходит всегда, если транзакция не read-only, @DynamicUpdate тут не влияет.

  5. @DynamicUpdate может быть актуален, если "дефолтный" update по всем полям зацепляет поле, которое а) не изменилось б) но в БД на него повешен триггер и происходит какой-то side effect.

В общем, без измерений под нагрузкой от @DynamicUpdate скорее всего будет псевдо-радость от "оптимизированных" SQL-запросов в логах и незначительная деградация производительности.

Информация

В рейтинге
3 543-й
Откуда
Абу Даби, Абу Даби, О.А.Э.
Зарегистрирован
Активность