getArrayResult()超过symfony上的最大执行时间

getArrayResult()超过symfony上的最大执行时间,symfony,doctrine,Symfony,Doctrine,我目前正试图从存储库中获取数据以在引导网格中显示,但我总是超过最大执行时间(120秒) 我使用以下代码: 在我的Javascript中: $params.table.bootgrid({ ajax: true, url: $params.authoritiesDataPath //the url is correct here, I verified it }) 在我的控制器中: /** * Authorities Data * * @param Request $req

我目前正试图从存储库中获取数据以在引导网格中显示,但我总是超过最大执行时间(120秒)

我使用以下代码:

在我的Javascript中:

$params.table.bootgrid({
    ajax: true,
    url: $params.authoritiesDataPath //the url is correct here, I verified it
})
在我的控制器中:

/**
 * Authorities Data
 *
 * @param Request $request
 * @return JsonResponse
 */
public function dataAction(Request $request)
{
    $this->denyAccessUnlessGranted(RoleVoterHelper::SECTION_COMPANY_VIEW);
    try {
        $data = $this->getDoctrine()->getRepository('BugTrackerModelBundle:Authority')->findByParameters(
            $request->request->all()
        );
    } catch (\Exception $e) {
        $data = [
            'status'   => 'error',
            'error'    => $e->getMessage(),
            'rows'     => [],
            'current'  => 1,
            'rowCount' => 0,
            'total'    => 0,
        ];
    }

    return new JsonResponse($data);
}
在我的存储库中:

public function findByParameters(array $parameters)
{
    $queryBuilder = $this->createQueryBuilder('a')
        ->select('COUNT(a.id)');

    if (!empty($parameters['searchPhrase'])) {
        $queryBuilder->where('a.name LIKE :search')
            ->setParameter('search', '%'.$parameters['searchPhrase'].'%');
    }

    $parameters['rows'] = array();
    $parameters['current'] = isset($parameters['current']) ? (int)$parameters['current'] : 0;
    if ($parameters['total'] = (int)$queryBuilder->getQuery()->getSingleScalarResult()) {
        $queryBuilder->select('a.id', 'a.name', 'COUNT(DISTINCT c.id) as companies',
            'COUNT(DISTINCT u.id) as users', 'COUNT(DISTINCT dl.id) as deviceLists',
            'COUNT(DISTINCT d.id) as devices', 'a.name as authority', 'a.enabled')
            ->leftJoin('BugTrackerModelBundle:Company', 'c', Join::WITH, 'c.authority = a.id')
            ->leftJoin('BugTrackerModelBundle:Device', 'd', Join::WITH, 'd.authority = a.id')
            ->leftJoin('BugTrackerModelBundle:Device\DeviceList', 'dl', Join::WITH, 'dl.authority = a.id')
            ->leftJoin('BugTrackerModelBundle:User', 'u', Join::WITH, 'u.company = c.id')
            ->groupBy('a.id');

        if (!empty($parameters['sort'])) {
            $order = reset($parameters['sort']) ?: 'ASC';
            switch (key($parameters['sort'])) {
                case 'name':
                    $queryBuilder->orderBy('c.name', $order);
                    break;
                case 'users':
                    $queryBuilder->orderBy('users', $order);
                    break;
                case 'company':
                    $queryBuilder->orderBy('companies', $order);
                    break;
                case 'enabled':
                    $queryBuilder->orderBy('a.enabled', $order);
                    break;
                default:
                    $queryBuilder->orderBy('c.id', $order);
            }
        }

        if (isset($parameters['rowCount']) && $parameters['rowCount'] > 0) {
            $queryBuilder->setFirstResult(($parameters['current'] - 1) * $parameters['rowCount'])
                ->setMaxResults($parameters['rowCount']);
        }

        $parameters['rows'] = $queryBuilder->getQuery()->getArrayResult();
    }

    return $parameters;
}
我几乎在任何地方都尝试返回数组,以找到循环的位置(我猜这是一个循环,因为我的代码通常非常快),它似乎来自下面一行

$parameters['rows'] = $queryBuilder->getQuery()->getArrayResult();
我试着返回
$queryBuilder->getQuery()
,但花了几秒钟,所以问题出在
getArrayResult

打印sql时返回的查询:

SELECT a0_.id AS id_0, a0_.name AS name_1, COUNT(DISTINCT c1_.id) AS sclr_2, COUNT(DISTINCT u2_.id) AS sclr_3, COUNT(DISTINCT d3_.id) AS sclr_4, COUNT(DISTINCT d4_.id) AS sclr_5, a0_.name AS name_6, a0_.enabled AS enabled_7 FROM authority a0_ LEFT JOIN client_company c1_ ON (c1_.authority_id = a0_.id) LEFT JOIN device d4_ ON (d4_.authority_id = a0_.id) LEFT JOIN device_list d3_ ON (d3_.authority_id = a0_.id) LEFT JOIN user u2_ ON (u2_.company_id = c1_.id) GROUP BY a0_.id LIMIT 5 OFFSET 0
以下是我在PhpMyAdmin中运行查询时的“解释”:


我真的不明白为什么要花这么多时间,我从数据库中获取数据从来没有遇到过问题,而且所有代码中都没有可能导致这种情况的循环。有没有什么方法可以让我测试其他东西来理解为什么要花这么多时间并对其进行更改?

您是否为正确的列编制了索引?这将减少查询时间,此外,可能是结果集非常复杂,需要花费一段时间才能使数组水合,这导致了您看到的持续时间

查看生成的查询,您有4个连接,它将合并5个实体BugTrackerModelBundle:AuthorityBugTrackerModelBundle:CompanyBugTrackerModelBundle:DeviceBugTrackerModelBundle:User

这是大量的连接,因为“当超过2个左连接操作子句时,水合过程变得极其昂贵”。看见简言之,和学说需要很长时间才能将其映射到实体

我的假设是ORM需要很长时间来规范化查询返回的结果集

我的建议是将查询拆分为2个,每个查询最多有2个联接:

$queryBuilder = $this->createQueryBuilder('a')
            ->select('a.id', 'a.name', 
            'COUNT(DISTINCT c.id) as companies',
            'COUNT(DISTINCT u.id) as users',
            'a.name as authority', 'a.enabled')
            ->leftJoin('BugTrackerModelBundle:Company', 'c', Join::WITH, 'c.authority = a.id')
            ->leftJoin('BugTrackerModelBundle:User', 'u', Join::WITH, 'u.company = c.id')
            ->groupBy('a.id');

$queryBuilder = $this->createQueryBuilder('a')
            ->select('a.id', 'a.name',
            'COUNT(DISTINCT dl.id) as deviceLists',
            'COUNT(DISTINCT d.id) as devices', 'a.name as authority', 'a.enabled')
            ->leftJoin('BugTrackerModelBundle:Device', 'd', Join::WITH, 'd.authority = a.id')
            ->leftJoin('BugTrackerModelBundle:Device\DeviceList', 'dl', Join::WITH, 'dl.authority = a.id')
            ->groupBy('a.id');

希望这有帮助。

哪一个是您的DBMS?您是否在您的DBMS上尝试了相同的查询并解释了查询和检查响应时间?我正在使用MySQL和PHPMyAdmin(Wamp)。我试过了,但查询速度似乎很慢,所以我想这就是问题的根源。(应该只需要几秒钟)。我只是不明白为什么查询这么慢,我从来没有遇到过大查询的问题,120秒比“我就是不懂”慢了近1000倍——我们都不懂。在上面添加生成的SQL和解释的结果。我在问题中添加了解释结果的屏幕。SQL已经在这里了。我正在使用的其他表中的所有列都已编制索引,但运行仍然需要将近一分钟的时间。请尝试打印SQL,应该在分析器中找到,然后在SQL程序中使用explain运行。因此:解释[query]这将帮助您查看是否遗漏了某些索引。另外,查询需要一段时间,还是查询需要一段时间?如果是水合作用,您是否考虑过将查询分解为多个查询,然后根据结果水合您自己的数组?我在PhpMyAdmin中运行SQL,速度很慢,所以我认为问题不在于水合作用。我在问题中放了一个解释的截图。谢谢!我试着用你的例子跑步,效果很好(从一分半到17秒左右)。可悲的是,它仍然是我慢,因为网页应该只需要几秒钟加载。我会继续找的。啊,原来我需要为每个查询或刚刚添加的连接创建一个新的查询生成器,结果是相同的。现在我这样做了,只需要1.5秒!非常感谢。