8 Stimmen

PHP/MySQL OOP: Laden komplexer Objekte aus SQL

Ich arbeite also an einem Projekt für einen Immobilienmakler. Ich habe die folgenden Objekte/MySQL-Tabellen in meinem Entwurf:

Complexes
Units
Amenities
Pictures
Links
Documents
Events
Agents

Dies sind die Beziehungen zwischen den oben genannten Objekten.

Complexes have a single Agent.
Complexes have multiple Units, Amenities, Pictures, Links, Documents, and Events.
Units have multiple Pictures, Links, and Documents.

Annehmlichkeiten, Bilder, Links, Dokumente und Ereignisse haben alle die notwendigen Fremdschlüssel in der Datenbank, um anzugeben, zu welcher Einheit/welchem Komplex sie gehören.

Ich muss die erforderlichen Objekte aus der Datenbank in PHP laden, damit ich sie in meinem Projekt verwenden kann.

Wenn ich versuche, alle Daten aus der Tabelle in einer Abfrage mit LEFT JOINS auszuwählen, erhalte ich MINDESTENS (Anzahl der Links) * (Anzahl der Bilder) * (Anzahl der Dokumente) Zeilen für jede einzelne Einheit. Fügen Sie Annehmlichkeiten und Ereignisse hinzu und ich erhalte alle * # Annehmlichkeiten * # Ereignisse für jeden Komplex... Ich bin nicht sicher, ob ich versuchen möchte, das in ein Objekt in PHP zu laden.

Die andere Möglichkeit ist, für jeden Komplex/jede Einheit jeweils 1 separate SQL-Anweisung für Links, Bilder, Dokumente, Ereignisse und Einrichtungen auszuführen

Meine Fragen lauten wie folgt:

Wenn ich alle meine Tabellen richtig indiziere, ist es dann wirklich eine schlechte Idee, 3-5 zusätzliche Abfragen für jeden Komplex/jede Einheit auszuführen?

Wenn nicht, wie kann ich sonst die Daten erhalten, die ich in ein PHP-Objekt laden muss. Im Idealfall würde ich ein Objekt wie folgt für Einheiten haben:

Unit Object
(
    [id]
    [mls_number]
    [type]
    [retail_price]
    [investor_price]
    [quantity]
    [beds]
    [baths]
    [square_feet]
    [description]
    [featured]
    [year_built]
    [has_garage]
    [stories]
    [other_features]
    [investor_notes]
    [tour_link]
    [complex] => Complex Object
        (
            [id]
            [name]
            [description]
            etc.
        )
    [agent] => Agent Object
        (
            [id]
            [first_name]
            [last_name]
            [email]
            [phone]
            [phone2] 
            etc.

        )
    [pictures] => Array
        (
            [1] => Picture Object
                (
                )
        )
    [links] => Array
        (
            [1] => Link Object
                (
                )
        )
    [documents] => Array
        (
            [1] => Document Object
                (
                )
        )    
)

Ich brauche nicht IMMER ALLE diese Informationen, manchmal brauche ich nur den Primärschlüssel des Komplexes, manchmal nur den Primärschlüssel des Agenten usw. Aber ich dachte, der richtige Weg, dies zu tun, wäre, das gesamte Objekt jedes Mal zu laden, wenn ich es instanziiere.

Ich habe viel über OO-PHP recherchiert, aber die meisten (ich habe alle) Online-Beispiele verwenden nur eine Tabelle. Das ist natürlich nicht hilfreich, da das Projekt, an dem ich arbeite, viele komplexe Beziehungen hat. Hat jemand eine Idee? Liege ich hier völlig daneben?

感謝

[UPDATE]

Auf der anderen Seite benötige ich für das Front-End, das jeder sehen wird, ALLE Informationen. Wenn zum Beispiel jemand Informationen über einen bestimmten Komplex wünscht, muss ich alle Einheiten, die zu diesem Komplex gehören, alle Bilder, Dokumente, Links und Ereignisse für den Komplex sowie alle Bilder, Dokumente und Links für die Einheit anzeigen.

Ich wollte vermeiden, dass ich während des Ladens einer Seite eine Abfrage ausführen muss, um den benötigten Komplex zu erhalten. Dann eine weitere Abfrage, um die 20 mit dem Komplex verbundenen Einheiten zu erhalten. Dann wird für jede der 20 Einheiten eine Abfrage für Bilder, eine weitere für Dokumente, eine weitere für Links usw. ausgeführt. Ich wollte sie alle auf einmal abrufen, mit einer einzigen Abfrage in der Datenbank.

[EDIT 2] Beachten Sie auch, dass die Abfragen zur Auswahl der Bilder, Dokumente, Links, Ereignisse und Agenten aus der Datenbank ziemlich einfach sind. Einfaches SELECT [Liste von Spalten] FROM [Tabelle] WHERE [primary_key] = [Wert] mit gelegentlichem INNER JOIN. Ich führe keine komplexen Berechnungen oder Unterabfragen durch, nur grundlegende Dinge.

[BENCHMARK] Nachdem ich also alle Antworten auf meine Frage gelesen hatte, beschloss ich, einen Benchmark mit dem zu machen, was ich beschlossen hatte. Ich lade alle Einheiten, die ich brauche. Wenn ich dann Bilder, Dokumente oder ähnliches anzeigen muss, lade ich sie zu diesem Zeitpunkt. Ich habe 30.000 Testeinheiten erstellt, jede mit 100 Bildern, 100 Dokumenten und 100 Links. Dann lud ich eine bestimmte Anzahl von Einheiten (ich begann mit 1000, dann 100, dann die realistischeren 10), ging sie in einer Schleife durch und lud dann alle Bilder, Dokumente und Links, die mit der Einheit verbunden waren. Bei 1000 Einheiten dauerte dies etwa 30 Sekunden. Bei 100 Einheiten dauerte es etwa 3 Sekunden. Bei 10 Einheiten dauerte es etwa 0,5 Sekunden. Die Ergebnisse waren sehr unterschiedlich. Manchmal dauerte es bei 10 Einheiten 0,12 Sekunden. Dann dauerte es 0,8 Sekunden. Dann vielleicht 0,5. Dann 0,78. Es war wirklich sehr unterschiedlich. Im Durchschnitt schien es jedoch etwa eine halbe Sekunde zu dauern. In Wirklichkeit brauche ich aber vielleicht nur 6 Einheiten auf einmal, und jede davon hat vielleicht nur 10 Bilder, 5 Links und 5 Dokumente... daher denke ich, dass der Ansatz "die Daten abrufen, wenn man sie braucht" in einer Situation wie dieser der beste ist. Wenn Sie jedoch alle Daten auf einmal abrufen müssten, wäre es sinnvoll, eine einzige SQL-Anweisung zu entwickeln, um alle benötigten Daten zu laden, so dass Sie die Daten nur einmal in einer Schleife durchlaufen müssen (6700 Einheiten auf einmal dauerten 217 Sekunden, während PHP bei den vollen 30.000 Einheiten der Speicher ausging).

4voto

Rob Knight Punkte 8244

Wenn ich alle meine Tabellen richtig indiziere, ist es dann wirklich eine schlechte Idee, 3-5 zusätzliche Abfragen für jeden Komplex/jede Einheit auszuführen?

Kurz gesagt, nein. Für jede der Bezugstabellen sollten Sie wahrscheinlich eine separate Abfrage ausführen. Das ist es, was die meisten ORM-Systeme (Object-Relational Mapping/Modelling) tun würden.

Wenn die Leistung wirklich ein Problem ist (und nach dem, was Sie gesagt haben, wird das nicht der Fall sein), dann könnten Sie in Erwägung ziehen, die Ergebnisse mit Hilfe von APC, memcache oder Xcache zwischenzuspeichern.

0voto

longneck Punkte 11522

Der Sinn von ORM ist nicht, jedes Mal ganze Objekte zu laden. Der Sinn ist, den Zugriff auf Objekte für Ihre Anwendung einfach und transparent zu machen.

Wenn Sie also das Einheitsobjekt benötigen, dann laden Sie das Einheitsobjekt und nur das Einheitsobjekt. Wenn Sie das Agentenobjekt benötigen, dann laden Sie es, wenn Sie es brauchen, nicht wenn Sie das Einheitsobjekt laden.

0voto

Robert DeBoer Punkte 1685

Vielleicht sollten Sie darüber nachdenken, die Sache zu beenden.

Wenn Sie Ihr Objekt initiieren, erhalten Sie nur die Details, die Sie für die Funktion des Objekts benötigen. Wenn Sie mehr Details benötigen, holen Sie diese nach. Auf diese Weise verteilen Sie die Last und die Verarbeitung: Das Objekt erhält nur die Last und die Verarbeitung, die es zum Funktionieren braucht, und wenn mehr benötigt wird, dann erhält es das auch.

In Ihrem Beispiel sollten Sie also zuerst den Komplex erstellen. Wenn Sie auf eine Einheit zugreifen müssen, dann erstellen Sie diese Einheit, wenn Sie den Agenten benötigen, dann holen Sie diesen Agenten, usw.

$complexDetails = array('id' => $id, etc);
$complexUnits = array();
.........
$complexUnits[] = new unit();
.........
$complexDetails['agent'] = new Agent();

0voto

Lucas Oman Punkte 15159

Mit diesem Problem musste ich mich vor einiger Zeit auseinandersetzen, als ich mein eigenes MVC-Framework als Experiment zusammenstellte. Um die aus der DB geladenen Datenschichten zu begrenzen, übergab ich eine ganze Zahl an den Konstruktor. Jeder Konstruktor würde diese Ganzzahl dekrementieren, bevor er sie an die Konstruktoren der Objekte weitergibt, die er instanziiert. Wenn der Wert 0 erreicht ist, werden keine weiteren Unterobjekte mehr instanziiert. Das bedeutete, dass die übergebene Ganzzahl die Anzahl der geladenen Ebenen war.

Wenn ich also nur ein Attribut des Unit-Objekts wollte, würde ich dies tun:

$myUnit = new Unit($unitId,1);

0voto

Brent Baisley Punkte 12551

Wenn Sie die Objekte "speichern", d.h. zwischenspeichern wollen, laden Sie sie einfach in ein PHP-Array und serialisieren es. Dann können Sie sie zurück in die Datenbank, in den Memcache oder sonst wo speichern. Durch das Anhängen eines Etiketts können Sie es abrufen und mit einem Zeitstempel versehen, damit Sie wissen, wie alt es ist (d.h. ob es aktualisiert werden muss).

Wenn sich die Daten nicht oder nur selten ändern, gibt es wirklich keinen Grund, jedes Mal mehrere komplexe Abfragen durchzuführen. Bei einfachen Abfragen, wie z. B. der Abfrage einer Primärdatei, können Sie die Datenbank auch direkt ansprechen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X