it-swarm.com.de

Sind einzelne Abfragen schneller als Joins?

Konzeptionelle Frage: Sind einzelne Abfragen schneller als Verknüpfungen, oder: Sollte ich versuchen, alle gewünschten Informationen auf der Clientseite in eins SELECT zu komprimieren Anweisung oder verwenden Sie einfach so viele, wie es zweckmäßig erscheint ?

TL; DR : Wenn my verbundene Abfrage länger dauert als das Ausführen einzelner Abfragen, ist dies meine Schuld oder ist dies der Fall erwartet werden?

Erstens bin ich nicht sehr datenbankbewusst, daher bin es vielleicht nur ich, aber ich habe festgestellt, dass es "oft" schneller ist, diese Informationen über mehrere Abfragen in einzelnen Tabellen abzurufen (möglicherweise ", wenn ich Informationen aus mehreren Tabellen abrufen muss enthält einen einfachen inneren Join) und patchen die Daten auf der Clientseite zusammen, um zu versuchen, eine (komplexe) verknüpfte Abfrage zu schreiben, bei der ich alle Daten in einer Abfrage erhalten kann.

Ich habe versucht, ein äußerst einfaches Beispiel zusammenzustellen:

SQL Fiddle

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

Ergebnisse:

| NAME |
--------
|  One |

Abfrage B :

select ID, VALUE from DATA
where MASTER_ID = 1

Ergebnisse:

| 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

Ergebnisse:

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

Natürlich habe ich damit keine Leistung gemessen, aber man kann beobachten:

  • Abfrage A + B gibt die gleiche 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 mit dem Join natürlich eine gewisse Redundanz in die Ergebnismenge einbinde.

Verallgemeinern davon (so weit hergeholt wie es ist):

Eine verknüpfte Abfrage immer muss mehr Daten zurückgeben als die einzelnen Abfragen, die dieselbe Informationsmenge erhalten. Da die Datenbank die Daten zusammenschustern muss, für große Datenmengen kann man davon ausgehen, dass die Datenbank mehr Arbeit an einer einzelnen verknüpften Abfrage leisten muss als an den einzelnen, da (zumindest) dies der Fall ist muss mehr Daten an den Client zurückgeben.

Würde sich daraus ergeben, dass wenn ich feststelle, dass das Aufteilen einer clientseitigen Abfrage in mehrere Abfragen eine bessere Leistung erbringt, dies nur der richtige Weg ist, oder würde dies eher bedeuten, dass ich die verknüpfte Abfrage durcheinander gebracht habe?

46
Martin

Sind einzelne Abfragen schneller als Verknüpfungen oder: Sollte ich versuchen, alle gewünschten Informationen auf der Clientseite in einer SELECT-Anweisung zusammenzufassen oder nur so viele zu verwenden, wie es zweckmäßig erscheint?

In jedem Leistungsszenario müssen Sie testen und messen die Lösungen, um zu sehen, welche schneller sind .

Es ist jedoch fast immer so, dass eine verknüpfte Ergebnismenge aus einer ordnungsgemäß abgestimmten Datenbank schneller und besser skalierbar ist, als die Quellzeilen an den Client zurückzugeben und sie dort zu verbinden. Insbesondere wenn die Eingabesätze groß und die Ergebnismenge klein sind, denken Sie im Zusammenhang mit beiden Strategien an die folgende Abfrage: Verbinden Sie zwei Tabellen mit jeweils 5 GB und einer Ergebnismenge von 100 Zeilen. Das ist extrem, aber Sie sehen meinen Standpunkt.

Ich habe festgestellt, dass es "oft" schneller ist, diese Informationen über mehrere Abfragen in einzelnen Tabellen (möglicherweise mit einem einfachen inneren Join) abzurufen und die Daten auf der Clientseite zusammenzufügen, um zu versuchen, wenn ich Informationen aus mehreren Tabellen abrufen muss um eine (komplexe) verknüpfte Abfrage zu schreiben, bei der ich alle Daten in einer Abfrage erhalten kann.

Es ist sehr wahrscheinlich, dass das Datenbankschema oder die Indizes verbessert werden, um die Abfragen, die Sie darauf werfen, besser bedienen zu können.

Eine verknüpfte Abfrage muss immer mehr Daten zurückgeben als die einzelnen Abfragen, die dieselbe Informationsmenge erhalten.

Normalerweise ist dies nicht der Fall. Selbst wenn die Eingabesätze groß sind, ist die Ergebnismenge meistens viel kleiner als die Summe der Eingaben.

Je nach Anwendung sind sehr große Abfrageergebnismengen, die an den Client zurückgegeben werden, eine sofortige rote Fahne: Was macht der Client mit einer so großen Datenmenge, die nicht näher an der Datenbank ausgeführt werden kann? Das Anzeigen von 1.000.000 Zeilen für einen Benutzer ist, gelinde gesagt, höchst verdächtig. Die Netzwerkbandbreite ist auch eine endliche Ressource.

Da die Datenbank die Daten zusammenschustern 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 sie (zumindest) mehr Daten an den Client zurückgeben muss.

Nicht unbedingt. Wenn die Daten korrekt indiziert sind, wird die Verknüpfungsoperation in der Datenbank mit größerer Wahrscheinlichkeit effizienter ausgeführt, ohne dass eine große Datenmenge gescannt werden muss. Darüber hinaus sind relationale Datenbank-Engines speziell auf niedriger Ebene für das Beitreten optimiert ; Client-Stacks gibt es nicht.

Würde sich daraus ergeben, dass wenn ich feststelle, dass das Aufteilen einer clientseitigen Abfrage in mehrere Abfragen eine bessere Leistung erbringt, dies nur der richtige Weg ist, oder würde dies eher bedeuten, dass ich die verknüpfte Abfrage durcheinander gebracht habe?

Da Sie sagten, dass Sie in Bezug auf Datenbanken unerfahren sind, würde ich empfehlen, mehr über Datenbankdesign und Leistungsoptimierung zu erfahren. Ich bin mir ziemlich sicher, dass hier das Problem liegt. Ineffizient geschriebene SQL-Abfragen sind ebenfalls möglich, aber mit einem einfachen Schema ist dies weniger wahrscheinlich ein Problem.

Das heißt nicht, dass es keine anderen Möglichkeiten gibt, die Leistung zu verbessern. Es gibt Szenarien, in denen Sie einen mittelgroßen bis großen Datensatz scannen und an den Client zurückgeben können, wenn ein Caching-Mechanismus verwendet werden soll. Caching kann großartig sein, führt jedoch zu Komplexität in Ihrem Design. Das Caching ist möglicherweise nicht einmal für Ihre Anwendung geeignet.

Eine Sache, die nirgendwo erwähnt wurde, ist die Wahrung der Konsistenz der von der Datenbank zurückgegebenen Daten. Wenn separate Abfragen verwendet werden, ist es wahrscheinlicher (aufgrund vieler Faktoren), dass inkonsistente Daten zurückgegeben werden, es sei denn, für jede Gruppe von Abfragen wird eine Form der Snapshot-Isolation verwendet.

46
Jon Seigel

Natürlich habe ich damit keine Leistung gemessen

Sie haben einen guten Beispielcode zusammengestellt. Haben Sie sich das Timing in SQL Fiddle angesehen? Selbst einige kurze unwissenschaftliche Leistungstests zeigen, dass die Ausführung von Abfrage drei in Ihrer Demonstration ungefähr genauso lange dauert wie die Abfrage eins oder zwei separat. Die Kombination aus eins und zwei dauert etwa doppelt so lange wie drei, bevor ein clientseitiger Join ausgeführt wird.

Wenn Sie die Daten erhöhen, würde die Geschwindigkeit von Abfrage eins und zwei abweichen, aber der Datenbank-Join wäre immer noch schneller.

Sie sollten auch überlegen, was passieren würde, wenn der innere Join Daten eliminiert.

6
Leigh Riffel

Der Abfrageoptimierer sollte ebenfalls berücksichtigt werden. Seine Aufgabe ist es, Ihr deklaratives SQL in prozedurale Schritte zu übersetzen. Um die effizienteste Kombination von Verfahrensschritten zu finden, werden Kombinationen aus Indexverwendung, Sortierung, Zwischenspeichern von Zwischenergebnismengen und vielen anderen Dingen untersucht. Die Anzahl der Permutationen kann selbst bei recht einfachen Abfragen außerordentlich groß werden.

Ein Großteil der Berechnungen, die durchgeführt werden, um den besten Plan zu finden, hängt von der Verteilung der Daten innerhalb der Tabellen ab. Diese Verteilungen werden abgetastet und als Statistikobjekte gespeichert. Wenn diese falsch sind, führen sie den Optimierer dazu, schlechte Entscheidungen zu treffen. Schlechte Entscheidungen zu Beginn des Plans führen später bei einem Schneeball-Effekt zu noch schlechteren Entscheidungen.

Es ist nicht unbekannt, dass eine mittelgroße Abfrage, die bescheidene Datenmengen zurückgibt, Minuten in Anspruch nimmt. Eine korrekte Indizierung und gute Statistiken reduzieren diese dann auf Millisekunden.

2
Michael Green