荒谬缓慢的Doctrine查询

时间:2013-09-18 20:11:25

标签: php mysql symfony doctrine-orm

我已经阅读了一些关于Doctrine性能的文章,但这一个查询速度太慢似乎错了:

public function getBetRoundMainDataBuilder(BetRound $betRound){
        $qb = $this->createQueryBuilder('br')
                   ->select('br, uG, u, b, gG, g, t1, t2')
                   ->where('br.id = :bID')
                   ->setParameter('bID', $betRound->getId())
                   ->innerJoin('br.userGroup', 'uG')
                   ->innerJoin('uG.users', 'u')
                   ->innerJoin('br.gameGroup', 'gG')
                   ->leftJoin('gG.games', 'g')
                   ->leftJoin('g.team1', 't1')
                   ->leftJoin('g.team2', 't2')
                   ->leftJoin('br.bets', 'b' );
        return $qb;

    }

我知道它有很多连接,但我认为我宁愿在一个查询中查询所有内容而不是延迟加载所有相关数据。

我已经对代码进行了分析,虽然这个查询没有选择太多的数据,但是对于array_shift来说这是无休止的:

Profiling Data

我错过了什么吗?我甚至将水化模式改为阵列,但仍有问题。

更新 我现在尝试仅部分选择,但没有太大改变:

           ->select('partial br.{id},
                     partial uG.{id},
                     partial u.{id, firstName, lastName, nickName, username, imageName},
                     partial b.{id, data},
                     partial gG.{id, title},
                     partial g.{id, data, date},
                     partial t1.{id, name, shortName, shortCode, logoName},
                     partial t2.{id, name, shortName, shortCode, logoName}')

下一步是拆分查询。

更新2

它变得越来越好,我的视图中有几个区域需要不同的数据集。我试图将我的内容分成这些区域,并相应地查询:

主区数据:

  • BetRound
    • GamGroup(仅限游戏)
      • 游戏
        • 投注(仅适用于当前用户!)

现在看起来像这样:

$qb = $this->createQueryBuilder('br')
        ->select(
            'partial br.{id},
            partial b.{id, data},
            partial gG.{id, title},
            partial g.{id, data, date},
            partial t1.{id, name, shortName, shortCode, logoName},
            partial t2.{id, name, shortName, shortCode, logoName}'
        )
        ->where('br.id = :bID')
        ->setParameter('bID', $betRound->getId())
        ->innerJoin('br.gameGroup', 'gG')
        ->leftJoin('gG.games', 'g')
        ->leftJoin('g.team1', 't1')
        ->leftJoin('g.team2', 't2')
        ->leftJoin('g.bets', 'b', 'WITH', 'b.user = :user')
        ->setParameter('user', $user->getId());
    return $qb;

第二个区域是PointTable

$qb = $this->createQueryBuilder('br')
    ->select('br, b, u, uBs')
    ->where('br.id = :bID')
    ->setParameter('bID', $betRound->getId())
    ->leftJoin('br.bets', 'b')
    ->innerJoin('b.user', 'u')
    ->innerJoin('u.betroundStatus', 'uBs', 'WITH', 'uBs.betRound = :bID');

return $qb;

然后我有第三个区域,其中包含所有统计数据。它与第一个查询基本相同,但包括所有用户的投注。我现在不确定,如果我只使用一个查询所有用户投注的查询,或者统计数据为每个用户创建一个查询或以某种方式不同。

更新问题:

也许你看到我有一个名为BetRound的根实体,它可以启动所有查询(我现在最多可以从我的BetRound获得4个完整的查询? 我只是不知道如何在初始加载后将数据“添加”到我的关系中。 正如您所看到的,我的BetRound有几个连接“路径”。其中一个是“游戏路径”,看起来像:

  • BetRound - > GameGroup - >游戏 - > Team1& Team2
  • BetRound - > UserGroup - >用户 - > UserBetRoundStatus
  • BetRound - >赌注

我需要所有这些数据,但是如何在一个根实体中获得具有正确关系的所有数据?如果我查询例如从例如GameGroup还是总是与我的root实体(= BetRound)?

2 个答案:

答案 0 :(得分:1)

实际查询(PDOStatement::execute())仅占总数的3%。看到与数据库交互应该是脚本中最慢的部分,总执行时间的3%是足够快的。

绝大多数时间由以下3个方法调用占用:

ArrayHydrator::hydrateRowData()   // 17%
AbstractHydrator::gatherRowData() // 39%
DateTimeType::convertToPHPValue() // 16%

如果算上这个,那就是总数的72%。 任何标准都是完全不能接受的。

  • “保湿”记录真的有必要吗?
  • 您可以取消日期/时间转换吗?

你只需要追捕最大的罪人。剃除脂肪。

答案 1 :(得分:1)

我认为有很多左连接可能非常慢。您应该重建此查询并删除这些左连接以提高某些性能。另请检查是否在数据库中正确创建了每个键和索引。

总之 - 这不是Doctrine的错,而是查询。