Bestes Muster für Konstanten in SQL?

8

Ich habe mehrere Muster gesehen, die verwendet wurden, um den Mangel an Konstanten in SQL Server zu "überwinden", aber keiner von ihnen scheint sowohl die Leistung als auch die Lesbarkeits- / Wartbarkeitsprobleme zu erfüllen.

Im folgenden Beispiel, unter der Annahme, dass wir eine integrale "Status" -Klassifikation in unserer Tabelle haben, scheinen die Optionen zu sein:

  • Nur um es hart zu kodieren und vielleicht nur den Status
  • zu kommentieren

%Vor%
  • Verwenden einer Nachschlagetabelle für Status und anschließendes Verbinden mit dieser Tabelle, sodass die WHERE -Klausel auf den angezeigten Namen verweist.

Unterabfrage:

%Vor%

oder verbunden

%Vor%
  • Eine Menge skalarer UDFs definiert die Rückkehrkonstanten, nämlich

%Vor%

und dann

%Vor%

(IMO das verursacht eine Menge Verschmutzung in der Datenbank - das könnte in einem Oracle Packet Wrapper OK sein)

  • Und ähnliche Muster mit Table Valued Functions, die die Konstanten mit Werten als Zeilen oder Spalten enthalten, die CROSS APPLIED zurück zu [Table] sind

Wie haben andere SO-Benutzer dieses häufige Problem gelöst?

Bearbeiten : Bounty - Hat jemand eine Best Practice-Methode zum Verwalten von $ (Variablen) in DBProj-DDL / Schemaskripten gemäß Remus-Antwort und -Kommentar?

    
StuartLC 30.07.2010, 10:48
quelle

4 Antworten

11

Fest codiert. Mit SQL-Leistung wird die Wartbarkeit übertroffen.

Die Konsequenzen im Ausführungsplan zwischen der Verwendung einer Konstanten, die das Optimierungsprogramm zur Plangenerierungszeit überprüfen kann, und der Verwendung einer beliebigen Form von Indirektion (UDF, JOIN, Unterabfrage) sind oft dramatisch. SQL 'Compilation' ist ein außergewöhnlicher Prozess (in dem Sinne, dass es nicht 'gewöhnlich' ist wie zB IL-Code-Generierung), da das Ergebnis nicht nur durch das zu kompilierende Sprachkonstrukt (dh den eigentlichen Text der Anfrage) bestimmt wird durch das Datenschema (vorhandene Indizes) und tatsächliche Daten in diesen Indizes (Statistiken). Wenn ein fest codierter Wert verwendet wird, kann der Optimierer einen besseren Plan erstellen, da er den Wert anhand der Indexstatistik überprüfen und eine Schätzung des Ergebnisses erhalten kann.

Eine weitere Überlegung ist, dass eine SQL-Anwendung nicht nur Code ist, sondern mit großem Abstand Code und Daten. 'Refactoring' ein SQL-Programm ist ... anders. In einem C # -Programm kann man eine Konstante oder eine Enumeration ändern, die Anwendung neu kompilieren und ausführen, in SQL kann man das nicht tun, weil der Wert wahrscheinlich in Millionen von Datensätzen in der Datenbank vorhanden ist und die Änderung des Konstantenwertes auch GBs von Daten ändert , oft online , während neue Operationen stattfinden.

Nur weil der Wert in den vom Server gesehenen Abfragen und Prozeduren fest codiert ist, bedeutet dies nicht unbedingt, dass der Wert im ursprünglichen Projektquellcode fest codiert sein muss. Es gibt verschiedene Tools zur Code-Generierung, die dafür sorgen können. Betrachten Sie etwas so Triviales wie die Verwendung der Skriptvariablen von sqlcmd :

defines.sql :

%Vor%

somesource.sql :

%Vor%

someothersource.sql :

%Vor%     
Remus Rusanu 30.07.2010, 12:20
quelle
6

Obwohl ich mit Remus Rusanu, IMO, übereinstimme, übertrumpfen die Wartbarkeit des Codes (und damit Lesbarkeit, geringstes Erstaunen usw.) andere Bedenken, es sei denn, der Leistungsunterschied ist ausreichend signifikant, um dies anders zu rechtfertigen. Daher verliert die folgende Abfrage an Lesbarkeit:

%Vor%

Wenn ich systemabhängige Werte habe, die im Code referenziert werden (vielleicht in einer Enumeration mit Namen imitiert), verwende ich im Allgemeinen String-Primärschlüssel für die Tabellen, in denen sie gehalten werden. Vergleichen Sie dies mit benutzerwechselnden Daten, in denen ich normalerweise Ersatzschlüssel verwende. Die Verwendung eines Primärschlüssels, der einen Eintrag erfordert, hilft (wenn auch nicht perfekt) anderen Entwicklern anzuzeigen, dass dieser Wert nicht willkürlich sein soll.

Somit würde meine "Status" -Tabelle wie folgt aussehen:

%Vor%

Dies macht die Abfrage lesbarer, erfordert keine Verbindung zur Statustabelle und erfordert keine magische Zahl (oder Guid). Mit benutzerdefinierten Funktionen ist IMO eine schlechte Übung. Über die Performance-Implikationen hinaus würde kein Entwickler jemals erwarten, dass UDFs auf diese Weise verwendet werden, und somit die geringsten Verwunderungskriterien verletzen. Sie wären fast gezwungen, eine UDF für jeden konstanten Wert zu haben; sonst, was du in die Funktion übergibst: ein Name? ein magischer Wert? Wenn Sie einen Namen haben, behalten Sie den Namen in einer Tabelle und verwenden ihn direkt in der Abfrage. Wenn ein magischer Wert, bist du das ursprüngliche Problem zurück.

    
Thomas 06.08.2010 16:36
quelle
3

Ich habe die Skalarfunktion in unserer Datenbank verwendet und es funktioniert gut und meiner Ansicht nach ist dies der beste Weg für diese Lösung.

Wenn mehr Werte mit einem Element verglichen werden, dann wird ein Lookup durchgeführt, wie wenn Sie eine Combobox oder ein anderes Steuerelement mit einem statischen Wert laden. Verwenden Sie dann Lookup, um dies zu erreichen.

    
KuldipMCA 30.07.2010 11:19
quelle
2

Sie können Ihrer Statustabelle auch weitere Felder hinzufügen, die als eindeutige Markierungen oder Gruppierer für Statuswerte fungieren. Wenn Sie beispielsweise Ihrer Statustabelle ein isLoaded-Feld hinzufügen, kann der Datensatz 87 der einzige sein, für den der Wert des Felds festgelegt ist, und Sie können anstelle der hartcodierten 87 oder der Statusbeschreibung den Wert des Feldes isLoaded überprüfen / p>     

Beth 05.08.2010 17:42
quelle