Ужасная производительность компонента Paginator knp

#php #mysql #sql #symfony #database-performance

#php #mysql #sql #симфония #база данных-производительность

Вопрос:

Я следую этому руководству https://symfonycasts.com/screencast/doctrine-relations/pagination

Потому что мне нужен способ легко разбивать результаты запроса на страницы.

Но я удивлен тем, как долго выполняется простой запрос count.

Это код

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

Я добавил четвертый параметр a array('distinct' => false) , потому что я использую внешний ключ в качестве первичного ключа (см. Эту проблему на github)

Конструктор запросов следующий :

 $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
  

Запрос, сгенерированный paginator, занимает 102 мс !!!?

Что я делаю не так, почему это занимает так много времени?

Это нормально, что запрос count занимает так много времени? Я не могу в это поверить. Как другие веб-сайты справляются с управлением нумерацией страниц?

Какова наилучшая практика разбиения на страницы.

Я попытался самостоятельно выполнить подсчет для разбиения на страницы, и у меня получилось это сделать :

 #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() функцию и the function, чтобы найти весь результат в моем репозитории…

Не рекомендуется каждый раз изменять функцию, которая просто подсчитывает скалярные результаты, и функцию, которая получает результаты данных…