分页器Knp组件的性能糟糕

问题描述

我按照本教程https://symfonycasts.com/screencast/doctrine-relations/pagination

因为我需要一种易于分页查询结果的方法

但是我对执行简单的计数查询需要多长时间感到惊讶。

这是代码

$pagination = $paginator->paginate($manager->getRepository(
App::getProductClassForGroup($selected_group_code))->findAllWithCurrentUserOptions($user->getId()),$selected_page_number,$product_per_page,array('distinct' => false));

我在第四个参数中添加array('distinct' => false),因为我使用外键作为主键(请参见this github issue

查询生成器如下:

$queryBuilder->addSelect('prod');
$queryBuilder->innerJoin($this->_alias . '.product','prod');
$queryBuilder->addSelect('users_bookmarks');
$queryBuilder->leftJoin('prod.users_bookmarks','users_bookmarks',Join::WITH,'users_bookmarks.id = :current_user_id');
$queryBuilder->setParameter('current_user_id',$current_user_id);

这是一个非常简单的查询,甚至没有任何where子句或任何东西。

在这knp pagniator service生成查询

102.11 ms   
SELECT count(p0_.no_product_w2) AS sclr_0 FROM product_nat p0_ INNER JOIN product p1_ ON 
p0_.no_product_w2 = p1_.no_product LEFT JOIN users_bookmark_products u3_ ON
p1_.no_product = u3_.product_no LEFT JOIN User u2_ ON u2_.id = u3_.user_id AND (u2_.id = ?)
Parameters:
[▼
  1
]

这是上一个查询的解释:

EXPLAIN
SELECT count(p0_.no_product_w2) AS sclr_0 FROM product_nat p0_ INNER JOIN product
 p1_ ON p0_.no_product_w2 = p1_.no_product LEFT JOIN users_bookmark_products u3_
 ON p1_.no_product = u3_.product_no LEFT JOIN User u2_ ON u2_.id = u3_.user_id 
AND (u2_.id = 1)
_________________________
# id    select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  p0_     index   PRIMARY PRIMARY 36      24567   100.00  Using index
1   SIMPLE  p1_     eq_ref  PRIMARY PRIMARY 36  test.p0_.no_product_w2  1   100.00  Using index
1   SIMPLE  u3_     ref IDX_A4705D7D9D172915    IDX_A4705D7D9D172915    36  test.p0_.no_product_w2  1   100.00  Using index
1   SIMPLE  u2_     const   PRIMARY PRIMARY 4   const   1   100.00  Using where; Using index

分页生成查询需要 102 ms !!!?

我在做什么错,为什么要花那么多时间?

计数查询花费这么长时间是正常现象吗?我不敢相信 其他网站正在如何管理分页

分页的最佳实践是什么。

我已经尝试自己对分页进行计数,并且我做到了:

#Controller:index
$count_all_row = $manager->getRepository(App::getProductClassForGroup($selected_group_code))->countAll()
#Repository
/**
     * Count all rows
     * @param QueryBuilder|null $queryBuilder If no queryBuilder is provided,a new queryBuilder object is created
     * @return int|null Number of rows
     * @throws noresultException
     * @throws NonUniqueResultException
     */
    public function countAll(?QueryBuilder $queryBuilder = null): ?int
    {
        $queryBuilder ??= $this->createqueryBuilder($this->_alias,($this->_id) ? $this->_alias . '.' . $this->_id : null);
        return $queryBuilder->select('COUNT(1)')->getQuery()->getSingleScalarResult();;
    }

它的工作时间约为5.67毫秒,好得多。

5.67 ms 
SELECT COUNT(1) AS sclr_0 FROM product_nat p0_

我的查询生成器非常简单,因为我只需要获取表包含的行数即可。 但是现在,如果我需要添加其他参数(例如,按标题搜索产品)或获取价格大于50 $的产品...,则需要修改countAll()函数,并在我的函数中查找所有结果仓库...

每次修改仅计算标量结果的函数获取数据结果的函数时,都不是一种好的做法。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)