У меня есть таблица (без отношений), которая нуждается в нумерации страниц. Для этого я использую инструмент Doctrine Pagination.
Таблица содержит 634484 записей. Doctrine выполняет следующие запросы:
SELECT p0_.id AS id_0, p0_.name AS name_1, p0_.level AS level_2, p0_.alignment AS alignment_3, p0_.account_id AS account_id_4 FROM player.player p0_ ORDER BY p0_.level DESC LIMIT 25;
объяснить:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE p0_ index search 1 25 100.00
время исполнения:
1,04 мс
проблемный запрос :
SELECT
COUNT(*) AS dctrn_count
FROM
(
SELECT
DISTINCT id_0
FROM
(
SELECT
p0_.id AS id_0,
p0_.name AS name_1,
p0_.level AS level_2,
p0_.alignment AS alignment_3
FROM
player.player p0_
ORDER BY
p0_.level DESC
) dctrn_result
) dctrn_table
объяснить:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived2> ALL 634484 100.00
2 DERIVED p0_ ALL PRIMARY 634484 100.00 Using temporary
Время выполнения: 2414,72 мс
Doctrine использует ключевое слово DISTINCT, чтобы узнать, сколько строк содержится в таблице, что, вероятно, является причиной того, что запрос выполнялся так долго.
Время выполнения без ключевого слова DISTINCT: 1,26 мс
EDIT
Repository:
public function findLatestPaginated(int $page = 1): array
{
$queryBuilder = $this->createQueryBuilder('c')
->addOrderBy('c.level', 'DESC');
return $this->paginate($queryBuilder, $page, Character::PER_PAGE);
}
Метод пагината:
<?php
namespace App\Core\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository as BaseServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
abstract class ServiceEntityRepository extends BaseServiceEntityRepository
{
protected function paginate(QueryBuilder $queryBuilder, int $currentPage, int $perPage)
{
$currentPage = $currentPage < 1 ? 1 : $currentPage;
$firstResult = ($currentPage - 1) * $perPage;
/** @var Query $query */
$query = $queryBuilder
->setFirstResult($firstResult)
->setMaxResults($perPage)
->getQuery();
$paginator = new Paginator($query, false);
$numResults = $paginator->count();
$hasPreviousPage = $currentPage > 1;
$hasNextPage = ($currentPage * $perPage) < $numResults;
return [
'result' => $paginator->getIterator(),
'currentPage' => $currentPage,
'hasPreviousPage' => $hasPreviousPage,
'hasNextPage' => $hasNextPage,
'previousPage' => $hasPreviousPage ? $currentPage - 1 : null,
'nextPage' => $hasNextPage ? $currentPage + 1 : null,
'numPages' => (int)ceil($numResults / $perPage),
'haveToPaginate' => $numResults > $perPage,
];
}
}
Вопросы:
- Почему Doctrine использует ключевое слово в запросе couting? (
id
, который является первичным ключом)
- Как я могу предотвратить это?