Доктрина запускает слишком много запросов с внутренним соединением - PullRequest
0 голосов
/ 03 октября 2018

Учитывая этот код, Doctrine запускает столько запросов, сколько строк у меня в таблице2

$qb = $this->getModelManager()->createQuery($er->getClassName(), 't1')->getQueryBuilder();

$qb->select('t1, t2, t3')
   ->innerJoin('table1.table2', 't2');
   ->innerJoin('table2.table3', 't3')
   ->where('t3.id = :foo')
   ->setParameter('foo', $foo);

, каждый запрос похож на этот:

SELECT t0.id AS id_1,
       t0.name AS name_2, 
       t0.slug AS slug_3,
       t0.description AS description_4, 
       t0.visible AS visible_5 
FROM table2 t0 
WHERE t0.id = ?

, и это сущности:

TABLE1: основная сущность witch связана с таблицей 2 manyToOne, если я сделаю innerJoin с таблицей 2, Doctrine будет действовать как ожидалось (1 запрос)

/**
 * @ORM\Entity(repositoryClass = "Table1Repo")
 * @ORM\Table(name="table1")
 */
class table1 extends BaseTable1 implements table1Interface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Gedmo\Versioned
     */
    protected $name;

    /**
     * @ORM\ManyToOne(targetEntity="table2", inversedBy="tables1")
     * @ORM\JoinColumn(name="table2_id", referencedColumnName="id", onDelete="CASCADE")
     */
     protected $table2;
}

TABLE2, связанной с таблицейодин от OneToMany и с таблицей 3 от ManyToMany.

/**
 * @ORM\Entity(repositoryClass="table2Repository")
 * @ORM\Table(name="table2")
 */
class table2 extends Basetable2
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="table3", inversedBy="table2s")
     * @ORM\JoinTable(name="table3_table2")
     */
    protected $table3;

    /**
     * @ORM\OneToMany(targetEntity="table1", mappedBy="table2")
     * @Accessor(getter="getTables1")
     */
    protected $tables1;
}

TABLE3: oly, связанный с таблицей 2 отношением ManyToMany.Когда я делаю innerJoin с таблицей 2, Doctrine по-прежнему работает, как и ожидалось, делая только один запрос

/**
 * @ORM\Entity(repositoryClass = "table3Repo")
 * @ORM\Table(name="table3")
 * @Gedmo\Loggable
 */
class table3 extends Basetable3
{
    /**
     * @ORM\Id 
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="table2", mappedBy="tables3")
     * @ORM\JoinTable(name="table3_table2")
     */
    protected $tables2;
}

Итак, когда я добавляю оба innerJoins в построитель запросов, Doctrine делает только один запрос, но когда ядобавьте предложение WHERE, когда Doctrine выполняет 279 запросов, по одному на строку в таблице 2, ведьма связана с таблицей 1 с помощью oneToMany и с таблицей 3 с помощью ManyToMany.

Другой важный момент заключается в том, что построитель запросов выполняется под управлением SonataAdmin query_builderопция поля.

Я не могу понять, почему у меня такое поведение, какая-либо подсказка?

1 Ответ

0 голосов
/ 03 октября 2018

Когда вы запускаете запрос, вы всегда должны иметь корневую сущность, которая присоединяется к другим.В вашем случае это table1.После выборки на основе метаданных запроса и сущности Doctrine попытается создать объект для каждого экземпляра root, но , если не указано иное , остановится на этом.Фактически, для каждого подобъекта (например, table2) он создаст фиктивные «прокси» объекты, которые являются едва поверхностными представлениями и должны разрешаться из БД всякий раз, когда они пытаются разыменовать их.Процесс преобразования результатов БД в объекты известен как гидратация объектов.

Чтобы выполнить гидратацию подобъектов, вам также необходимо «выбрать» подобъект:

$qb->select('t1', 't2', 't3')
    ->innerJoin('t1.table2', 't2');
    ->innerJoin('t2.table3', 't3')
    ->where('t3.id = :foo')
    ->setParameter('foo', $foo);

Обратите внимание, чтобы не сходить с ума от извлечения всего, так какзанимает больше времени и потребляет значительно больше оперативной памяти.Точно настраивайте свой запрос, пока не достигнете желаемого (логика и производительность).

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...