eager fetching через entity graph, чтобы доставать полную entity одним запросом, по итогу, запрос один, померил jprofiler'ом, сам запрос выполняется 18к наносекунд, а на уровне хибера 210 миллисекунд, это хибер такие накладные расходы несет? Даже с учетом маппинга, всяких query-кешэй, first-level кэшей и других абстракций это слишком, на мой взгляд.
https://vimeo.com/267560432 - hibernate против jooq 🙂 Давнишнее видео, но недавно прилетело. Но вообще, там же есть общение по сети, создание объектов и прочая и прочая. Где конкретно просадка в производительности, выяснилось? Что именно оптимизируем?
Сложно сказать, где именно просадка, так как я не вижу этого, в call stack'е просто нет той функции, которая сжирает 90% производительности, но я вижу разницу между jdbc-вызовом самого запроса и вызовом запроса из хибернейта, вероятно, можно попробовать через jstack записать, может тогда пойму. Оптимизируем обычный селект с джоином, он раньше lazy вытягивался, я решил сделать eager, чтоб не плодить запросы при определенных обстоятельствах, но там ботл неком, такое чувство, стал сам хибернейт.
А какой запрос генерируется? Сколько данных вытягивается? jdbc запрос мерился только для выполнения или rowmapper тоже отрабатывал?
Обычный join fetch. 40 записей, и на каждую запись по две-три подзаписи, rowmapper не мерил, но не может быть же, что маппинг настолько долгий.
Его прямо видно в логах, что нужный делается? Не N+1 нигде?
Да, show-sql ставил, все красиво.
возможно ты столкнулся с Cartesian Product Problem
А если план разбора посмотреть этого запроса, как оно будет? У меня пока только мысль, что где-то что-то лишнее тянется.
Сейчас попробую.
Я так понимаю, эта проблема связана с множественными джоинами, а у меня только одна коллекция.
Как то мало слишком, что запрос выполняется в базу за 18 микросекунд
QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Hash Right Join (cost=21.76..38.42 rows=109 width=981) Hash Cond: ((nodeporten1_.project_id = nodeentity0_.project_id) AND (nodeporten1_.node_id = nodeentity0_.id)) -> Seq Scan on node_ports nodeporten1_ (cost=0.00..15.45 rows=218 width=651) Filter: (project_id = '90686c22-9198-4f88-8e68-a37f41344a50'::uuid) -> Hash (cost=21.10..21.10 rows=44 width=282) -> Seq Scan on nodes nodeentity0_ (cost=0.00..21.10 rows=44 width=282) Filter: (project_id = '90686c22-9198-4f88-8e68-a37f41344a50'::uuid)
Действительно, врет jprofiler, 3 миллисекунды в analyze показал.
Ну выглядит не стремно, значит, надо копать в другом месте где-то. Т.е. хибер делает нормальный запрос, он быстро выполняется, но или путь туда занимает много времени (генерация SQL+сеть+ожидание выполнения), или обратно (сеть+обновление кэша+маппинг). Смотреть, что именно тупит. Можно попробовать сделать native SQL и выполнить через EntityManager, чтобы пройти мимо L1, если это он.
Это я на локальной базе проверял, попробую таки через native sql. Спасибо.
Ну блин, если у тебя БД опирается на статистику при построении плана запроса, а она не обновлена, то все может знатно тупить. Если у тебя таблицы огромные, что может не быть HashJoin, например, в плане разбора. С другим набором данных будет другой план разбора. В идеале - смотреть план надо на стейджинге
Ну так проблема и локально, и на стейджинге, так что разницы большой нет.
ты пробовал сырой запрос запрос напрямую в базу отправлять?
Через jdbc? Нет. Через psql - да.
пэйджинация есть какая-то?
Да уж
ты отправлял ровно то, что сгенерил хибер?
А что не так? N+1 лучше что ли? Там запрос типа такого генерируется. Ничего криминального. ``` from nodes n left outer join node_ports np on n.id = np.node_id and n.project_id = np.project_id where n.project_id = '90686c22-9198-4f88-8e68-a37f41344a50'; ```
Должен летать по сути
Смотрите план запроса
Про горячий код слышал? Прогрев ВМ? Ты сейчас измерил температуру на Марсе своим комнатным термометром
а бывает перегрев вм?
Бывает до ядерного взрыва
Ты уверен что тебе нужен Игорь для вытягивания ща раз?) Ты читал как он работает?)
Табличка маленькая, чему там долго тянуться
Ты же видел, что я там написал, что делаю eager fetching через entity граф?
Честно говоря, не совсем понимаю, о чем ты, я же вижу, что работает медленно, и по call stack'у и эмпирически.
Ты как замерял? Сколько раз? Запустил и тут же один раз дёрнул и посмотрел результат?
Сделал 10 запросов, посмотрел среднее, открыл call stack, посмотрел, какие запросы самые долгие, оптимизировал их, и так циклично, пока не дошел до этого.
Ну когда начинаешь что-то оптимизировать, неплохо было бы сначала погонять бенчмарки на гретой jvm, а потом уже оптимизированный код измерять
Там SQL оптимизируется. Температура джвм не особенно показательна будет в этом случае.
Обсуждают сегодня