Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MikroORM does unnecessary JOINs when matching values on primary keys expliciting the PK column #549

Closed
darkbasic opened this issue May 6, 2020 · 1 comment
Assignees
Labels
bug Something isn't working
Milestone

Comments

@darkbasic
Copy link
Collaborator

@Entity()
export class Message extends BaseIdEntity {
  @ManyToMany({pivotTable: 'message_to_deletion'})
  deletions: Collection<User> = new Collection<User>(this);
em.find(Message, {
  group: groupId,
  deletions: 1,
});

The previous query matches a primary key on the M:N deletions field, without explicitly mentioning the PK column. This is the sql it generates:

select "e0".*, "e1"."message_id", "e1"."user_id"
from "message" as "e0"
left join "message_to_deletion" as "e1"
on "e0"."id" = "e1"."message_id"
where "e0"."group_id" = 1 and "e1"."user_id" = 1

In the following one, instead, we explictly specify the PK column (id):

em.find(Message, {
  group: groupId,
  deletions: {id: 1},
});
select "e0".*
from "message" as "e0"
left join "message_to_deletion" as "e2"
on "e0"."id" = "e2"."message_id"
left join "user" as "e1"
on "e2"."user_id" = "e1"."id"
where "e0"."group_id" = 1 and "e1"."id" = 1

As you can see in the generated sql it does an unnecessary JOIN on the user table. The JOIN is unnecessary because we are matching its primary key.

Expected behavior
Avoid a second JOIN when matching PKs.

Additional context
The expected behaviour is surely a desiderable one, but I do get why for semplicity this has been done: if you want to match a PK just use a scalar instead of explicitly specify the PK column.
The problem is that you cannot match null values unless you explicitely specify the PK column, see #548
So fixing this could help to achieve LEFT JOIN / IS NULL-like constraints (see https://explainextended.com/2009/09/15/not-in-vs-not-exists-vs-left-join-is-null-sql-server/) necessary to implement the following type of JOIN:

left_join_is_null

In fact the following snippet succeeds in implementing a LEFT JOIN / IS NULL-like constraint, except for the unnecessary JOIN which is the reason of this bug report:

em.find(Message, {
  group: groupId,
  $or: [{deletions: {id: null}}, {deletions: {$ne: 1}}],
});
select "e0".*
from "message" as "e0"
left join "message_to_deletion" as "e2"
on "e0"."id" = "e2"."message_id"
left join "user" as "e1"
on "e2"."user_id" = "e1"."id"
where "e0"."group_id" = 1 and ("e1"."id" is null or "e2"."user_id" != 1)

Versions

Dependency Version
node v13.14.0
typescript 3.8.3
mikro-orm 3.6.11
pg 8.0.3
@B4nan
Copy link
Member

B4nan commented Jun 7, 2020

Closing as fixed in dev via 24511a6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants