Wie kann ich das Schreiben komplexer SQL-Abfragen vereinfachen? [geschlossen]

42

Ich finde es sehr schwierig, komplexe SQL-Abfragen zu schreiben, die Verknüpfungen über viele (mindestens 3-4) Tabellen und mehrere verschachtelte Bedingungen beinhalten. Die Abfragen, zu denen ich aufgefordert werde, lassen sich leicht durch ein paar Sätze beschreiben, erfordern jedoch möglicherweise eine irreführende Menge an Code, um sie auszuführen. Ich benutze häufig temporäre Ansichten, um diese Abfragen zu schreiben, die wie eine Krücke wirken. Welche Tipps können Sie mir geben, um diese komplexen Abfragen zu vereinfachen? Wie kann ich diese Abfragen in die Schritte unterteilen, die zum eigentlichen Schreiben des SQL-Codes erforderlich sind?

Beachten Sie, dass ich der SQL-Code bin, den ich schreiben soll, Teil der Hausaufgaben für einen Datenbankkurs ist. Daher möchte ich keine Software, die die Arbeit für mich erledigt. Ich möchte den Code, den ich schreibe, wirklich verstehen.

Weitere technische Details:

  • Die Datenbank wird auf einem PostgreSQL-Server gehostet, der auf dem lokalen Computer ausgeführt wird.
  • Die Datenbank ist sehr klein: Es gibt nicht mehr als sieben Tabellen und die größte Tabelle hat weniger als 50 Zeilen.
  • Die SQL-Abfragen werden unverändert über LibreOffice Base an den Server übergeben.
bwDraco
quelle
Temporäre Ansichten sind eigentlich sehr nützlich, da Sie mit einer solchen Tabelle (wie expliziten komplexen Indizes) etwas anfangen können, das für den SQL-Parser nur sehr schwer zu erkennen ist.
Persönlich finde ich es einfacher, mit einer grafischen Benutzeroberfläche (z. B. LibreOffice Base "Abfrage in der Entwurfsansicht erstellen" oder Office Access "Erstellen"> "Abfrageentwurf") zu cheaten und dann die von dieser erstellte SQL anzuzeigen. Manchmal ist es notwendig, die von einem GUI-Designer angegebene SQL zu ändern, aber es gibt einen guten Ausgangspunkt
kurdtpage

Antworten:

49

Ich stütze mich dabei hauptsächlich auf den Versuch, die "richtige" Antwort zu erhalten, sodass Sie möglicherweise feststellen, dass es einige Leistungsprobleme gibt. Es macht keinen Sinn, eine falsche Abfrage zu beschleunigen.

Verstehen Sie die Tabellenbeziehungen - Die meisten werden eins zu viele sein. Kennen Sie die "viele" Tabelle. Identifizieren Sie die für Ihre Joins erforderlichen Felder.

Denken Sie an LINKS-Beitrittsszenarien - Wählen Sie alle Mitarbeiter und deren Gehaltsscheck aus dem letzten Monat aus. Was wäre, wenn sie letzten Monat keinen Gehaltsscheck bekämen?

Kennen Sie die Ergebnismenge: 1) Geben Sie in einer Tabelle manuell mindestens einen korrekten Datensatz für Ihre Abfrage ein. 2) Schreiben Sie die Abfrage in einer ausreichend einfachen Form, um zu bestimmen, wie viele Datensätze zurückgegeben werden sollen. Verwenden Sie diese beiden Methoden, um Ihre Abfrage zu testen und sicherzustellen, dass das Ergebnis durch das Verknüpfen einer neuen Tabelle nicht geändert wird.

Teilen Sie Ihre Anfrage in überschaubare Teile auf - Sie müssen nicht alles auf einmal schreiben. Komplexe Abfragen können manchmal nur eine Sammlung einfacher Abfragen sein.

Beachten Sie gemischte Aggregationsebenen : Wenn Sie monatliche, vierteljährliche und jährliche Werte in dieselbe Ergebnismenge aufnehmen müssen, müssen Sie diese in Abfragen, die auf verschiedenen Werten gruppiert sind, separat berechnen.

Wissen, wann UNION erforderlich ist Manchmal ist es einfacher, Untergruppen in ihre eigenen select-Anweisungen aufzuteilen. Wenn Sie eine Tabelle mit Managern und anderen Mitarbeitern gemischt haben und in jeder Spalte Case-Anweisungen ausführen müssen, die auf der Zugehörigkeit zu einer dieser Gruppen basieren, ist es möglicherweise einfacher, eine Manager-Abfrage und eine Union zu einer Mitarbeiter-Abfrage zu schreiben. Jeder würde seine eigene Logik enthalten. Es liegt auf der Hand, Elemente aus verschiedenen Tabellen in verschiedene Zeilen aufnehmen zu müssen.

Komplexe / verschachtelte Formeln - Versuchen Sie, konsistent einzurücken, und haben Sie keine Angst davor, mehrere Zeilen zu verwenden. "CASE WHEN CASE WHEN CASE WHEN" wird Sie verrückt machen. Nehmen Sie sich Zeit, um diese zu durchdenken. Speichern Sie die komplexen Berechnungen zum Schluss. Wählen Sie zuerst die richtigen Datensätze aus. Dann greifen Sie komplexe Formeln an und wissen, dass Sie mit den richtigen Werten arbeiten. Wenn Sie die in den Formeln verwendeten Werte sehen, können Sie Bereiche erkennen, in denen Sie NULL-Werte berücksichtigen müssen und in denen Sie mit dem Fehler der Division durch Null umgehen müssen.

Testen Sie regelmäßig, während Sie neue Tabellen hinzufügen, um sicherzustellen, dass Sie immer noch die gewünschte Ergebnismenge erhalten und wissen, welcher Join oder welche Klausel der Schuldige ist.

JeffO
quelle
1
Wirklich exzellente Sachen. Ich möchte Jeffs Argumente für die Suche nach LINKEN Verknüpfungen und die Aufteilung komplexer Abfragen in kleinere, besser verwaltbare und anschließende Kombination hervorheben. Ich schreibe fast jeden Tag große Abfragen in großen Datenbanken, und diese beiden Dinge tauchen die ganze Zeit auf. Führen Sie Ihre Abfragen und Unterabfragen immer so schnell wie möglich aus, um sicherzustellen, dass Sie die Daten erhalten, die Sie bei jedem Schritt erwarten.
CodexArcanum
@CodexArcanum - und wenn Sie Abfragen für Big Data ausführen, schadet es nicht, TOP zu verwenden;)
JeffO
Ich stimme jeder Aussage Ihres Vorschlags zu
Alessandro Rossi
28
  1. Einrücken wäre das erste, was Sie tun müssen, wenn Sie es nicht bereits tun. Dies ist nicht nur bei einfachen Abfragen hilfreich, sondern auch bei Verknüpfungen und Abfragen, die etwas komplexer sind als a select top 1 [ColumnName] from [TableName].

  2. Einmal richtig eingerückt, verbietet nichts, Kommentare in die Abfrage selbst einzufügen, wenn dies angebracht ist. Überbeanspruchen Sie sie nicht: Wenn der Code explizit genug ist, schadet das Hinzufügen von Kommentaren nur der Klarheit des Codes. Sie sind jedoch für die weniger expliziten Teile der Abfrage immer noch willkommen.

    Beachten Sie, dass längere Abfragen (einschließlich Abfragen mit Kommentaren) eine größere Bandbreitennutzung zwischen Ihrem Anwendungsserver und Ihrem Datenbankserver bedeuten. Beachten Sie auch, dass die durch die Kommentare hinzugefügte Größe möglicherweise nichts für Sie in Bezug auf die Leistung ändert, es sei denn, Sie arbeiten an einem Produkt im Google-Maßstab mit einer großen Anzahl von Anfragen pro Sekunde, die eine außergewöhnliche Leistung und Ressourcenverwendung erfordern.

  3. Das Erzwingen des gleichen Stils für Tabellen, Spalten usw. trägt ebenfalls erheblich zur Lesbarkeit bei. Wenn eine Legacy - Datenbank die Tabellen hat PRODUCT, users, USERS_ObsoleteDONT_USE, PR_SHIPMENTSund HRhbYd_UU, etwas tut jemand sehr falsch.

  4. Das Erzwingen des gleichen Stils bei Abfragen ist ebenfalls wichtig. Wenn Sie beispielsweise Abfragen für Microsoft SQL Server schreiben und sich für die Verwendung [TableName]von entscheiden TableName, bleiben Sie dabei. Wenn Sie nach a zu einer neuen Zeile wechseln select, tun Sie dies nicht nur in der Hälfte Ihrer Abfragen, sondern in allen.

  5. Nicht verwenden* , es sei denn, es gibt gute Gründe dafür (wie if exists(select * from [TableName] where ...)in Microsoft SQL Server). Dies *wirkt sich nicht nur negativ auf die Leistung einiger (wenn nicht der meisten) Datenbanken aus, sondern ist auch für den Entwickler, der Ihre Abfrage verwendet, nicht hilfreich. Ebenso muss ein Entwickler auf die Werte nach Namen zugreifen, niemals nach Index.

  6. Schließlich ist es für Selects nichts Falsches, eine Ansicht bereitzustellen . Für alles andere können auch gespeicherte Prozeduren verwendet werden, abhängig vom Projekt und den Personen, mit denen Sie arbeiten².


¹ Manche Leute hassen gespeicherte Prozeduren. Andere mögen sie aus mehreren (zumindest aus diesen Gründen) Gründen nicht.

² Ihre Kollegen, die anderen Schüler, Ihre Lehrer usw.

Arseni Mourzenko
quelle
9

Ein bisschen wie im Dunkeln, aber wenn Sie viele temporäre Ansichten schreiben, haben Sie vielleicht noch nicht gemerkt, dass an den meisten Stellen, an denen Sie eine Tabelle in eine SQL-Anweisung einfügen können, diese Tabelle durch eine Abfrage ersetzt werden kann.

Anstatt also Tabelle A mit temporärer Ansicht B zu verbinden, können Sie Tabelle A mit der Abfrage verbinden, die Sie als temporäre Ansicht B verwendet haben. Beispiel:

    SELECT A.Col1, A.Col2, B.Col1,B.Col2
      FROM (SELECT RealTableZ.Col1, RealTableY.Col2, RealTableY.ID as ID
              FROM RealTableZ 
   LEFT OUTER JOIN RealTableY
                ON RealTableZ.ForeignKeyY=RealTableY.ID
             WHERE RealTableY.Col11>14
            ) As B
        INNER JOIN A
                ON A.ForeignKeyY=B.ID

Dieses Beispiel ist ziemlich sinnlos, sollte aber die Syntax erläutern.

Für Ansichten, die nicht "speziell" sind (indiziert, partitioniert), sollte dies zu demselben Abfrageplan führen, als ob Sie eine Ansicht verwendet hätten.

Um das Schreiben zu vereinfachen, können Sie jedes Teil überprüfen, um sicherzustellen, dass Sie das erhalten, was Sie erwarten, bevor Sie die gesamte Abfrage ausschreiben.

Ich entschuldige mich, wenn das für Sie schon ein alter Hut ist.

bA
quelle
3
Ich bin ein Experte für SQL und hasse diesen Einzug wirklich: Es mag nett aussehen, ist aber "meiner Meinung nach" völlig nutzlos. Zwei Gründe: Ich kann nicht klar verstehen, ob diese linke äußere Verknüpfung Teil der Hauptabfrage oder Teil einer Unterabfrage ist, ob sie eine Code-Verschönerung benötigt und wann immer Sie ein paar Zeilen hinzufügen möchten, müssen Sie den gesamten Text erneut verschönern . Planen Sie Einrückungen, die nur TABS benötigen. Dies ist wesentlich flexibler. Ich habe Ihre Antwort nicht herabgestimmt, aber ich entmutige wirklich jeden, der diesen Stil verwendet ... vor allem, wenn er meine Hilfe benötigt.
Alessandro Rossi
7

Verwenden Sie anstelle von temporären Ansichten die WITH-Klausel . Dies macht es viel einfacher, große Abfragen in lesbarere kleinere Teile zu zerlegen.

user281377
quelle
1
Wenn Sie ein CTE verwenden, beachten Sie, dass die Abfrage nur bis zur nächsten Abfrage ausgeführt wird. In einigen Fällen, in denen Sie das CTE in mehreren Abfragen verwenden, ist es möglicherweise für die Leistung besser, eine temporäre Tabelle zu verwenden.
Rachel
3
  1. Machen Sie sich mit der Mengenlehre vertraut, wenn Sie es noch nicht sind. SQL basiert auf Mengenlehre, und wenn Sie mehr über Mengen wissen, werden Sie besser mit der Funktionsweise von SQL vertraut.
  2. Übe mehr SQl, wenn du nur SQL lernst, wird es einige Zeit dauern, bis du verstehst, wie man alles macht. Manchmal dauert es nur eine Weile, bis du sie wirklich verstehst.
  3. Stellen Sie sicher, dass die Tabellen, die Sie abfragen, ordnungsgemäß gestaltet sind
  4. Haben Sie keine Angst davor, Ansichten für ausgewählte Abfragen zu verwenden, insbesondere wenn Sie einen gemeinsamen Satz haben, der auf verschiedene Arten verfeinert werden muss
Ryathal
quelle
1

Wie alles andere möchten Sie das Problem in überschaubare Teile aufteilen.

Übrigens lösen Sie auf diese Weise komplexe Probleme.

Also: Sie möchten die Unterabfrage überprüfen, um festzustellen, ob sie wirklich das zurückgibt, was Sie möchten, bevor Sie eine äußere Abfrage ausführen. Sie möchten versuchen, eine minimale Verknüpfung für jeden Tisch herzustellen, an dem Sie teilnehmen, damit Sie sehen, dass Sie wirklich richtig darüber nachdenken. Sachen wie diese. Es ist einfach unrealistisch zu hoffen, dass Sie alles auf einmal eingeben und genau das herausholen, was Sie wollen.

Eine SQL-Anweisung ist, sobald sie ein bestimmtes Maß an Komplexität erreicht, im Grunde genommen ein kleines Programm für sich. Es macht einen großen Unterschied zu verstehen, wie die Daten kombiniert, ausgewählt, gefiltert und ausgegeben werden.

Dan Ray
quelle