it-swarm.com.de

Warum ist SQL nicht umgestaltbarer?

Jeder weiß, dass neue Entwickler lange Funktionen schreiben. Wenn Sie Fortschritte machen, können Sie Ihren Code besser in kleinere Teile zerlegen, und die Erfahrung lehrt Sie, wie wichtig dies ist.

Geben Sie SQL ein. Ja, die SQL-Denkweise über Code unterscheidet sich von der prozeduralen Denkweise über Code, aber dieses Prinzip scheint ebenso anwendbar zu sein.

Angenommen, ich habe eine Abfrage in folgender Form:

select * from subQuery1 inner join subQuerry2 left join subquerry3 left join join subQuery4 

Verwendung einiger IDs oder Daten usw.

Diese Unterabfragen sind selbst komplex und können eigene Unterabfragen enthalten. In keinem anderen Programmierkontext würde ich denken, dass die Logik für die komplexen Unterabfragen 1 bis 4 mit meiner übergeordneten Abfrage übereinstimmt, die sie alle verbindet. Es scheint so einfach zu sein, dass diese Unterabfragen als Ansichten definiert werden sollten, genau wie sie Funktionen wären, wenn ich prozeduralen Code schreiben würde.

Warum ist das nicht üblich? Warum schreiben Leute so oft diese langen monolithischen SQL-Abfragen? Warum fördert SQL nicht die Nutzung umfangreicher Ansichten, genau wie die prozedurale Programmierung die Nutzung umfangreicher Funktionen fördert? (In vielen Unternehmensumgebungen ist das Erstellen von Ansichten nicht einmal einfach. Es sind Anforderungen und Genehmigungen erforderlich. Stellen Sie sich vor, andere Programmierertypen müssten jedes Mal eine Anforderung senden, wenn sie eine Funktion erstellen!)

Ich habe mir drei mögliche Antworten überlegt:

  1. Dies ist bereits üblich und ich arbeite mit unerfahrenen Menschen

  2. Erfahrene Programmierer schreiben kein komplexes SQL, weil sie es vorziehen, Probleme bei der Datenverarbeitung mit prozeduralem Code zu lösen

  3. Etwas anderes

39
ebrts

Ich denke, das Hauptproblem ist, dass nicht alle Datenbanken Common Table Expressions unterstützen.

Mein Arbeitgeber nutzt DB/2 für viele Dinge. Die neuesten Versionen unterstützen CTEs, sodass ich folgende Aufgaben ausführen kann:

with custs as (
    select acct# as accountNumber, cfname as firstName, clname as lastName,
    from wrdCsts
    where -- various criteria
)
, accounts as (
    select acct# as accountNumber, crBal as currentBalance
    from crzyAcctTbl
)
select firstName, lastName, currentBalance
from custs
inner join accounts on custs.accountNumber = accounts.accountNumber

Das Ergebnis ist, dass wir stark abgekürzte Tabellen-/Feldnamen haben können und ich im Wesentlichen temporäre Ansichten mit besser lesbaren Namen erstelle, die ich dann verwenden kann. Klar, die Abfrage wird länger. Aber das Ergebnis ist, dass ich etwas schreiben kann, das ziemlich klar voneinander getrennt ist (mit CTEs, wie Sie Funktionen verwenden würden, um DRY zu erhalten) und am Ende Code habe, der gut lesbar ist. Und weil ich meine Unterabfragen aufteilen und eine Unterabfrage auf eine andere verweisen kann, ist nicht alles "inline". Ich habe gelegentlich einen CTE geschrieben, dann vier andere CTEs, die alle darauf verweisen, und dann die Ergebnisse der letzten vier von der Hauptabfragevereinigung.

Dies kann erfolgen mit:

  • DB/2
  • PostGreSQL
  • Orakel
  • MS SQL Server
  • MySQL (neueste Version; noch ein bisschen neu)
  • wahrscheinlich andere

Aber es trägt wesentlich dazu bei, den Code sauberer, lesbarer und trockener zu machen.

Ich habe eine "Standardbibliothek" von CTEs entwickelt, die ich in verschiedene Abfragen einbinden kann, um meine neue Abfrage zu starten. Einige von ihnen werden auch von anderen Entwicklern in meiner Organisation angenommen.

Mit der Zeit kann es sinnvoll sein, einige davon in Ansichten umzuwandeln, sodass diese "Standardbibliothek" verfügbar ist, ohne dass sie kopiert/eingefügt werden muss. Aber meine CTEs werden am Ende so leicht an verschiedene Anforderungen angepasst, dass ich nicht in der Lage war, einen einzigen CTE SO WIDELY ohne Mods zu verwenden, sodass es sich lohnen könnte, eine Ansicht zu erstellen.

Es scheint, dass ein Teil Ihrer Beschwerde lautet: "Warum weiß ich nichts über CTEs?" oder "Warum unterstützt meine DB keine CTEs?"

Was Updates betrifft ... ja, Sie können CTEs verwenden, aber meiner Erfahrung nach müssen Sie sie innerhalb der set-Klausel UND in der where-Klausel verwenden. Es wäre schön, wenn Sie eine oder mehrere vor der gesamten Update-Anweisung definieren und dann nur die "Hauptabfrage" -Teile in den set/where-Klauseln haben könnten, aber das funktioniert nicht so. Und obskure Tabellen-/Feldnamen in der Tabelle, die Sie aktualisieren, lassen sich nicht vermeiden.

Sie können CTEs zum Löschen verwenden. Es kann mehrere CTEs erfordern, um die PK/FK-Werte für Datensätze zu ermitteln, die Sie aus dieser Tabelle löschen möchten. Auch hier können Sie unklare Tabellen-/Feldnamen in der Tabelle, die Sie ändern, nicht vermeiden.

Soweit Sie eine Auswahl in eine Einfügung vornehmen können, können Sie CTEs für Einfügungen verwenden. Wie immer haben Sie es möglicherweise mit obskuren Tabellen-/Feldnamen in der Tabelle zu tun, die Sie ändern.

Mit SQL können Sie NICHT das Äquivalent eines Domänenobjekts erstellen, indem Sie eine Tabelle mit Getter/Setter umschließen. Dazu müssen Sie eine Art ORM zusammen mit einer prozeduraleren/OO - Programmiersprache verwenden. Ich habe solche Dinge in Java/Hibernate geschrieben.

25
Meower68

Das Sperren der Erstellung von Datenbankansichten wird häufig von Organisationen durchgeführt, die keine Leistungsprobleme in der Datenbank haben. Dies ist eher ein Problem der Organisationskultur als ein technisches Problem mit SQL.

Darüber hinaus werden große monolithische SQL-Abfragen häufig geschrieben, da der Anwendungsfall so spezifisch ist, dass nur sehr wenig SQL-Code in anderen Abfragen wirklich wiederverwendet werden kann. Wenn eine komplexe Abfrage benötigt wird, ist dies normalerweise ein ganz anderer Anwendungsfall. Das Kopieren der SQL aus einer anderen Abfrage ist häufig ein Ausgangspunkt. Aufgrund der anderen Unterabfragen und JOINs in der neuen Abfrage ändern Sie die kopierte SQL jedoch gerade so weit, dass jede Art von Abstraktion unterbrochen wird, die eine "Funktion" in einer anderen Sprache ausführen würde wird benutzt für. Das bringt mich zu dem wichtigsten Grund, warum SQL schwer zu überarbeiten ist.

SQL befasst sich nur mit konkreten Datenstrukturen, nicht mit abstraktem Verhalten (oder einer Abstraktion im wahrsten Sinne des Wortes). Da SQL auf konkreten Ideen basiert, gibt es nichts, was in ein wiederverwendbares Modul abstrahiert werden könnte. Datenbankansichten können dabei helfen, jedoch nicht auf der gleichen Ebene wie eine "Funktion" in einer anderen Sprache. Eine Datenbankansicht ist weniger eine Abstraktion als eine Abfrage. Nun, eigentlich ist eine Datenbankansicht ist eine Abfrage. Es wird im Wesentlichen wie eine Tabelle verwendet, aber wie eine Unterabfrage ausgeführt. Sie haben es also wieder mit etwas Konkretem zu tun, nicht mit Abstraktem.

Mit Abstraktionen lässt sich Code leichter umgestalten, da eine Abstraktion Implementierungsdetails vor dem Konsumenten dieser Abstraktion verbirgt. Straight SQL bietet keine solche Trennung, obwohl prozedurale Erweiterungen von SQL wie PL/SQL für Oracle oder Transact-SQL für SQL Server die Linien ein wenig verwischen.

36
Greg Burghardt

Ich denke, dass Sie in Ihrer Frage/Sichtweise möglicherweise fehlen, dass SQL Operationen an Mengen ausführt (unter Verwendung von Mengenoperationen usw.).

Wenn Sie auf dieser Ebene arbeiten, geben Sie natürlich die Kontrolle über den Motor auf. Sie können immer noch einen prozeduralen Stilcode mit Cursorn erzwingen, aber wie die Erfahrung zeigt, sollten Sie dies 99/100 Mal nicht tun.

Refactoring SQL ist möglich, verwendet jedoch nicht die gleichen Code-Refactoring-Prinzipien wie im Code auf Anwendungsebene. Stattdessen optimieren Sie, wie Sie die SQL-Engine selbst verwenden.

Dies kann auf verschiedene Arten erfolgen. Wenn Sie Microsoft SQL Server verwenden, können Sie SSMS verwenden, um einen ungefähren Ausführungsplan bereitzustellen, und Sie können diesen verwenden, um zu sehen, welche Schritte Sie zum Optimieren Ihres Codes ausführen können.

Im Fall der Aufteilung von Code in kleinere Module, wie @ greg-burghardt erwähnte, ist SQL im Allgemeinen ein speziell erstellter Code und daher. Es macht das eine, wofür du es brauchst und sonst nichts. Es hält sich an das S in SOLID, es hat nur einen Grund, geändert/beeinflusst zu werden, und dann benötigen Sie diese Abfrage, um etwas anderes zu tun. Der Rest des Akronyms (OLID) gilt hier nicht (AFAIK gibt es keine Abhängigkeitsinjektion, Schnittstellen oder Abhängigkeiten als solche in SQL). Abhängig von der verwendeten SQL-Variante können Sie möglicherweise bestimmte Abfragen erweitern, indem Sie sie umschließen In einer gespeicherten Prozedur/Tabellenfunktion oder wenn Sie sie als Unterabfragen verwenden, würde ich sagen, dass das Open-Closed-Prinzip in gewisser Weise immer noch gilt. Aber ich schweife ab.

Ich denke, Sie müssen Ihr Paradigma dahingehend ändern, wie Sie SQL-Code anzeigen. Aufgrund der festgelegten Art kann es nicht viele der Funktionen bieten, die Sprachen auf Anwendungsebene bieten können (Generika usw.). SQL wurde nie so konzipiert, es ist eine Sprache zum Abfragen von Datensätzen, und jeder Satz ist auf seine Weise einzigartig.

Abgesehen davon gibt es Möglichkeiten, wie Sie Ihren Code schöner aussehen lassen können, wenn die Lesbarkeit innerhalb des Unternehmens eine hohe Priorität hat. Speichern von Bits häufig verwendeter SQL-Blöcke (von Ihnen verwendete allgemeine Datensätze) in gespeicherten Prozeduren/Tabellenwertfunktionen und anschließendes Abfragen und Speichern in temporären Tabellen/Tabellenvariablen, gefolgt von deren Verwendung, um die Teile zu einer massiven Transaktion zusammenzufügen dass Sie sonst schreiben würden, ist eine Option. IMHO lohnt es sich nicht, so etwas mit SQL zu machen.

Als Sprache ist sie so konzipiert, dass sie für jeden, auch für Nicht-Programmierer, leicht lesbar und verständlich ist. Wenn Sie also nichts sehr Kluges tun, müssen Sie den SQL-Code nicht in kleinere Teile mit Byte-Größe umgestalten. Ich persönlich habe während der Arbeit an einer Data Warehouse-ETL/Reporting-Lösung umfangreiche SQL-Abfragen geschrieben, und alles war immer noch sehr klar in Bezug auf die Vorgänge. Alles, was für andere etwas seltsam ausgesehen haben könnte, würde eine kurze Reihe von Kommentaren erhalten, um eine kurze Erklärung zu liefern.

Ich hoffe das hilft.

12
Toni Kostelac

Ich werde mich in Ihrem Beispiel auf die "Unterabfragen" konzentrieren.

Warum werden sie so oft verwendet? Weil sie die natürliche Denkweise einer Person verwenden: Ich habe diese Datenmenge und möchte eine Aktion für eine Teilmenge davon ausführen und diese mit einer Teilmenge anderer Daten verbinden. 9 von 10 Mal, wenn ich eine Unterabfrage sehe, wird sie falsch verwendet. Mein Witz über Unterabfragen lautet: Leute, die Angst vor Joins haben, verwenden Unterabfragen.

Wenn Sie solche Unterabfragen sehen, ist dies häufig auch ein Zeichen für ein nicht optimales Datenbankdesign.

Je normalisierter Ihre Datenbank ist, je mehr Verknüpfungen Sie erhalten, desto mehr sieht Ihre Datenbank wie eine große Excel-Tabelle aus, desto mehr Unterauswahlen erhalten Sie.

Refactoring in SQL hat oft ein anderes Ziel: mehr Leistung, bessere Abfragezeiten, "Vermeiden von Tabellenscans". Diese können den Code sogar weniger lesbar machen, sind aber sehr wertvoll.

Warum sehen Sie so viele riesige monolithische, nicht überarbeitete Abfragen?

  • SQL ist in vielerlei Hinsicht keine Programmiersprache.
  • Schlechtes Datenbankdesign.
  • Leute, die SQL nicht wirklich fließend beherrschen.
  • Keine Stromversorgung über die Datenbank (z. B. keine Ansichten verwenden dürfen)
  • Unterschiedliche Ziele beim Refactoring.

(Je erfahrener ich mit SQL bin, desto weniger umfangreich werden meine Abfragen. Mit SQL können Menschen aller Könnensstufen ihre Arbeit erledigen, egal was passiert.)

6
Pieter B

Aufgabentrennung

Im Sinne von SQL ist die Datenbank ein gemeinsam genutztes Asset, das die Unternehmensdaten enthält. Der Schutz dieser Daten ist von entscheidender Bedeutung. Betritt den DBA als Hüter des Tempels.

Das Erstellen einer neuen Ansicht in der Datenbank dient einem dauerhaften Zweck und wird von einer Benutzergemeinschaft geteilt. In der DBA-Ansicht ist dies nur zulässig, wenn die Ansicht durch die Struktur der Daten gerechtfertigt ist. Jede Änderung einer Ansicht ist dann mit Risiken für alle aktuellen Benutzer verbunden, auch für diejenigen, die die Anwendung nicht verwenden, aber die Ansicht entdeckt haben. Schließlich erfordert das Erstellen neuer Objekte die Verwaltung von Berechtigungen und im Falle der Ansicht konsistent mit den Berechtigungen der zugrunde liegenden Tabellen.

All dies erklärt, warum Datenbankadministratoren nicht gerne Ansichten hinzufügen, die nur für den Code einer einzelnen Anwendung bestimmt sind.

SQL-Design

Wenn Sie eine Ihrer komplexen Abfragen in Nizza zerlegen, stellen Sie möglicherweise fest, dass die Unterabfragen häufig einen Parameter benötigen, der von einer anderen Unterabfrage abhängt.

Das Transformieren von Unterabfragen in der Ansicht ist daher nicht unbedingt so einfach wie angegeben. Sie müssen die variablen Parameter isolieren und Ihre Ansicht so gestalten, dass die Parameter als Auswahlkriterien zur Ansicht hinzugefügt werden können.

Leider müssen Sie dabei manchmal mehr und weniger effektiv auf Daten zugreifen als bei einer maßgeschneiderten Abfrage.

Proprietäre Erweiterungen

Sie können auf ein Refactoring hoffen, indem Sie einige Verantwortlichkeiten auf prozedurale Erweiterungen von SQL wie PL/SQL oder T-SQL übertragen. Diese sind jedoch herstellerabhängig und schaffen eine technologische Abhängigkeit. Darüber hinaus werden diese Erweiterungen auf dem Datenbankserver ausgeführt, wodurch mehr Verarbeitungslast für eine Ressource entsteht, die viel schwieriger zu skalieren ist als ein Anwendungsserver.

Aber was ist das Problem am Ende?

Ist die Aufgabentrennung und das SQL-Design mit seinen Stärken und Einschränkungen ein echtes Problem? Letztendlich haben sich diese Datenbanken als erfolgreich und zuverlässig für sehr kritische Daten erwiesen, auch in geschäftskritischen Umgebungen.

Um ein erfolgreiches Refactoring zu erreichen:

  • betrachten Sie ein bessere Kommunikation. Versuchen Sie, die Einschränkungen Ihres DBA zu verstehen. Wenn Sie einem DBA nachweisen, dass eine neue Ansicht durch die Datenstrukturen gerechtfertigt ist, dass es sich nicht um eine Wegwerf-Problemumgehung handelt und dass sie keine Auswirkungen auf die Sicherheit hat, wird er/sie mit Sicherheit zustimmen, dass sie erstellt wird. Denn dann wäre es ein gemeinsames Interesse.

  • bereinigen Sie Ihr eigenes Haus zuerst: Nichts zwingt Sie dazu, an vielen Stellen viel SQL zu generieren. Refaktorieren Sie Ihren Anwendungscode, um die SQL-Zugriffe zu isolieren und die Klassen oder Funktionen zu erstellen, um wiederverwendbare Unterabfragen bereitzustellen, falls diese häufig verwendet werden.

  • verbessern Teambewusstsein: Stellen Sie sicher, dass Ihre Anwendung keine Aufgaben ausführt, die von der DBMS-Engine effizienter ausgeführt werden könnten. Wie Sie zu Recht betont haben, werden der prozedurale Ansatz und der datenorientierte Ansatz von verschiedenen Teammitgliedern nicht gleichermaßen beherrscht. Es hängt von ihrem Hintergrund ab. Um das System als Ganzes zu optimieren, muss Ihr Team es als Ganzes verstehen. Schaffen Sie also Bewusstsein, um sicherzustellen, dass weniger erfahrene Spieler das Rad nicht neu erfinden und ihre DB-Gedanken mit erfahreneren Mitgliedern teilen.

2
Christophe

Zu den Punkten 1 und 3: Ansichten sind nicht der einzige Weg. Abhängig vom RDBMS gibt es auch temporäre Tabellen, Marts, Tabellenvariablen, aggregierte Spalten, CTEs, Funktionen, gespeicherte Prozeduren und möglicherweise andere Konstrukte.

DBAs (und ich spreche als jemand, der sowohl DBA als auch Entwickler war) neigen dazu, die Welt auf ziemlich binäre Weise zu betrachten, und sind daher aufgrund der wahrgenommenen Leistungseinbußen oft gegen Dinge wie Ansichten und Funktionen.

In letzter Zeit hat sich der Bedarf an komplexen Verknüpfungen verringert, da erkannt wurde, dass denormalisierte Tabellen, obwohl sie aus Sicht von NF nicht optimal sind, eine hohe Leistung erbringen.

Es gibt auch den Trend, Abfragen clientseitig mit Technologien wie LINQ durchzuführen, die Sie in Punkt 2 ansprechen.

Obwohl ich der Meinung bin, dass die Modularisierung von SQL schwierig sein kann, wurden große Fortschritte erzielt, obwohl es immer eine Zweiteilung zwischen clientseitigem Code und SQL geben wird - obwohl 4GL die Linien etwas verwischt hat.

Ich denke, es hängt wirklich davon ab, inwieweit Ihre DBAs/Architekten/Techniker bereit sind, diesbezüglich abzutreten. Wenn sie sich weigern, etwas anderes als Vanilla SQL mit vielen Verknüpfungen zuzulassen, können große Abfragen auftreten. Wenn Sie damit nicht weiterkommen, schlagen Sie Ihren Kopf nicht gegen eine Mauer, eskalieren Sie sie. Es gibt im Allgemeinen bessere Möglichkeiten, Dinge mit ein wenig Kompromiss zu tun - insbesondere, wenn Sie die Vorteile nachweisen können.

1
Robbie Dee