【问题标题】:Faster pagination with Doctrine 2.1 EXTRA_LAZY associations使用 Doctrine 2.1 EXTRA_LAZY 关联进行更快的分页
【发布时间】:2018-09-21 04:50:28
【问题描述】:

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 魔法进行关联。

谢谢!

【问题讨论】:

    标签: performance symfony doctrine-orm pagination associations


    【解决方案1】:

    您可以使用 Doctrine\ORM\PersistentCollection 的matching function 提供过滤条件,例如:

    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);
    

    "matching()" 如果您的关联定义为“EXTRA_LAZY”,则返回 Doctrine\ORM\LazyCriteriaCollection。

    你可以用后者分页:

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

    使用光标分页

    在某些情况下,需要使用cursor pagination。您可以按照建议通过扩展 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);
    }
    

    基于游标的分页的想法是使用结果行作为起点,而不是偏移量,并获取下一行。正如alternative for using OFFSET 所述,这个想法是用 order by 子句中的条件替换偏移量

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      • 1970-01-01
      • 2014-05-13
      • 2015-06-28
      相关资源
      最近更新 更多