2010-11-18 11 views
0

Kurzbeschreibung meiner Umgebung:Lehre: leftJoin auf dem Tisch erzeugt unnötige Abfragen

  • Symfony: 1.4.8
  • Lehre: 1.2.3
  • Centos 5.5 (PHP 5.3.3)
  • MySQL 5.1.52

ich habe ein neues Projekt in Symfony gebaut und hier wird das Projekt Schema:

# 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 

Wenn ich will die letzten 10 Autos mit Kategorienamen und Benutzernamen, verwende ich den folgenden Code in der RjCarTable.class.php abzurufen:

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

    return $last_cars; 

Auf meiner Seite alles sieht gut aus, ich habe Alle meine Ergebnisse, aber in der Debug-Leiste, sehe ich 22 Abfragen (anstelle von 2, wie es sein sollte). Hier

ist die Ausgabe der Abfrage für die erste, die normal ist:

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 

Also, bis dann ist alles normal, außer diese Abfrage durch 20 andere folgen Informationen über die einzelnen Kategorien (2 Abfragen für jede abrufen Ergebnis anscheinend), während Sie in der vorherigen Abfrage feststellen können, dass diese Informationen verfügbar sind. Ich werde nicht alle von ihnen setzen, aber hier einige:

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 */ 

Also meine wirklichen Fragen sind: - Warum ist es, all diese unnötigen Abfragen durchführen, während die erste Abfrage diese Informationen haben sollte? - Warum passiert das nicht für die Tabelle sfGuardUser? Die Beziehung zwischen meinem RjCar-Objekt und dem sfGuardUser-Objekt ist anscheinend die gleiche wie die zwischen RjCar und RjCategory.

Wenn jemand bereits das gleiche Problem hat, werde ich mich sehr freuen darüber zu hören. Wie ich sage, funktioniert alles gut, aber ich bevorzuge dieses Modul nicht generieren unnötige Abfragen, wie es auf der Homepage meiner Anwendung durchführen sollte.

Antwort

0

ich mich geschlagen:

Hier ist, was ich in der RjCar.class.php

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

So erklärt es die unecessary Abfragen ... Ich erinnere mich nicht einmal dieses Schreiben Stück Code, aber da ich der einzige bin, der an diesem Projekt arbeitet, denke ich, dass ich es bin.

Wie üblich war das Problem zwischen dem Stuhl und der Tastatur ...

Vielen Dank für Ihre Hilfe.

-1

Bei der Verwendung von ORM-Frameworks wie Doctrine und Hibernate werden häufig redundante und hässliche Abfragen generiert. Je komplizierter die Abfrage ist, desto hässlicher wird sie auf diesen Systemen (versuchen Sie, Ihrer verknüpften Abfrage ein "Limit" hinzuzufügen und den generierten Code zu betrachten).
Frameworks im Allgemeinen bieten eine großartige Lösung für 80% Ihrer Fälle. Für die restlichen 20% müssen Sie etwas härter arbeiten. Normalerweise ist es ein fairer Kompromiss.
Wenn Sie über die Qualität der Ausgabe dieser Abfrage besorgt sind oder denken, dass Sie die Latenz, die sie verursacht, nicht leisten können - Doctrine verfügt über eine sehr einfache Methode zum Schreiben und Verwalten benutzerdefinierter Abfragen. Haben Sie keine Angst, diesen Pfad zu gehen ...

+0

Während Sie Recht haben, dass es manchmal notwendig ist, aus dem ORM auszubrechen, ist dies definitiv nicht einer der Fälle. –

0

Dieses Verhalten scheint seltsam und definitiv nicht, was erwartet wird. Einige Dinge zum Ausprobieren:

  • Zwischenspeichern Sie Doctrine-Abfragen oder Ergebnisse? Manchmal können Abfragen nach Änderungen am Modell mit seltsamen Effekten zwischengespeichert werden.
  • Diese Abfragen sehen definitiv aus wie Doctrines Lazy-Fetching-Verhalten. Haben Sie versucht einzugrenzen, welche Aufrufe diese Abfragen spezifisch auslösen? Versuchen Sie herauszufinden, welche spezifischen Zeilen die Abfragen auslösen, und sehen Sie, ob es etwas Besonderes an ihnen gibt.
+0

Danke für Ihr Interesse. Ich glaube nicht, dass es zwischengespeichert wird: Ich benutze die Doktrin: Build --all - and-load Befehl jedes Mal, gefolgt von cc. Wenn ich die -> leftJoin ('RjCategory') aus der Abfrage entfernen, ist alles in Ordnung. Aber danke für den Hinweis auf faulen Laden, ich habe nicht darüber nachgedacht. – Remiz