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

Используя jooq 3.19 с неявными путями соединения, в одной таблице генерируются несколько соединений.

  1. Ожидается ли это?

  2. Создают ли несколько соединений в одной таблице проблемы с производительностью?

Пример:

DSL.using( SQLDialect.SQLSERVER2017, new Settings().withRenderImplicitJoinToManyType( RenderImplicitJoinType.LEFT_JOIN ) )
.select( Entity.ENTITY.ID ).from( Entity.ENTITY )
.where( Entity.ENTITY.subEntity()
.entity().subEntity()
.entity().subEntity()
.entity().subEntity()
.entity().NAME.eq( "a" ) )
.getSQL()

он генерирует следующий sql:

"select [ENTITY].[ID] from ([ENTITY] 
left outer join ([SUB_ENTITY] [alias_87004649] 
left outer join ([SUB_ENTITY] [alias_112570288] 
left outer join ([SUB_ENTITY] [alias_55342369] 
left outer join ([SUB_ENTITY] [alias_126614199] 
join [ENTITY] [alias_74449122] 
on [alias_126614199].[ENTITY_ID] = [alias_74449122].[ID]) 
on [alias_126614199].[ENTITY_ID] = [alias_55342369].[ID]) 
on [alias_55342369].[ENTITY_ID] = [alias_112570288].[ID]) 
on [alias_112570288].[ENTITY_ID] = [alias_87004649].[ID]) 
on [alias_87004649].[ENTITY_ID] = [ENTITY].[ID]) 
where [alias_74449122].[NAME] = ?"

Почему этого нельзя было ожидать? Что ты на самом деле пытаешься здесь сделать?

Lukas Eder 11.04.2024 18:06

Привет спасибо. мы пытаемся создать динамический запрос, переведенный с языка rql. но пользователь может писать циклические вещи: "filter=eq(subEntities.subEntities2.entity.name, \"a\")"

Tomi 12.04.2024 09:15

мы преобразуем его без методов пути jooq ...выбираем отдельный "ENTITY"."ID" из "ENTITY" левое внешнее соединение "SUB_ENTITY" на "SUB_ENTITY"."ENTITY_ID" = "ENTITY"."ID" левое внешнее соединение "SUB_ENTITY2" " на "SUB_ENTITY2"."SUB_ENTITY_ID" = "SUB_ENTITY"."ID" левое внешнее соединение "SUB_ENTITY2" на "SUB_ENTITY2"."ENTITY_ID" = "ENTITY"."ID" где "ENTITY"."NAME" = ? и каким-то образом мы ожидали, что использование этих методов неявного пути соединения jooq будет проще. но мы не знаем точно, влияет ли способ выполнения jooq на производительность или jooq может устранить эти дубликаты.

Tomi 12.04.2024 09:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ожидается ли это?

Да, это.

Хотя на первый взгляд кажется, что перемещение по одному и тому же пути внешнего ключа снова и снова бессмысленно, и соединения можно устранить, на самом деле это невозможно. Каждый сегмент пути «ко-многим» может создавать декартово произведение с предыдущими сегментами, точно так же, как это может сделать любое обычное явное соединение «ко-многим». Следовательно, из-за небольшой вероятности того, что такое декартово произведение будет желательным, jOOQ не может предотвратить это без изменения логики запроса, поэтому, если вы скажете jOOQ повторно присоединиться к одной и той же таблице много раз (даже если вы не собираетесь этого делать) , то jOOQ должен будет повторно присоединиться к одной и той же таблице много раз, чтобы реализовать потенциально желаемую логику запроса.

Обратите внимание, что переходы обратно к родительскому элементу фактически исключаются, поскольку их удаление не меняет семантику запроса в вашем случае, поскольку родительский столбец не проецируется:

Создают ли несколько соединений в одной таблице проблемы с производительностью?

Конечно! Это не только приводит к проблемам с производительностью, но и дает неправильные результаты. Похоже, вы включили Settings.renderImplicitJoinToManyType просто для того, чтобы «заставить его работать», не задумываясь о последствиях. Но последствия именно такие, как я сказал. Ваше предложение WHERE теперь дает декартово произведение, чего я сомневаюсь, что вы этого хотите и не ожидаете.

В разделе руководства о неявных соединениях путей ко-многим об этом ясно сказано

Случайные дубликаты объектов не являются основной проблемой, которую могут вызвать такие неявные объединения путей ко-многим. Основная проблема заключается в том, что неявный путь ко многим, помещенный в предложение SELECT или предложение WHERE (и другие предложения), сможет генерировать строки, тогда как на самом деле SELECT только преобразует строки (например, Stream.map()) и WHERE только фильтрует строки (например, Stream.filter() ). Было бы слишком SQL-унидиоматично и запутанно, если бы эти предложения могли эффективно создавать строки.

В вашем конкретном случае вы, вероятно, захотите переместить предикат в подзапрос EXISTS, используя корреляцию пути соединения , например.

ctx
  .select(ENTITY.ID)
  .from(ENTITY)
  .where(exists(
    selectOne()
    .from(ENTITY.subEntity()
      ...
      .entity().NAME.eq("a")
    )
  ))
.getSQL()

Для этого не требуется включать вышеуказанное спорное Settings.renderImplicitJoinToManyType. У вас все еще будет странный путь и ненужные соединения, но, по крайней мере, теперь вы не получите никаких декартовых произведений.

Избавление от циклов

Вы лучше всех знаете свою собственную семантику перевода RQL в jOOQ. Если вы знаете, что можете удалить эти циклы, то лучше всего сделайте это самостоятельно. Я надеюсь, что приведенный выше ответ прояснил, почему jOOQ не может сделать это за вас автоматически.

Другие вопросы по теме