Более быстрая разбивка на страницы с doctrine 2.1 extra_lazy ассоциациями

В Doctrine 2.1 добавлена ​​новая функция загрузки EXTRA_LAZY для ассоциаций: https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html

Эта функция создает новый метод slice($offset, $length) для запроса только страницы ассоциации и очень полезен для разбивки на страницы больших наборов данных.

Однако за кулисами SQL-запрос использует классический синтаксис LIMIT XX OFFSET XX, который работает медленно для больших наборов данных (https://www.eversql.com/faster-pagination-in-mysql-why-order-by-with-limit-and-offset-is-slow/).

Есть ли способ использовать разбиение на страницы с предложением WHERE?

Если нет, как я могу расширить экземпляр Doctrine\ORM\PersistentCollection для создания метода sliceWithCursor($columnName, $cursor, $length)?

Моя главная цель - реализовать более быструю разбивку на страницы, используя очень удобную магию Doctrine для ассоциаций.

Спасибо !

1
0
605
1

Ответы 1

Вы можете использовать функция сопоставления из Doctrine \ ORM \ PersistentCollection, предоставляя критерии для фильтрации, например:

use Doctrine\Common\Collections\Criteria;

$group          = $entityManager->find('Group', $groupId);
$userCollection = $group->getUsers();

$criteria = Criteria::create()
    ->where(Criteria::expr()->eq("birthday", "1982-02-17"))
    ->orderBy(array("username" => Criteria::ASC));

$birthdayUsers = $userCollection->matching($criteria);

«соответствие ()» возвращает Doctrine \ ORM \ LazyCriteriaCollection, если ваша ассоциация определена как «EXTRA_LAZY».

Вы можете перемещаться по страницам с помощью последнего:

$birthdayUsers->slice($offset, $length);

Использование разбивки на страницы курсора

В некоторых случаях требуется использовать пагинация курсора. Вы можете сделать это, расширив Doctrine \ ORM \ PersistentCollection, как предлагается:

public function sliceWithCursor($criteria,  $cursorEntity, $length) {
    $orderBy = $criteria->getOrderings();
    foreach($orderBy as $columnName => $direction) {

        if($direction === Criteria::ASC) {
           $criteria->andwhere(Criteria::expr()->gte($columnName, $cursorEntity->{$columnName}));
        }
        else {
          $criteria->andwhere(Criteria::expr()->lte($columnName, $cursorEntity->{$columnName}));
        }
        $criteria->andwhere(Criteria::expr()->eq("id", $cursorEntity->id)); // exclude cursor entity from the results
    }
    $criteria->orderBy($orderBy));

    $criteria->setMaxResults();
    return $this->matching($length);
}

Идея разбиения на страницы на основе курсора состоит в том, чтобы использовать строку результатов в качестве начальной точки вместо смещения и получать следующие строки. Как указано в альтернатива использованию OFFSET, идея заключается в заменяющее смещение, с условиями из пункта заказа по.

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