Ich weiß, dass gespeicherte Prozeduren über den Ausführungspfad effizienter sind (als die Inline-SQL in Anwendungen). Wenn ich gedrückt werde, weiß ich nicht genau, warum.
Ich würde gerne die technischen Gründe dafür erfahren (so, dass ich es später jemandem erklären kann).
Kann mir jemand helfen, eine gute Antwort zu formulieren?
Antworten:
Ich glaube, dass dieses Gefühl zu einem bestimmten Zeitpunkt wahr war, aber nicht in aktuellen Versionen von SQL Server. Das ganze Problem war, dass in früheren Zeiten Ad-hoc-SQL-Anweisungen nicht richtig optimiert werden konnten, da SQL Server nur auf Stapelebene optimieren / kompilieren konnte. Jetzt haben wir eine Optimierung auf Anweisungsebene, sodass eine ordnungsgemäß parametrisierte Abfrage, die von einer Anwendung stammt, denselben Ausführungsplan wie die in eine gespeicherte Prozedur eingebettete Abfrage verwenden kann.
Ich bevorzuge gespeicherte Prozeduren von der DBA-Seite aus den folgenden Gründen (und einige von ihnen können einen großen Einfluss auf die Leistung haben):
sys.sql_modules
für Verweise auf bestimmte Objekte zu verwenden), erleichtert das Leben aller erheblich.SET ANSI_WARNINGS ON
kann und eine andere vorhanden seinSET ANSI_WARNINGS OFF
kann und jede eine eigene Kopie des Plans hat. Der Plan, den sie erhalten, hängt von den verwendeten Parametern, den vorhandenen Statistiken usw. ab, wenn die Abfrage zum ersten Mal aufgerufen wird. Dies kann zu unterschiedlichen Plänen und damit zu einer sehr unterschiedlichen Leistung führen.Trotzdem wird diese Frage wahrscheinlich mehr religiöse Argumente hervorrufen als technische Auseinandersetzungen. Wenn wir das sehen, werden wir es wahrscheinlich herunterfahren.
quelle
Obwohl ich den Einsender respektiere, bin ich mit der gegebenen Antwort demütig nicht einverstanden und nicht aus "religiösen Gründen". Mit anderen Worten, ich glaube, es gibt keine Möglichkeit, die Microsoft zur Verfügung gestellt hat, die den Bedarf an Anleitungen zur Verwendung gespeicherter Prozeduren verringert.
Jede Anleitung, die einem Entwickler zur Verfügung gestellt wird, der die Verwendung von SQL-Abfragen mit Rohtext bevorzugt, muss mit zahlreichen Einschränkungen versehen sein. Ich halte es daher für den klügsten Rat, die Verwendung gespeicherter Prozeduren zu fördern und Ihre Entwicklerteams davon abzuhalten, sich an der Praxis zu beteiligen Einbetten von SQL-Anweisungen in Code oder Senden von unformatierten, textbasierten SQL-Anforderungen außerhalb von SQL-SPROCs (gespeicherten Prozeduren).
Ich denke, die einfache Antwort auf die Frage, warum ein SPROC verwendet wird, lautet, wie der Absender vermutet: SPROCs werden analysiert, optimiert und kompiliert. Daher werden ihre Abfrage- / Ausführungspläne zwischengespeichert, da Sie eine statische Darstellung einer Abfrage gespeichert haben und diese normalerweise nur um Parameter variieren. Dies gilt nicht für kopierte / eingefügte SQL-Anweisungen, die sich wahrscheinlich ändern von Seite zu Seite und von Komponente / Schicht und sind oft so variabel, dass von Aufruf zu Aufruf verschiedene Tabellen, sogar Datenbanknamen, angegeben werden können. Unter Berücksichtigung dieser Art von dynamischem Ad-hocDurch die SQL-Übermittlung wird die Wahrscheinlichkeit, dass das DB-Modul den Abfrageplan für Ihre Ad-hoc-Anweisungen nach sehr strengen Regeln wiederverwendet, erheblich verringert. Hier unterscheide ich zwischen dynamischen Ad-hoc-Abfragen (im Sinne der aufgeworfenen Frage) und der Verwendung des effizienten Systems SPROC sp_executesql.
Insbesondere gibt es die folgenden Komponenten:
Wenn eine SQL-Anweisung von einer Webseite ausgegeben wird, die als "Ad-hoc-Anweisung" bezeichnet wird, sucht das Modul nach einem vorhandenen Ausführungsplan, um die Anforderung zu verarbeiten. Da es sich um von einem Benutzer gesendeten Text handelt, wird dieser aufgenommen, analysiert, kompiliert und ausgeführt, sofern er gültig ist. Zu diesem Zeitpunkt wird es eine Abfrage von Null erhalten. Abfragekosten werden verwendet, wenn das DB-Modul seinen Algorithmus verwendet, um zu bestimmen, welche Ausführungspläne aus dem Cache entfernt werden sollen.
Ad-hoc-Abfragen erhalten standardmäßig einen ursprünglichen Abfragekostenwert von Null. Bei der anschließenden Ausführung des exakt gleichen Ad-hoc-Abfragetexts durch einen anderen Benutzerprozess (oder denselben) werden die aktuellen Abfragekosten auf die ursprünglichen Kompilierungskosten zurückgesetzt. Da die Kosten für die Kompilierung von Ad-hoc-Abfragen gleich Null sind, ist die Möglichkeit der Wiederverwendung nicht gut. Natürlich ist Null die am wenigsten wertvolle Ganzzahl, aber warum sollte sie entfernt werden?
Wenn Speicherprobleme auftreten und wenn Sie eine häufig verwendete Site haben, verwendet das DB-Modul einen Bereinigungsalgorithmus, um zu ermitteln, wie es den vom Prozedurcache verwendeten Speicher wiederherstellen kann. Es verwendet die aktuellen Abfragekosten, um zu entscheiden, welche Pläne entfernt werden sollen. Wie Sie sich vorstellen können, werden Pläne mit einem Preis von Null als erstes aus dem Cache entfernt, da Null im Wesentlichen "keine aktuellen Benutzer dieses Plans oder Verweise auf diesen Plan" bedeutet.
Daher ist es sehr wahrscheinlich, dass ein solcher Plan zuerst geräumt wird, wenn Speicherdruck entsteht.
Wenn Sie also einen Server mit viel Arbeitsspeicher haben, der "über Ihre Anforderungen hinaus" geht, tritt dieses Problem möglicherweise nicht so häufig auf wie bei einem ausgelasteten Server, der nur "genügend" Arbeitsspeicher hat, um seine Arbeitslast zu bewältigen. (Die Speicherkapazität und Auslastung des Servers ist leider etwas subjektiv / relativ, der Algorithmus jedoch nicht.)
Wenn ich in Bezug auf einen oder mehrere Punkte sachlich falsch liege, bin ich auf jeden Fall bereit, korrigiert zu werden.
Zuletzt schrieb der Autor:
"Jetzt haben wir eine Optimierung auf Anweisungsebene, sodass eine ordnungsgemäß parametrisierte Abfrage, die von einer Anwendung stammt, denselben Ausführungsplan wie die in eine gespeicherte Prozedur eingebettete Abfrage verwenden kann."
Ich glaube, der Autor bezieht sich auf die Option "Für Ad-hoc-Workloads optimieren".
In diesem Fall ist mit dieser Option ein zweistufiger Prozess möglich, bei dem nicht sofort der vollständige Abfrageplan an den Prozedurcache gesendet wird. Es wird dort nur ein kleinerer Abfragestub gesendet. Wenn ein genauer Abfrageaufruf zurück an den Server gesendet wird, während sich der Abfragestub noch im Prozedurcache befindet, wird zu diesem Zeitpunkt der vollständige Abfrageausführungsplan im Prozedurcache gespeichert. Dies spart Speicher, der es dem Auslagerungsalgorithmus bei Speicherdruckereignissen möglicherweise ermöglicht, den Stub seltener auszuräumen als bei einem größeren Abfrageplan, der zwischengespeichert wurde. Dies hängt wiederum vom Arbeitsspeicher und der Auslastung Ihres Servers ab.
Sie müssen diese Option jedoch aktivieren, da sie standardmäßig deaktiviert ist.
Abschließend möchte ich betonen, dass Entwickler SQL häufig nur deshalb in Seiten, Komponenten und andere Bereiche einbetten, weil sie flexibel sein und dynamische SQL-Abfragen an das Datenbankmodul senden möchten. In einem realen Anwendungsfall ist es daher unwahrscheinlich, dass derselbe Text, Call-over-Call, übermittelt wird, wie auch die von uns angestrebten Zwischenspeicherungs- / Effizienzvorteile, wenn Ad-hoc-Abfragen an SQL Server gesendet werden.
Weitere Informationen finden Sie unter:
https://technet.microsoft.com/en-us/library/ms181055(v=sql.105).aspx
http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql
Am besten
Henry
quelle
TLDR: Es gibt keinen nennenswerten Leistungsunterschied zwischen den beiden, solange Ihre Inline-SQL parametrisiert ist.
Dies ist der Grund, warum ich gespeicherte Prozeduren langsam auslaufe:
Wir betreiben eine Beta-Anwendungsumgebung - eine Umgebung parallel zur Produktion, in der die Produktionsdatenbank gemeinsam genutzt wird. Da sich DB-Code auf Anwendungsebene befindet und Änderungen an der DB-Struktur nur selten vorkommen, können Mitarbeiter neue Funktionen über die Qualitätssicherung hinaus bestätigen und Bereitstellungen außerhalb des Produktionsbereitstellungsfensters ausführen, jedoch weiterhin Produktionsfunktionen und nicht kritische Korrekturen bereitstellen. Dies wäre nicht möglich, wenn sich die Hälfte des Anwendungscodes in der DB befände.
Wir üben Devops auf Datenbankebene (Octopus + Dacpacs). Während Business Layer und höher im Grunde genommen gelöscht und ersetzt werden können und die Wiederherstellung genau umgekehrt, gilt dies nicht für die inkrementellen und potenziell destruktiven Änderungen, die an den Datenbanken vorgenommen werden müssen. Aus diesem Grund ziehen wir es vor, unsere DB-Bereitstellungen leichter und seltener durchzuführen.
Um nahezu exakte Kopien desselben Codes für optionale Parameter zu vermeiden, verwenden wir häufig das Muster 'where @var is null oder @ var = table.field'. Mit einem gespeicherten Prozess erhalten Sie wahrscheinlich trotz unterschiedlicher Absichten den gleichen Ausführungsplan. Auf diese Weise treten entweder Leistungsprobleme auf oder es werden zwischengespeicherte Pläne mit Hinweisen zum erneuten Kompilieren entfernt. Mit einem einfachen Code, der einen "Signatur" -Kommentar an das Ende des SQL anfügt, können wir jedoch verschiedene Pläne erzwingen, basierend darauf, welche Variablen null waren (nicht als anderer Plan für alle Variablenkombinationen zu interpretieren - nur null vs nicht null).
Ich kann dramatische Änderungen an den Ergebnissen vornehmen, mit nur geringfügigen Änderungen im laufenden Betrieb an der SQL. Zum Beispiel kann ich eine Anweisung haben, die mit zwei CTEs, "Raw" und "ReportReady", abgeschlossen wird. Es gibt nichts, was besagt, dass beide CTEs verwendet werden müssen. Meine SQL-Anweisung kann dann sein:
...
wähle * aus {(Format)} "
Auf diese Weise kann ich für einen optimierten API-Aufruf und einen Bericht, der detaillierter sein muss, genau dieselbe Geschäftslogikmethode verwenden, um sicherzustellen, dass keine komplizierte Logik dupliziert wird.
Es gibt triftige Gründe, procs zu verwenden:
Sicherheit - Sie haben hier eine weitere Ebene, die die App durchlaufen muss. Wenn das Anwendungsdienstkonto keine Tabellen berühren darf, sondern nur die Berechtigung zum Ausführen von Prozessen hat, haben Sie zusätzlichen Schutz. Das ist nicht selbstverständlich, da es Kosten verursacht, aber es ist eine Möglichkeit.
Wiederverwendung - Während ich sagen würde, dass die Wiederverwendung größtenteils auf Unternehmensebene erfolgen sollte, um sicherzustellen, dass Sie nicht mit der Datenbank zusammenhängende Geschäftsregeln umgehen, gibt es immer noch den gelegentlichen, einfachen Typ von Utility-Prozessen und -Funktionen, die "überall" verwendet werden.
Es gibt einige Argumente, die Procs nicht wirklich unterstützen oder die IMO einfach zu mildern sind:
Wiederverwendung - Ich erwähnte dies oben als "Plus", wollte aber auch hier erwähnen, dass die Wiederverwendung größtenteils auf Unternehmensebene erfolgen sollte. Ein Vorgang zum Einfügen eines Datensatzes sollte nicht als "wiederverwendbar" betrachtet werden, wenn die Business-Schicht möglicherweise auch andere Nicht-DB-Services überprüft.
Cache-Plan aufgebläht - dies ist nur dann ein Problem, wenn Sie Werte verketten und nicht parametrisieren. Die Tatsache, dass Sie selten mehr als einen Plan pro Proc erhalten, schmerzt Sie tatsächlich oft, wenn Sie ein 'oder' in einer Abfrage haben
Anweisungsgröße - Ein zusätzliches KByte an SQL-Anweisungen über dem Prozessnamen ist im Vergleich zu den zurückkommenden Daten normalerweise vernachlässigbar. Wenn es für Entities in Ordnung ist, ist es für mich in Ordnung.
Anzeigen der genauen Abfrage - Um das Auffinden von Abfragen im Code zu vereinfachen, müssen Sie lediglich den aufrufenden Speicherort als Kommentar zum Code hinzufügen. Das Kopieren von Code von c # -Code in ssms ist so einfach wie die kreative Interpolation und Verwendung von Kommentaren:
SQL Injection - Parametrisieren Sie Ihre Abfragen. Getan. Dies kann tatsächlich rückgängig gemacht werden, wenn der Prozess stattdessen dynamisches SQL verwendet.
Bereitstellung umgehen - Wir üben Devops auch auf Datenbankebene aus, daher ist dies für uns keine Option.
"Langsam in der Anwendung, schnell in SSMS" - Dies ist ein Plan-Caching-Problem, das beide Seiten betrifft. Die gesetzten Optionen bewirken lediglich die Kompilierung eines neuen Plans, der das Problem für THE ONE SET OFF-Variablen zu beheben scheint. Dies beantwortet nur, warum Sie unterschiedliche Ergebnisse sehen - die eingestellten Optionen selbst beheben NICHT das Problem des Parameter-Schnüffelns.
Inline-SQL-Ausführungspläne werden nicht zwischengespeichert - einfach falsch. Eine parametrisierte Anweisung wird ebenso wie der Proc-Name schnell gehasht, und dann wird ein Plan von diesem Hash gesucht. Es ist zu 100% dasselbe.
Um klar zu sein, ich spreche von rohem Inline-SQL-Code, der nicht aus einem ORM generiert wurde. Wir verwenden nur Dapper, das bestenfalls ein Mikro-ORM ist.
https://weblogs.asp.net/fbouma/38178
https://stackoverflow.com/a/15277/852208
quelle