Ist SQL deklarativ?

22

Ich frage, weil sich so viele der Fragen, die ich in SQL sehe, auf Folgendes belaufen: "Das ist langsam. Wie beschleunige ich das?" Oder in Tutorials heißt es: "Mach das so und nicht so, weil es schneller ist".

Mir scheint, ein großer Teil von SQL weiß, wie ein Ausdruck ausgeführt wird, und wählt aus diesem Wissen die Ausdrucksstile, die eine bessere Leistung erbringen. Dies steht nicht im Einklang mit einem Aspekt der deklarativen Programmierung - dem Verlassen des Systems, um zu entscheiden, wie die Berechnung am besten durchgeführt werden soll, wobei Sie lediglich angeben, was die Berechnung ergeben soll.

Sollte sich eine SQL-Engine nicht darum kümmern, ob Sie sie verwendet haben in, existsoder joinob sie wirklich deklarativ ist, sollte sie Ihnen nicht einfach die richtige Antwort in angemessener Zeit geben, wenn dies mit einer der drei Methoden möglich ist? Dieses letzte Beispiel wird durch diesen kürzlich veröffentlichten Beitrag veranlasst, der von dem Typ ist, der in meinem einleitenden Absatz erwähnt wurde.

Indizes

Ich denke, das einfachste Beispiel, das ich hätte verwenden können, bezieht sich auf das Erstellen eines Index für eine Tabelle. Das Gumph hier auf w3schools.com versucht sogar, es als etwas zu erklären, das der Benutzer aus Leistungsgründen nicht sieht. Ihre Beschreibung scheint SQL-Indizes in das nicht deklarative Lager zu stellen, und sie werden aus reinen Leistungsgründen routinemäßig von Hand hinzugefügt.

Ist es der Fall, dass es irgendwo eine ideale SQL-Datenbank gibt, die aussagekräftiger ist als alle anderen, aber weil es so gut ist, hört man nicht davon?

Paddy3118
quelle
@FrustratedWithFormsDesigner: Ich weiß genau, was das bedeutet. select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param). Es sollte trivial sein zu sehen, wie man das mit a existsoder a wiedergibt join.
Mason Wheeler
Ich schätze, dass reguläre Ausdrücke eine aussagekräftigere Ausdrucksmethode sind, wenn man ähnliche Argumente verwendet, da ich selten Leistungsfragen sehe, die mit "Sie sollten es so schreiben, um eine bessere Leistung zu erzielen" beantwortet werden. Ich zerbreche mir den Kopf und kann mich zur Hälfte an eine Frage erinnern, die mit negativen Look-behind- oder Ahead-Behauptungen in einem langsamen regulären Ausdruck zu tun hat, bei der die Antwort darin bestand, den regulären Ausdruck auf eine andere Weise umzuschreiben, um dasselbe in kürzerer Zeit zu tun.
Paddy3118
Leistung ist ein Implementierungsdetail. Die Leistung nahezu jeder IN-Implementierung könnte vergleichbar oder besser sein als bei EXISTS und JOIN, wenn die Entwickler des Abfrageprozessors dies für vorrangig hielten.
JustinC
1
@JustinC, es scheint mehr als nur ein Detail zu sein, da es überwiegend leistungsorientierte SQL-Fragen und -Tipps für eine angeblich deklarative Sprache gibt.
Paddy3118
Es gibt keine klare Definition einer deklarativen Programmiersprache, und daher ist es sinnlos, darüber zu sprechen. Einige Sprachen sind höher als andere, das ist alles.
Gardenhead

Antworten:

21

SQL ist theoretisch deklarativ. Aber Sie wissen, was sie über den Unterschied zwischen Theorie und Praxis sagen ...

Im Kern war das Konzept der "deklarativen Programmierung" nie wirklich effektiv und wird es wahrscheinlich auch nie tun, bis wir einen AI-basierten Compiler haben, der in der Lage ist, Code zu betrachten und die Frage "Was ist die Absicht dieses Codes?" Zu beantworten. intelligent, auf die gleiche Weise wie die Person, die es geschrieben hat. Das Herzstück jeder deklarativen Sprache ist eine ganze Reihe von imperativem Code, der verzweifelt versucht, dieses Problem ohne die Hilfe einer KI zu lösen.

Oft funktioniert es überraschend gut, da es sich bei den häufigsten Fällen um häufige Fälle handelt , von denen die Leute, die die Implementierung der Sprache geschrieben haben, wussten und gute Möglichkeiten fanden, damit umzugehen. Aber dann stoßen Sie auf einen Randfall, den der Implementierer nicht berücksichtigt hat, und Sie sehen, dass sich die Leistung schnell verschlechtert, da der Interpreter gezwungen ist, den Code viel wörtlicher zu nehmen und weniger effizient damit umzugehen.

Mason Wheeler
quelle
3
Nie wirklich effektiv? SQL, LINQ, Knockout.js, Prolog, ELM-Sprache. Vielleicht möchten Sie es noch einmal überprüfen. Im Moment verwende ich hauptsächlich deklarative Technologien.
Brian
5
@brian: Und alle degenerieren ziemlich schnell, wenn Sie auf einen Randfall stoßen, an den niemand gedacht hat. Ich hätte wohl sagen sollen: "Niemals wirklich effektiv im allgemeinen Fall ."
Mason Wheeler
Wann wird Ihre Antwort beeinträchtigt, da sie in einer SQL Server-Datenbank gespeichert ist? :) Ich habe selten einen Randfall in einem von ihnen getroffen, der im Rahmen nicht gelöst werden konnte. Ich sehe, woher Sie kommen, aber die Randfälle bereiten mir kaum Schmerzen, da 99% des deklarativen Codes nützlich und leicht zu beurteilen sind. Es ist, als ob man sagt, dass Clojure oder F # schlecht sind, weil man einen veränderlichen Typ verwenden musste, um das Problem zu lösen.
Brian
11
@brian: I rarely hit an edge case in any of them that couldn't be solved within the framework.Ja, das ist der springende Punkt: Sie müssen einen Weg finden, um sie innerhalb des Frameworks zu lösen, da das Framework nicht intelligent genug ist, um es für Sie so zu lösen, wie Sie es ursprünglich deklariert haben.
Mason Wheeler
Was ist mit select ... for update? Es scheint ein zwingender Befehl zu sein.
Jesvin Jose
6

Ich habe vor einigen Tagen nach einer SQL-Optimierung darüber nachgedacht. Ich denke, wir können uns darauf einigen, dass SQL eine "deklarative Sprache" in der Definition von Wikipedia ist:

Programmierparadigma, das die Logik der Berechnung ausdrückt, ohne den Steuerungsfluss zu beschreiben

Wenn Sie sich vorstellen, wie viele Dinge hinter den Kulissen erledigt werden (Betrachten von Statistiken, Entscheiden, ob ein Index nützlich ist, Suchen nach einem verschachtelten, zusammengeführten oder Hash-Join usw.), müssen Sie zugeben, dass wir nur ein hohes Niveau angeben Logik, und die Datenbank kümmerte sich um alle Low-Level-Kontrollflusslogik.

Auch in diesem Szenario benötigt der Datenbankoptimierer manchmal einige "Hinweise" vom Benutzer, um die besten Ergebnisse zu erzielen.

Eine andere gebräuchliche Definition von "deklarativer" Sprache ist (ich kann keine autorisierende Quelle finden):

Programmierparadigma, das das gewünschte Ergebnis der Berechnung ausdrückt, ohne die Schritte zu beschreiben, um es zu erreichen (auch mit "beschreiben, was, nicht wie" abgekürzt)

Wenn wir diese Definition akzeptieren, stoßen wir auf die vom OP beschriebenen Probleme.

Das erste Problem ist, dass SQL uns mehrere gleichwertige Möglichkeiten bietet, "dasselbe Ergebnis" zu definieren. Wahrscheinlich ist das ein notwendiges Übel: Je mehr Ausdruckskraft wir einer Sprache verleihen, desto wahrscheinlicher ist es, dass es verschiedene Möglichkeiten gibt, dasselbe auszudrücken.

Als Beispiel wurde ich einmal gebeten, diese Abfrage zu optimieren:

 SELECT Distinct CT.cust_type,  ct.cust_type_description 
   from customer c 
              INNER JOIN 
              Customer_type CT on c.cust_type=ct.cust_type;

Da die Typen viel kleiner waren als die des Kunden und ein Index auf dem cust_typeKundentisch vorhanden war, habe ich eine große Verbesserung erzielt, indem ich ihn folgendermaßen umgeschrieben habe:

 SELECT CT.cust_type,  ct.cust_type_description 
   from Customer_type CT
  Where exists ( select 1 from customer c 
                  Where c.cust_type=ct.cust_type);

In diesem speziellen Fall, als ich den Entwickler fragte, was er erreichen wolle, sagte er mir: "Ich wollte alle Kundentypen, für die ich mindestens einen Kunden hatte", das ist übrigens genau die Beschreibung der Optimierungsabfrage.

Wenn ich also eine gleichwertige und effizientere Abfrage finden könnte, warum kann das Optimierungsprogramm nicht dasselbe tun?

Ich vermute, dass es zwei Hauptgründe gibt:

SQL drückt Logik aus:

Da SQL eine übergeordnete Logik ausdrückt, möchten wir wirklich, dass der Optimierer uns und unsere Logik überlistet? Ich würde begeistert "Ja" rufen, wenn ich nicht immer den Optimierer zwingen müsste, den effizientesten Ausführungspfad auszuwählen. Ich denke, die Idee könnte sein, dem Optimierer zu erlauben, sein Bestes zu geben (und auch unsere Logik zu überarbeiten), uns aber einen "Hinweismechanismus" zu geben, um zu retten, wenn etwas verrückt wird (es wäre, als hätte man das Rad + Bremsen ein autonomes Auto).

Mehr Auswahl = mehr Zeit

Selbst der beste RDBMS-Optimierer testet nicht ALLE möglichen Ausführungspfade, da sie sehr schnell sein müssen: Wie gut wäre es, eine Abfrage von 100 ms auf 10 ms zu optimieren, wenn ich jedes Mal 100 ms für die Auswahl des besten Pfads aufwenden müsste? Und das mit dem Optimierer, der unsere "High-Level-Logik" respektiert. Wenn auch alle entsprechenden SQL-Abfragen getestet werden sollen, kann die Optimierungszeit um ein Vielfaches anwachsen.

Ein weiteres gutes Beispiel für das Umschreiben von Abfragen, zu dem kein RDBMS in der Lage ist, ist (aus diesem interessanten Blog-Beitrag ).

SELECT t1.id, t1.value, SUM(t2.value)
  FROM mytable t1
       JOIN mytable t2
         ON t2.id <= t1.id
 GROUP BY t1.id, t1.value;

als kann so geschrieben werden (analytische Funktionen erforderlich)

 SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
   FROM mytable
Insac
quelle
1
Das Beispiel des Umschreibens des Joins in eine vorhandene ist interessant. Eine Faustregel, die ich SQL-Entwicklern aufzwinge, ist, dass die Verwendung von DISTINCT ein Codegeruch ist - entweder die Abfrage oder das Datenmodell ist möglicherweise falsch, und es sollte nach einem anderen Ansatz gesucht werden.
David Aldridge