Доктрина: leftJoin для таблицы генерирует ненужные запросы - PullRequest
0 голосов
/ 18 ноября 2010

Краткое описание моей среды:

  • Symfony: 1,4,8
  • Учение: 1.2.3
  • Centos 5.5 (PHP 5.3.3)
  • MySQL 5.1.52

У меня есть новый проект, созданный в Symfony, и вот схема проекта:

# Car
RjCar:
  actAs: { Timestampable: ~ }
  columns:
    id: { type: integer(4), unsigned: true, primary: true, autoincrement: true }
    year: { type: integer(2), unsigned: true, notnull: true }
    engine_mod: { type: string(1000) }
    exterior_mod: { type: string(1000) }
    suspension_mod: { type: string(1000) }
    audio_mod: { type: string(1000) }
    vote_pos: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    vote_neg: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    views: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    # Foreign keys
    category_id: { type: integer(1), unsigned: true, notnull: true }
    category_check: { type: boolean, notnull: true, default: 0 }
    user_id: { type: integer(5) }
  relations:
    RjCategory: { onDelete: CASCADE, local: category_id, foreign: id, foreignAlias: RjCars }
    sfGuardUser: { onDelete: CASCADE, local: user_id, foreign: id, foreignAlias: RjCars }

# Category
RjCategory:
  columns:
    id: { type: integer(1), unsigned: true, primary: true, autoincrement: true }
    name: { type: string(255), notnull: true}

# I do not include the sfGuardUser schema, but it's the default one from the plugin

Когда я хочу получить последние 10 автомобилей с именем категории и именем пользователя, я использую следующий код в RjCarTable.class.php:

  $last_cars = $this->createQuery('car')
               ->leftJoin('car.sfGuardUser user')
               ->leftJoin('car.RjCategory categ')
               ->orderBy('car.created_at DESC')
               ->limit(10)
               ->execute();

   return $last_cars;

На моей странице все выглядит нормально, у меня есть все мои результаты, но в панели отладки я вижу 22 запроса (вместо 2, как должно быть).

Вот вывод запроса для первого, который является нормальным:

SELECT
/* Everything about the car */
r.id AS r__id, 
r.year AS r__year, 
r.engine_mod AS r__engine_mod, 
r.exterior_mod AS r__exterior_mod, 
r.suspension_mod AS r__suspension_mod, 
r.audio_mod AS r__audio_mod,  
r.vote_pos AS r__vote_pos, 
r.vote_neg AS r__vote_neg, 
r.views AS r__views, 
r.type_id AS r__type_id, 
r.category_id AS r__category_id, 
r.category_check AS r__category_check, 
r.user_id AS r__user_id, 
r.created_at AS r__created_at, 
r.updated_at AS r__updated_at, 
/* ... hidden because irrelevant... retrieve everything about the sfGuardUser and profile... */
/* Everything about the category */
r2.id AS r2__id, 
r2.name AS r2__name, 
FROM rj_car r 
LEFT JOIN sf_guard_user s ON r.user_id = s.id 
LEFT JOIN rj_category r2 ON r.category_id = r2.id 
ORDER BY r.created_at DESC 
LIMIT 10

Так что до тех пор все нормально, за исключением того, что за этим запросом следуют еще 20 человек, чтобы получить информацию о каждой категории (по-видимому, 2 запроса для каждого результата), в то время как в предыдущем запросе вы можете заметить, что эта информация доступна. Я не буду помещать их все, но вот некоторые:

SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '8') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '8') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '9') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '9') LIMIT 1
/* etc.. 20 times */

Итак, мои настоящие вопросы: - Почему он выполняет все эти ненужные запросы, а первый запрос должен содержать эту информацию? - Почему это не происходит для таблицы sfGuardUser? Соотношение между моим объектом RjCar и объектом sfGuardUser, по-видимому, такое же, как и между RjCar и RjCategory.

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

Ответы [ 3 ]

0 голосов
/ 19 ноября 2010

Такое поведение кажется странным и определенно не таким, как ожидается.Некоторые вещи, которые нужно попробовать:

  • Кешируете ли вы запросы или результаты Doctrine?Иногда запросы могут оставаться в кеше после изменений в модели со странными эффектами.
  • Эти запросы определенно выглядят как ленивое поведение Doctrine.Вы пытались сузить, какие звонки специально вызывают эти запросы?Попробуйте отследить, какие именно строки вызывают запросы, и посмотрите, есть ли в них что-то особенное.
0 голосов
/ 19 ноября 2010

Я ударил себя:

Вот что я нашел в RjCar.class.php

/**
* Return the category of the car
*/    
public function getRjCategory(){
  return Doctrine_Core::getTable('RjCategory')->find($this->getCategoryId());
}

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

Как обычно, проблема была между стулом и клавиатурой ...

Спасибо за вашу помощь.

0 голосов
/ 18 ноября 2010

При использовании каркасов ORM, таких как Doctrine и Hibernate, он часто генерирует избыточные и уродливые запросы.Чем сложнее запрос, тем уродливее он становится в этих системах (попробуйте добавить «предел» к вашему присоединенному запросу и посмотрите на сгенерированный код).Каркасы в целом обеспечивают отличное решение для 80% ваших случаев.Для оставшихся 20% нужно работать немного усерднее.Обычно это справедливый компромисс.Если вы обеспокоены качеством вывода этого запроса или считаете, что не можете позволить себе задержку, которую он вызывает, - в Doctrine есть очень простой метод написания и управления пользовательскими запросами.Не бойся идти по этому пути ...

...