Konzeptionelle Frage: Sind einzelne Abfragen schneller als Verknüpfungen? Oder: Soll ich versuchen, alle Informationen, die ich auf der Clientseite haben möchte, in einer SELECT-Anweisung zusammenzufassen, oder einfach so viele verwenden, wie es zweckmäßig erscheint?
TL; DR : Wenn meine verknüpfte Abfrage länger dauert als die Ausführung einzelner Abfragen, ist dies meine Schuld oder ist dies zu erwarten?
Erstens bin ich nicht sonderlich datenbanktauglich, daher kann es nur an mir liegen, aber ich habe festgestellt, dass es "oft" schneller ist, diese Informationen über mehrere Abfragen für einzelne Tabellen abzurufen (möglicherweise), wenn ich Informationen aus mehreren Tabellen abrufen muss eine einfache innere Verknüpfung enthalten) und patchen Sie die Daten auf der Clientseite, um zu versuchen, eine (komplexe) verknüpfte Abfrage zu schreiben, in der alle Daten in einer Abfrage abgerufen werden können.
Ich habe versucht, ein sehr einfaches Beispiel zusammenzustellen:
Schema-Setup :
CREATE TABLE MASTER
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);
CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);
INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');
CREATE SEQUENCE SEQ_DATA_ID;
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);
Abfrage A :
select NAME from MASTER
where ID = 1
| NAME |
--------
| One |
Abfrage B :
select ID, VALUE from DATA
where MASTER_ID = 1
| ID | VALUE |
--------------
| 1 | 1.3 |
| 2 | 1.5 |
| 3 | 1.7 |
Abfrage C :
select M.NAME, D.ID, D.VALUE
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1
| NAME | ID | VALUE |
---------------------
| One | 1 | 1.3 |
| One | 2 | 1.5 |
| One | 3 | 1.7 |
Natürlich habe ich keine Leistung mit diesen gemessen, aber man kann beobachten:
- Abfrage A + B gibt dieselbe Menge verwendbarer Informationen zurück wie Abfrage C.
- A + B muss 1 + 2x3 == 7 "Datenzellen" an den Client zurückgeben
- C muss 3x3 == 9 "Datenzellen" an den Client zurückgeben, da ich beim Join natürlich etwas Redundanz in die Ergebnismenge mit einbeziehe.
Verallgemeinern (so weit es geht):
Eine verknüpfte Abfrage muss immer mehr Daten zurückgeben als die einzelnen Abfragen, die dieselbe Informationsmenge erhalten. Da die Datenbank die Daten zusammenfügen muss, kann bei großen Datenmengen davon ausgegangen werden, dass die Datenbank mehr Arbeit an einer einzelnen verknüpften Abfrage als an den einzelnen Abfragen leisten muss, da (zumindest) mehr Daten an den Client zurückgegeben werden müssen.
Würde sich daraus ergeben, dass die Aufteilung einer clientseitigen Abfrage in mehrere Abfragen zu einer besseren Leistung führt, oder würde dies eher bedeuten, dass ich die verknüpfte Abfrage durcheinander gebracht habe?
Antworten:
In jedem Leistungs Szenario Sie müssen testen und messen die Lösungen zu sehen , welche schneller ist .
Trotzdem ist es fast immer so, dass eine verknüpfte Ergebnismenge aus einer ordnungsgemäß optimierten Datenbank schneller und skalierbarer ist als die Rückgabe der Quellzeilen an den Client und die anschließende Verknüpfung derselben. Denken Sie insbesondere bei großen Eingabesätzen und kleinen Ergebnissätzen an die folgende Abfrage im Kontext beider Strategien: Verbinden Sie zwei Tabellen mit jeweils 5 GB und einer Ergebnismenge von 100 Zeilen. Das ist ein Extrem, aber du verstehst, was ich meine.
Es ist sehr wahrscheinlich, dass das Datenbankschema oder die Indizes verbessert werden, um die Abfragen besser zu bedienen, die Sie darauf abzielen.
Normalerweise ist dies nicht der Fall. Meistens ist die Ergebnismenge auch bei großen Eingabesätzen viel kleiner als die Summe der Eingaben.
Je nach Anwendung werden sehr große Abfrageergebnismengen, die an den Client zurückgegeben werden, sofort als rote Fahne angezeigt. Was macht der Client mit einer so großen Datenmenge, die nicht näher an der Datenbank erstellt werden kann? Das Anzeigen von 1.000.000 Zeilen für einen Benutzer ist, gelinde gesagt, sehr verdächtig. Die Netzwerkbandbreite ist auch eine begrenzte Ressource.
Nicht unbedingt. Wenn die Daten korrekt indiziert sind, ist es wahrscheinlicher, dass die Verknüpfungsoperation in der Datenbank effizienter ausgeführt wird, ohne dass eine große Datenmenge gescannt werden muss. Darüber hinaus sind relationale Datenbank-Engines auf niedriger Ebene speziell für den Beitritt optimiert . Client-Stacks sind nicht.
Da Sie sagten, Sie seien unerfahren, wenn es um Datenbanken geht, empfehle ich Ihnen, mehr über das Datenbankdesign und die Leistungsoptimierung zu erfahren. Ich bin mir ziemlich sicher, dass hier das Problem liegt. Ineffizient geschriebene SQL-Abfragen sind ebenfalls möglich, bei einem einfachen Schema ist dies jedoch weniger wahrscheinlich.
Das heißt nicht, dass es keine anderen Möglichkeiten gibt, die Leistung zu verbessern. Es gibt Szenarien, in denen Sie einen mittleren bis großen Datensatz scannen und an den Client zurückgeben können, wenn eine Art Caching-Mechanismus verwendet werden soll. Zwischenspeichern kann großartig sein, bringt jedoch Komplexität in Ihr Design. Das Zwischenspeichern ist möglicherweise nicht einmal für Ihre Anwendung geeignet.
Eine Sache, die nirgendwo erwähnt wurde, ist die Aufrechterhaltung der Konsistenz der von der Datenbank zurückgegebenen Daten. Wenn separate Abfragen verwendet werden, ist es (aufgrund vieler Faktoren) wahrscheinlicher, dass inkonsistente Daten zurückgegeben werden, es sei denn, für jeden Abfragesatz wird eine Form der Snapshot-Isolation verwendet.
quelle
Sie haben einen guten Beispielcode zusammengestellt. Haben Sie sich das Timing in SQL Fiddle angesehen? Sogar einige kurze, unwissenschaftliche Leistungstests zeigen, dass die Ausführung von Abfrage drei in Ihrer Demonstration ungefähr genauso lange dauert wie die von Abfrage eins oder zwei getrennt. Die Kombination von eins und zwei dauert ungefähr doppelt so lange wie drei, bevor ein clientseitiger Join ausgeführt wird.
Wenn Sie die Datenmenge erhöhen, weichen die Abfragegeschwindigkeiten eins und zwei voneinander ab, der Datenbank-Join ist jedoch immer noch schneller.
Sie sollten auch überlegen, was passieren würde, wenn der innere Join Daten entfernt.
quelle
Das Abfrageoptimierungsprogramm sollte ebenfalls berücksichtigt werden. Ihre Aufgabe ist es, Ihr deklaratives SQL in prozedurale Schritte zu übersetzen. Um die effizienteste Kombination von Verfahrensschritten zu finden, werden Kombinationen aus Indexnutzung, Sortierungen, Zwischenspeichern von Zwischenergebnissen und allerlei anderem untersucht. Die Anzahl der Permutationen kann selbst bei recht einfachen Abfragen außerordentlich groß werden.
Ein Großteil der Berechnungen zur Ermittlung des besten Plans basiert auf der Verteilung der Daten in den Tabellen. Diese Verteilungen werden abgetastet und als Statistikobjekte gespeichert. Wenn diese falsch sind, veranlassen sie den Optimierer, schlechte Entscheidungen zu treffen. Schlechte Entscheidungen zu Beginn des Plans führen zu noch schlechteren Entscheidungen in einem Schneeballeffekt.
Es ist nicht ungewöhnlich, dass eine mittelgroße Abfrage, die bescheidene Datenmengen zurückgibt, Minuten benötigt, um ausgeführt zu werden. Durch eine korrekte Indizierung und eine gute Statistik wird dies auf Millisekunden reduziert.
quelle
Mehrere Abfragen sind der richtige Weg. Wenn Sie mit einfachen Szenarien wie diesen umgehen, ist der Kostenaufwand des Abfrageoptimierers ein Faktor. Mit mehr Daten tritt die Netzwerkineffizienz des Joins (redundante Zeilen) ein. Nur mit viel mehr Daten ist die Effizienz da.
Am Ende sehen viele Entwickler, was Sie erleben. Die Datenbankadministratoren sagen immer "Nein, mach einen Join", aber die Realität ist: In diesem Fall ist es schneller, mehrere einfache Auswahlen zu treffen.
quelle