Ist es besser, eine große Abfrage in mehrere kleinere Abfragen aufzuteilen?

13

Es gibt Situationen, in denen eine sehr große Abfrage erforderlich ist, die mehrere Tabellen mit Sub-Select-Anweisungen verknüpft, um die gewünschten Ergebnisse zu erzielen.

Meine Frage ist, sollten wir in Betracht ziehen, mehrere kleinere Abfragen zu verwenden und die logischen Operationen in die Anwendungsschicht zu bringen, indem wir die Datenbank in mehr als einem Aufruf abfragen, oder es ist besser, sie alle auf einmal zu haben?
Betrachten Sie zum Beispiel die folgende Abfrage:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

Wie geht das am besten?

Hamed Momeni
quelle

Antworten:

14

Ich bin nicht einverstanden mit großen und komplizierten Fragen mit Datagod hier. Ich sehe diese nur als Probleme, wenn sie unorganisiert sind. In Bezug auf die Leistung sind diese fast immer besser, da der Planer viel mehr Freiheit beim Abrufen der Informationen hat. Bei umfangreichen Abfragen muss jedoch auf Wartungsfreundlichkeit geachtet werden. Im Allgemeinen habe ich festgestellt, dass einfaches, gut strukturiertes SQL auch dann leicht zu debuggen ist, wenn eine einzelne Abfrage über 200 Zeilen umfasst. Dies liegt daran, dass Sie normalerweise eine ziemlich gute Vorstellung davon haben, um welche Art von Problem es sich handelt, sodass die Abfrage nur wenige Bereiche enthält, die Sie überprüfen müssen.

Die Wartungsprobleme, IME, treten auf, wenn die SQL-Struktur zusammenbricht. Lange, komplexe Abfragen in Unterauswahlen beeinträchtigen die Lesbarkeit und Fehlerbehebung, ebenso wie Inline-Ansichten. Beides sollte in langen Abfragen vermieden werden. Verwenden Sie stattdessen nach Möglichkeit VIEWs (beachten Sie, dass Views auf MySQL nicht so gut funktionieren, auf den meisten anderen Datenbanken jedoch) und verwenden Sie allgemeine Tabellenausdrücke, bei denen diese nicht funktionieren (MySQL unterstützt diese nicht) übrigens).

Lange komplexe Abfragen funktionieren sowohl in Bezug auf die Wartbarkeit als auch in Bezug auf die Leistung recht gut, wenn Sie Ihre where-Klauseln einfach halten und so viel wie möglich mit Joins anstelle von Unterauswahlen tun. Das Ziel ist es, dafür zu sorgen, dass "Datensätze werden nicht angezeigt" Ihnen einige sehr spezifische Stellen in der Abfrage gibt, die Sie überprüfen müssen (wird sie in einem Join gelöscht oder in einer where-Klausel herausgefiltert?), Und so das Wartungsteam kann tatsächlich Dinge pflegen.

Bedenken Sie hinsichtlich der Skalierbarkeit, dass das auch gut ist, je flexibler der Planer ist.

Bearbeiten: Sie erwähnen, dass dies MySQL ist, so dass es unwahrscheinlich ist, dass Ansichten so gut funktionieren und CTEs nicht in Frage kommen. Darüber hinaus ist das angegebene Beispiel nicht besonders lang oder komplex, sodass dies kein Problem darstellt.

Chris Travers
quelle
Hinweis: Ich hatte Abfragen (nicht in MySQL, aber immer noch ...), die lang und komplex genug waren, dass die generierten Abfragepläne nicht optimal waren. In diesen Fällen können Sie in der Tat schnellere Ergebnisse erzielen, indem Sie eine äußerst komplexe Abfrage in zwei weniger komplexe Abfragen aufteilen. Das heißt, es ist selten, und ich schreibe im Allgemeinen die komplexe Abfrage und finde heraus, ob es ein Problem gibt, anstatt die Abfrage präventiv in kleinere Abschnitte zu unterteilen.
RDFozz
8

Als jemand, der diese großen und komplizierten Abfragen unterstützen / bereinigen muss, würde ich sagen, dass es weitaus besser ist, sie in mehrere kleine, leicht verständliche Abschnitte aufzuteilen. Unter Performance-Gesichtspunkten ist es nicht unbedingt besser, aber Sie geben SQL zumindest eine bessere Chance, einen guten Abfrageplan zu entwickeln.

Erleichtern Sie den Menschen, die Ihnen folgen, das Leben, und sie werden gute Dinge über Sie sagen. Machen Sie es ihnen schwer und sie werden Sie verfluchen.

datagod
quelle
2
Der Nachteil einer Reihe einfacher Abfragen besteht jedoch darin, dass sich der Status in den einzelnen Abfragen erheblich ändert, wodurch das Debuggen der Anwendung insgesamt komplexer wird. Sie können große SQL-Abfragen häufig als Bäume debuggen, aber der Anwendungscode wird von einer Anweisung geprüft, um festzustellen, wie sich der Status in Anweisungen ändert. Die eigentlichen Probleme haben damit zu tun, dass Unterauswahlen und Inline-Ansichten auch ihre eigenen Bäume sind .....
Chris Travers
In meinem Fall bin ich der einzige, der die DB und den Code verwalten muss. Und meistens ging es bei meiner Frage um den Leistungspunkt der Abfrage.
Hamed Momeni
Ihr müsst euch ansehen, wie ich meine großen Batch-Prozesse schreibe. Teilen Sie die Dinge in einfache Abfragen auf, die sehr einfach zu lesen sind. Ich bin voreingenommen, weil die Abfragen, die ich versuche aufzuräumen, routinemäßig mehr als 1000 Zeilen lang sind.
Datum
5

Meine 2 Cent für die 2 Schlüsselwörter Abfrage-Performance und Skalierbarkeit:

Abfrageleistung: Die SQL Server-Parallelität funktioniert bereits sehr gut, wenn Abfragen in Suchanfragen mit mehreren Threads unterteilt werden. Daher bin ich mir nicht sicher, wie stark sich die Abfrageleistung bei SQL Server verbessert. Sie müssen sich den Ausführungsplan ansehen, um festzustellen, wie viel Parallelität Sie erhalten, wenn Sie ihn ausführen, und die Ergebnisse in beide Richtungen vergleichen. Wenn Sie am Ende einen Abfragehinweis verwenden müssen, um die gleiche oder eine bessere Leistung zu erzielen, lohnt sich IMO nicht, da der Abfragehinweis später möglicherweise nicht optimal ist.

Skalierbarkeit: Das Lesen der Abfragen ist möglicherweise einfacher, wie von datagod angegeben, und das Aufteilen in separate Abfragen ist sinnvoll, wenn Sie Ihre neuen Abfragen auch in anderen Bereichen verwenden können, sie aber nicht auch für andere Anrufe verwenden möchten Es sind noch mehr gespeicherte Prozesse für eine Aufgabe zu verwalten, und IMO würde keinen Beitrag zur Skalierbarkeit leisten.

Ali Razeghi
quelle
2
RE: „SQL Server“ Referenzen , obwohl die OP hat keine besondere RDBMS keine Angabe ich sich von den hinteren Zecken sind auf MySQL vermute , undLIMIT
Martin Smith
@MartinSmith Sie vermuten richtig. Es ist MySQL.
Hamed Momeni
2

Manchmal bleibt keine andere Wahl, als die große / komplexe Abfrage in kleine Abfragen aufzuteilen. Der beste Weg, dies festzustellen, wäre, EXPLAINAnweisung mit der SELECTAnweisung zu verwenden. Die Anzahl der Traces / Scans, die Ihre Datenbank zum Abrufen Ihrer Daten durchführen wird, ist das Produkt der von Ihrer EXPLAINAbfrage zurückgegebenen "Zeilen" -Werte . In unserem Fall hatten wir eine Abfrage, die 10 Tabellen verknüpft. Insbesondere betrug der Trace 409 Millionen, die unsere Datenbank bloggten und die CPU-Auslastung unseres DB-Servers um mehr als 300% erhöhten. Wir konnten dieselben Informationen abrufen, indem wir die Abfragen viel schneller aufteilten.

Kurz gesagt, in einigen Fällen ist das Aufteilen einer komplexen / großen Abfrage sinnvoll, in anderen Fällen kann es jedoch zu zahlreichen Leistungs- oder Wartungsproblemen kommen. Dies sollte von Fall zu Fall behandelt werden.

user140665
quelle