7

Ich habe eine große Abfrage (in meinem Abfrage-Generator) und viele Links Joins. So bekomme ich Artikel mit ihren Kommentaren und Tags und so weiter. Lassen Sie uns sagen, dass ich die folgende dql haben:Doctrine2: Begrenzung mit Links Joins/Pagination - Best Practice

$dql = 'SELECT blogpost, comment, tags 
FROM BlogPost blogpost 
LEFT JOIN blogpost.comments comments 
LEFT JOIN blogpost.tags tags'; 

Jetzt sagen lassen Sie uns meine Datenbank mehr als 100 Blogeinträge hat, aber ich möchte nur die ersten 10, aber mit all den Kommentaren von denen 10 und alle ihre Tags, wenn sie vorhanden sind . Wenn ich setMaxResults verwende, begrenzt es die Zeilen. So könnte ich die ersten zwei Posts bekommen, aber der letzte von denen fehlt einige seiner Kommentare oder Tags. Also funktioniert das folgende nicht.

$result = $em->createQuery($dql)->setMaxResults(15)->getResult(); 

die kaum dokumentiert Pagination Lösung verwenden, die Schiffe mit doctrine2.2 wirklich für mich nicht funktioniert entweder, da es so langsam ist, könnte ich auch alle Daten geladen werden.

Ich habe versucht, die Lösungen in der Stackoverflow Article, aber auch dieser Artikel fehlt noch eine Best Practice und die vorgestellte Lösung ist tödlich langsam.

Gibt es keine Best Practice, wie man das macht? Verwendet niemand Doctrine2.2 im Produktionsmodus?

+1

Bitte fügen Sie den Code, den Sie haben, zu Ihrer Frage hinzu, vielleicht sogar mit Beispielergebnissen, um zu zeigen, was Sie wollen und was Sie bekommen. –

Antwort

10

Das richtige Ergebnis mit einer Abfrage wie dieser ist problematisch. Es gibt ein Tutorial auf der Doctrine-Website, das dieses Problem erklärt.

Pagination

Das Tutorial mehr über Paginierung ist, anstatt die Top-5-Ergebnisse zu erzielen, aber die allgemeine Idee ist, dass Sie ein „SELECT DISTINCT a.id FROM Artikel eines ... LIMIT 5“ tun müssen, statt eines normalen SELECT. Es ist ein wenig komplizierter als das, aber die letzten 2 Punkte in diesem Tutorial sollten Sie auf den richtigen Weg bringen.

Update:

Das Problem hier ist nicht Lehre, oder jede andere ORM. Das Problem besteht darin, dass die Datenbank die gewünschten Ergebnisse zurückgeben kann. So funktionieren Joins.

Wenn Sie ein EXPLAIN für die Abfrage ausführen, erhalten Sie eine detailliertere Antwort auf das, was passiert. Es wäre eine gute Idee, die Ergebnisse Ihrer ersten Frage hinzuzufügen.

Aufbauend auf dem, was im Paginierung Artikel diskutiert wird, scheint es, dass Sie mindestens 2 Abfragen benötigen, um Ihre gewünschten Ergebnisse zu erhalten. Das Hinzufügen von DISTINCT zu einer Abfrage kann Ihre Abfrage erheblich verlangsamen, wird jedoch nur benötigt, wenn Sie Joins darin haben. Sie könnten eine weitere Abfrage schreiben, die nur die ersten 10 nach dem Erstellungsdatum angeordneten Beiträge ohne Joins abruft. Sobald Sie die IDs dieser 10 Posts haben, führen Sie eine weitere Abfrage mit Ihren Joins und einer WHERE blogpost.id IN (...) ORDER BY blogpost.created. Diese Methode sollte viel effizienter sein.

Da alles, was Sie in der ersten Abfrage interessieren, die IDs sind, können Sie Doctrine auf Scalar Hydration setzen.

SELECT 
    bg 
FROM 
    Blogpost bp 
LEFT JOIN 
    bp.comments c 
LEFT JOIN 
    bp.tags t 
WHERE 
    bp.id IN (...) 
ORDER BY 
    bp.created DESC 

Sie könnten auch tun es wahrscheinlich in einer Abfrage eine korrelierte Unterabfrage verwendet. Der Mythos, dass Unterabfragen immer schlecht sind, ist NICHT wahr. Manchmal sind sie schneller als Joins. Sie müssen experimentieren, um herauszufinden, was die beste Lösung für Sie ist.

2

bearbeiten im Lichte der Frage geklärt:

können Sie tun, was Sie in nativen MySQL wollen eine Unterabfrage in der FROM-Klausel als solche mit:

SELECT * FROM 
(SELECT * FROM articles ORDER BY date LIMIT 5) AS limited_articles, 
comments, 
tags 
WHERE 
limited_articles.article_id=comments.article_id 
limited_articles.article_id=tags.article_id 

Soweit ich weiß, DQL unterstützt keine Unterabfragen wie diese, daher können Sie die NativeQuery-Klasse verwenden.

+0

Nein, ich möchte nicht die neuesten M von meinem N. Ich möchte die neuesten N mit all ihren M, X und Y. –

+0

Ich bin kein großer Fan von Verwendung eines DABL/ORM-Framework und dann immer noch mit nativen Abfragen Das macht für mich keinen Sinn. –

+1

Dann sieht es so aus, als müssten Sie zwei Abfragen durchführen. Ich stimme zu, dass es eine bessere Möglichkeit geben sollte, Ergebnisse von Joins zu begrenzen und zu paginieren. –