2013-09-18 6 views
1

Я уже прочитал несколько статей о производительности доктрины, но это один запрос настолько медленно, это кажется просто неправильно:Смешной медленно Doctrine Query

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

ли я что-то отсутствует? Я даже изменил режим гидратации на массив, но все еще есть проблемы.

UPDATE: Теперь я пытался выбрать только частично, но не менять слишком много:

  ->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}') 

Следующий шаг заключается в разделении запросов вверх.

Update 2

Это становится лучше, у меня есть на мой взгляд, несколько областей, где нужны разные наборы данных. Я пытался разделить мое содержание вверх в этих районах, а также запросов соответственно:

Данные для Main Площадь:

  • 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; 

А потом у меня есть третья область со всеми характеристиками. Это в основном то же самое, что и первый запрос, но включает в себя ставки для всех пользователей. Я теперь не уверен, если я должен использовать только один запрос, который запрашивает все ставки пользователей или, чем для статистики, создает один запрос для каждого пользователя или как-то иначе.

UPDATE ВОПРОС:

Может быть, вы видите, что у меня есть корневой объект под названием BetRound такого рода начинается все запросы (я теперь до 4 compley quersies моего BetRound? Я просто не знаю, как я могу «добавить» данные в мои отношения после начальной загрузки. Как вы можете видеть, есть несколько путей присоединиться к моей BetRound. Одним из них является "игры путь", который выглядит следующим образом:

  • BetRound -> GameGroup -> Игры -> Команда1 & team2
  • BetRound -> UserGroup -> Пользователи -> UserBetRoundStatus
  • BetRound -> Ставки

Мне нужны все эти данные, но как я могу получить все данные в одном корневом Entity с правильными отношениями? И если я запрашиваю, например. я начинаю с, например, GameGroup или всегда с моей корневой сущностью (= BetRound)?

+0

Ну, вы выбираете много данных. Попробуйте выбрать только нужные вам поля, а не целые объекты. –

+1

Также получите выполненный SQL и запустите EXPLAIN. –

+0

Я попытался изменить выбор только на необходимые поля, но затем я получаю ArrayResult с этими полями в основном ResultArray, хотя выбранные данные будут в связанном объекте. – m0c

ответ

1

Я думаю, что есть много левых объединений, которые могут быть очень медленными. Вы должны перестроить этот запрос и удалить эти левые соединения для повышения производительности. Также проверьте, правильно ли созданы все ключи и индексы в базе данных.

В заключение - это не вина Доктрины, а запрос.

1

Фактический запрос (PDOStatement::execute()) занимает всего 3% от общего количества. Наблюдение за взаимодействием с базой данных должно быть самой медленной частью скрипта, 3% от общего времени выполнения довольно быстро.

Подавляющее большинство времени занимают следующие 3 вызовы метода:

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

Если вы считаете, что вверх, это 72% от общей суммы. Это совершенно неприемлемо для любого стандарта.

  • «увлажняющий» записи действительно необходимы?
  • Можете ли вы устранить преобразование даты и времени?

Вам просто нужно отправиться за самыми большими грешниками. Сбрить жир.

+0

Привет, я временно играл с ArrayHydration и теперь снова использую гидратацию объекта. Но результат не является абсолютным релизом. – m0c