#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, чтобы найти весь результат в моем репозитории…
Не рекомендуется каждый раз изменять функцию, которая просто подсчитывает скалярные результаты, и функцию, которая получает результаты данных…