Search code examples
symfonyjoindoctrine-ormdoctrinequery-optimization

Reducing unnecessary joins in Doctrine


For simplicity sake let there be 2 entities in Symfony. The first one is called Job and the second one Field (category for Job). Each job can belong to multiple fields. Job is aware of it's fields, while the Field entity knows nothing about jobs.

// Job.php

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Field")
 * @ORM\JoinTable(name="job_to_fields",
 *     joinColumns={@ORM\JoinColumn(name="job_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="field_id", referencedColumnName="id")}
 * )
 */
private $fields;

When we want to load all jobs for fields [1, 2, 3], I'd expect something like

SELECT j.*
FROM job j
INNER JOIN job_to_fields jtf ON j.id = jtf.job_id
WHERE /* some other parameters */jtf.field_id IN (1, 2, 3)

In reality Doctrine constructs this SQL statement:

SELECT j.*
FROM job j
INNER JOIN job_to_fields jtf ON j.id = jtf.job_id
INNER JOIN field f ON f.id = jtf.field_id
WHERE /* some other parameters */f.id IN (1, 2, 3)

The second join (to the field table) seams unnecessary. Is there a way to remove this/tell doctrine not to do this?
In theory Doctrine should know about the relation of f.id and jtf.field_id, as it's using them in a join.


Solution

  • This is correct behavior because without that join calling getFields() on a Job object would not have access to the data to display.

    You might be able to affect this by using lazy fetch on your $fields annotation, but if you ever call getFields() it will wind up running further queries to get the data anyway.

    @ORM\ManyToMany(targetEntity="App\Entity\Field", fetch="EXTRA_LAZY")

    But, unless you are addressing a specific issue, I'd let it ride. This is ORM doing what ORM does.