Search
Write a publication
Pull to refresh
5
0
Send message

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

И ещё надо учитывать, что БД одна, а приложений тысячи, так что проще вытащить весь объём из БД сразу, чем бомбить её бедную-несчастную лишними запросами.

А в целом, спасибо за совет, конечно. Я не юзал подобный подход, возьму на заметку

>Любая Lazy-загрузка -- это потенциальная N+1 проблема.

А если этих полей несколько, то будет ещё "веселее".

>fetch = FetchType.EAGER` вы же над коллекциями не ставите,

Потому что при работе с коллекциями возникают проблемы при join-ах. Для скалярных свойств нет таких проблем.

Более того, в ManyToOne EAGER по умолчанию, а это неспроста.

>Как вы работаете с lazy-коллекциями "за пределами транзакций"?

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

С коллекциями Lazy используется не только и не столько из-за уменьшения объёма, но и по другим причинам.

>А внимательно перечитаете мой самый первый комментарий, погуглите -- уверен, заработает.

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

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

Равно как и Lazy загрузка может быть полезной в некоторых случаях

Опять же, с Lazy имеем кучу проблем, таких как n+1 и работа за пределами транзакций. Тем более Lazy для скалярных свойств без танцев с бубнами не особо работает. Вот пример для h2:

@Column(name = "LOB")@Lob @Basic(fetch = FetchType.LAZY)private String lob;

При чтении получаем:

"select bt1_0."id",bt1_0."LOB",bt1_0."NAME" from "BIG_TABLE" bt1_0"

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

>Вы предлагаете @DynamicUpdate , а я предлагаю сделать его LAZY

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

>ссылка на маленький тест демонстрирующий разницу между обычным обновлением и динамическим, была бы куда более весом

Могу даже большой тест привести). Например магазины "Магнит" работают в том числе благодаря такой оптимизации. Что может быть весомей? )

>Гм, раз вы меня дважды упрекаете, что я невнимательно читаю статью

Да, невнимательно.

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

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

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

Ко вот только это относится не DynamicUpdate, а к Stateless Session. Просьба таки прочитать статью целиком)

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

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

Почитайте Тома Кайта, например. Там всё популярно описано

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

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

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

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

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

Странное утверждение. Читают данные не с целью потом их записать. Проблему с записью LOB конечно можно решить переносом их в отдельную таблицу, но данная статья не про проектирование БД.

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

Я обратного и не утверждал. dirty checking упоминался в другом разделе, просьба внимательнее читать статью

>но в БД на него повешен триггер и происходит какой-то side effect.

Триггерная логика - это зло, там более если она приводит к побочкам)

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

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

На 5-й версии SUBSELECT  работал, но не работала пагинаци.

Да, все примеры для spring boot 3.

Если не указать @BatchSize, то в Postgres всё считается в коллекцию, потом получите стрим. В Oracle нет такого. Проверял на разных версиях

Всё бы так, но есть пара нюансов

  1. Далеко не всегда SQL запросы занимают одну строчку

  2. При использовании db-specific native query при переключении с СУБД на СУБД (что очень актуально в наше время) придётся править java код, в случае же сохранения запросов в xml ресурсах переключение делается на уровне конфигов.

Сергей, спасибо! Отличная идея и реализация!

Пишите ручками.

Статья как раз для тех, кто не хочет писать ручками, а хочет пользоваться плодами чужого труда. В программировании это благо)

запускать кодогенерацию на каждый билд

Как минимум, нужно запускать при изменении версии API. А если команд, поставляющих каждая свой API, штук десять-двадцать, то это не совсем удобно.

всего api на 100500 методов

Проектируйте API грамотно, и будет вам счастье)

держать в памяти ненужные классы.

Если таки прочитать всю статью, а не только выводы, то будет понятно, что библиотека API содержит только интерфейсы и потребителю совсем нет необходимости загружать все их реализации. Так что тут экономия на спичках. Но опять же, если команда-поставщик грамотно проектирует API.

Ха-ха-ха.

Что может быть проще для потребителя, чем поменять номер версии в gradle? При желании, чтобы получить актуальную версию API, можно даже это действие убрать.

Information

Rating
Does not participate
Registered
Activity