Alle von uns, die mit relationalen Datenbanken arbeiten, haben gelernt (oder lernen), dass SQL anders ist. Um die gewünschten Ergebnisse zu erzielen und dies effizient zu tun, ist ein langwieriger Prozess erforderlich, der teilweise durch das Erlernen unbekannter Paradigmen gekennzeichnet ist und herausfindet, dass einige unserer bekanntesten Programmiermuster hier nicht funktionieren. Was sind die häufigsten Antimuster, die Sie gesehen haben (oder die Sie selbst begangen haben)?
sql
anti-patterns
le dorfier
quelle
quelle
Antworten:
Ich bin immer wieder enttäuscht von der Tendenz der meisten Programmierer, ihre UI-Logik in der Datenzugriffsschicht zu mischen:
Normalerweise tun dies Programmierer, weil sie beabsichtigen, ihr Dataset direkt an ein Raster zu binden, und es ist einfach praktisch, das SQL Server-Format serverseitig als das Format auf dem Client zu haben.
Abfragen wie die oben gezeigte sind extrem spröde, da sie die Datenschicht eng mit der UI-Schicht koppeln. Darüber hinaus verhindert diese Art der Programmierung gründlich, dass gespeicherte Prozeduren wiederverwendbar sind.
quelle
Hier sind meine Top 3.
Nummer 1. Keine Angabe einer Feldliste. (Bearbeiten: Um Verwirrung zu vermeiden: Dies ist eine Produktionscode-Regel. Sie gilt nicht für einmalige Analyseskripte - es sei denn, ich bin der Autor.)
sollte sein
Nummer 2. Verwenden eines Cursors und einer while-Schleife, wenn eine while-Schleife mit einer Schleifenvariablen ausreicht.
Nummer 3. DateLogic durch Zeichenfolgentypen.
Sollte sein
Ich habe kürzlich einen Anstieg von "Eine Abfrage ist besser als zwei, oder?" Gesehen.
Diese Abfrage erfordert zwei oder drei verschiedene Ausführungspläne, abhängig von den Werten der Parameter. Für diesen SQL-Text wird nur ein Ausführungsplan generiert und im Cache gespeichert. Dieser Plan wird unabhängig vom Wert der Parameter verwendet. Dies führt zu einer zeitweise schlechten Leistung. Es ist viel besser, zwei Abfragen zu schreiben (eine Abfrage pro beabsichtigtem Ausführungsplan).
quelle
Vom Menschen lesbare Passwortfelder , z. Selbsterklärend.
Verwenden von LIKE für indizierte Spalten, und ich bin fast versucht, nur LIKE im Allgemeinen zu sagen.
Recycling von SQL-generierten PK-Werten.
Überraschung, dass noch niemand den Gott-Tisch erwähnt hat. Nichts sagt "organisch" wie 100 Spalten mit Bitflags, großen Strings und ganzen Zahlen.
Dann gibt es das Muster "Ich vermisse INI-Dateien" : Speichern von CSVs, durch Pipe getrennten Zeichenfolgen oder anderen analysierten erforderlichen Daten in großen Textfeldern.
Und für MS SQL Server die Verwendung von Cursorn überhaupt . Es gibt eine bessere Möglichkeit, eine bestimmte Cursoraufgabe auszuführen.
Bearbeitet, weil es so viele gibt!
quelle
LIKE '%LIKE'
.Sie müssen nicht tief graben: Verwenden Sie keine vorbereiteten Anweisungen.
quelle
Verwenden bedeutungsloser Tabellen-Aliase:
Das Lesen einer großen SQL-Anweisung wird so viel schwieriger als nötig
quelle
quelle
Meine Bugbears sind die 450-Spalten-Zugriffstabellen, die vom 8-jährigen Sohn des Hundefreundes des besten Freundes des Geschäftsführers zusammengestellt wurden, und die zwielichtige Nachschlagetabelle, die nur existiert, weil jemand nicht weiß, wie man eine Datenstruktur richtig normalisiert.
In der Regel sieht diese Nachschlagetabelle folgendermaßen aus:
Ich habe die Anzahl der Kunden verloren, die Systeme gesehen haben, die auf solchen Greueln beruhen.
quelle
Diejenigen, die ich am wenigsten mag, sind
Verwenden von Leerzeichen beim Erstellen von Tabellen, Sprocs usw. Ich bin mit CamelCase oder under_scores und Singular oder Plural und Großbuchstaben oder Kleinbuchstaben einverstanden, muss mich aber auf eine Tabelle oder Spalte [mit Leerzeichen] beziehen, insbesondere wenn [sie einen merkwürdigen Abstand hat] (ja, Ich bin darauf gestoßen) irritiert mich wirklich.
Denormalisierte Daten. Eine Tabelle muss nicht perfekt normalisiert sein, aber wenn ich auf eine Tabelle mit Mitarbeitern stoße, die Informationen über ihre aktuelle Bewertungspunktzahl oder ihre primären Daten enthält, muss ich wahrscheinlich irgendwann eine separate Tabelle erstellen Versuchen Sie dann, sie synchron zu halten. Ich werde zuerst die Daten normalisieren und dann, wenn ich einen Ort sehe, an dem die Denormalisierung hilft, werde ich darüber nachdenken.
Überbeanspruchung von Ansichten oder Cursorn. Ansichten haben einen Zweck, aber wenn jede Tabelle in eine Ansicht eingeschlossen ist, ist es zu viel. Ich musste einige Male Cursor verwenden, aber im Allgemeinen können Sie dafür andere Mechanismen verwenden.
Zugriff. Kann ein Programm ein Anti-Pattern sein? Wir haben SQL Server in meiner Arbeit, aber eine Reihe von Personen verwenden den Zugriff aufgrund seiner Verfügbarkeit, "Benutzerfreundlichkeit" und "Freundlichkeit" für nicht technische Benutzer. Es gibt hier zu viel, um darauf einzugehen, aber wenn Sie in einer ähnlichen Umgebung waren, wissen Sie.
quelle
Verwenden Sie SP als Präfix für den Namen der Speicherprozedur, da diese zuerst am Speicherort der Systemprozeduren und nicht an den benutzerdefinierten suchen.
quelle
Überbeanspruchung temporärer Tabellen und Cursor.
quelle
Zum Speichern von Zeitwerten sollte nur die UTC-Zeitzone verwendet werden. Ortszeit sollte nicht verwendet werden.
quelle
Verwenden von @@ IDENTITY anstelle von SCOPE_IDENTITY ()
Zitiert aus dieser Antwort :
quelle
Wiederverwendung eines "toten" Felds für etwas, für das es nicht vorgesehen war (z. B. Speichern von Benutzerdaten in einem "Fax" -Feld) - sehr verlockend als schnelle Lösung!
quelle
und unter der Annahme, dass das Ergebnis nach some_column sortiert wird. Ich habe dies ein bisschen bei Sybase gesehen, wo die Annahme (vorerst) gilt.
quelle
Oder alles in eine Zeile packen.
quelle
Die
FROM TableA, TableB WHERE
Syntax für JOINS anstattFROM TableA INNER JOIN TableB ON
Die Annahme, dass eine Abfrage zurückgegeben wird, wird auf eine bestimmte Weise sortiert, ohne dass eine ORDER BY-Klausel eingefügt wird, nur weil dies beim Testen im Abfragetool so angezeigt wurde.
quelle
In den ersten sechs Monaten ihrer Karriere SQL lernen und in den nächsten 10 Jahren nichts anderes lernen. Insbesondere nicht lernen oder Fensterfunktionen / analytische SQL-Funktionen effektiv nutzen. Insbesondere die Verwendung von over () und Partitionierung durch.
In O'Reilly SQL Cookbook Anhang A finden Sie eine schöne Übersicht über die Fensterfunktionen.
quelle
Ich muss hier meinen eigenen aktuellen Favoriten eintragen, um die Liste zu vervollständigen. Mein Lieblings-Antimuster testet Ihre Fragen nicht .
Dies gilt, wenn:
Und Tests, die gegen atypische oder unzureichende Daten durchgeführt werden, zählen nicht. Wenn es sich um eine gespeicherte Prozedur handelt, fügen Sie die Testanweisung in einen Kommentar ein und speichern Sie sie mit den Ergebnissen. Andernfalls fügen Sie es in einen Kommentar im Code mit den Ergebnissen ein.
quelle
Vorübergehender Tischmissbrauch.
Speziell so etwas:
Erstellen Sie keine temporäre Tabelle aus einer Abfrage, nur um die nicht benötigten Zeilen zu löschen.
Und ja, ich habe Codeseiten in dieser Form in Produktions-DBs gesehen.
quelle
Gegenteilige Ansicht: Überbesessenheit mit Normalisierung.
Die meisten SQL / RBDB-Systeme bieten eine Reihe von Funktionen (Transaktionen, Replikation), die selbst bei nicht normalisierten Daten sehr nützlich sind. Der Speicherplatz ist billig und manchmal kann es einfacher (einfacherer Code, schnellere Entwicklungszeit) sein, abgerufene Daten zu bearbeiten / filtern / durchsuchen, als ein 1NF-Schema zu schreiben und alle darin enthaltenen Probleme zu lösen (komplexe Verknüpfungen, unangenehme Unterauswahlen) , etc).
Ich habe festgestellt, dass die übernormalisierten Systeme häufig vorzeitig optimiert werden, insbesondere in frühen Entwicklungsphasen.
(Weitere Gedanken dazu ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )
quelle
Ich habe gerade diese zusammengestellt, basierend auf einigen der SQL-Antworten hier auf SO.
Es ist ein ernstes Gegenmuster zu glauben, dass Trigger für Datenbanken gelten, wie Event-Handler für OOP. Es gibt diese Wahrnehmung, dass nur jede alte Logik in Trigger gesetzt werden kann, um ausgelöst zu werden, wenn eine Transaktion (ein Ereignis) auf einem Tisch stattfindet.
Nicht wahr. Einer der großen Unterschiede besteht darin, dass Trigger synchron sind - mit aller Macht, weil sie bei einer festgelegten Operation und nicht bei einer Zeilenoperation synchron sind. Auf der OOP-Seite ist genau das Gegenteil der Fall - Ereignisse sind eine effiziente Möglichkeit, asynchrone Transaktionen zu implementieren.
quelle
Gespeicherte Prozeduren oder Funktionen ohne Kommentare ...
quelle
1) Ich weiß nicht, dass es sich um ein "offizielles" Anti-Pattern handelt, aber ich mag es nicht und versuche, String-Literale als magische Werte in einer Datenbankspalte zu vermeiden.
Ein Beispiel aus MediaWikis Tabelle 'image':
(Ich bemerke nur ein anderes Gehäuse, eine andere Sache, die man vermeiden sollte)
Ich entwerfe solche Fälle wie int-Lookups in Tabellen ImageMediaType und ImageMajorMime mit int-Primärschlüsseln.
2) Datums- / Zeichenfolgenkonvertierung, die auf bestimmten NLS-Einstellungen basiert
ohne Formatkennung
quelle
Identische Unterabfragen in einer Abfrage.
quelle
Die geänderte Ansicht - Eine Ansicht, die zu oft und ohne Vorankündigung oder Grund geändert wird. Die Änderung wird entweder zum unangemessensten Zeitpunkt bemerkt oder ist schlimmer noch falsch und wird nie bemerkt. Möglicherweise wird Ihre Anwendung unterbrochen, weil sich jemand einen besseren Namen für diese Spalte ausgedacht hat. In der Regel sollten Ansichten den Nutzen von Basistabellen erweitern und gleichzeitig einen Vertrag mit Verbrauchern aufrechterhalten. Beheben Sie Probleme, fügen Sie jedoch keine Funktionen hinzu oder ändern Sie das Verhalten nicht. Erstellen Sie dazu eine neue Ansicht. Um dies zu verringern, teilen Sie keine Ansichten mit anderen Projekten und verwenden Sie CTEs, wenn die Plattformen dies zulassen. Wenn Ihr Shop über einen DBA verfügt, können Sie die Ansichten wahrscheinlich nicht ändern, aber alle Ihre Ansichten sind veraltet und in diesem Fall unbrauchbar.
The! Paramed - Kann eine Abfrage mehr als einen Zweck haben? Wahrscheinlich, aber die nächste Person, die es liest, wird es erst in tiefer Meditation wissen. Selbst wenn Sie sie gerade nicht brauchen, werden Sie es wahrscheinlich tun, auch wenn es "nur" zum Debuggen ist. Das Hinzufügen von Parametern verkürzt die Wartungszeit und hält die Dinge trocken. Wenn Sie eine where-Klausel haben, sollten Sie Parameter haben.
Der Fall für keinen Fall -
quelle
Die beiden, die ich am meisten finde und die erhebliche Kosten in Bezug auf die Leistung verursachen können, sind:
Verwenden von Cursorn anstelle eines satzbasierten Ausdrucks. Ich denke, dies tritt häufig auf, wenn der Programmierer prozedural denkt.
Verwenden von korrelierten Unterabfragen, wenn ein Join zu einer abgeleiteten Tabelle die Aufgabe übernehmen kann.
quelle
Das Einfügen von Inhalten in temporäre Tabellen, insbesondere von Personen, die von SQL Server zu Oracle wechseln, hat die Angewohnheit, temporäre Tabellen zu häufig zu verwenden. Verwenden Sie einfach verschachtelte select-Anweisungen.
quelle
Entwickler, die Abfragen schreiben, ohne eine gute Vorstellung davon zu haben, was SQL-Anwendungen (sowohl einzelne Abfragen als auch Mehrbenutzersysteme) schnell oder langsam macht. Dies beinhaltet Unwissenheit über:
quelle
Verwenden von SQL als verherrlichtes ISAM-Paket (Indexed Sequential Access Method). Insbesondere das Verschachteln von Cursorn anstelle der Kombination von SQL-Anweisungen zu einer einzigen, wenn auch größeren Anweisung. Dies gilt auch als "Missbrauch des Optimierers", da der Optimierer tatsächlich nicht viel tun kann. Dies kann mit nicht vorbereiteten Aussagen kombiniert werden, um maximale Ineffizienz zu erzielen:
Die richtige Lösung besteht (fast immer) darin, die beiden SELECT-Anweisungen zu einer zu kombinieren:
Der einzige Vorteil der Doppelschleifenversion besteht darin, dass Sie die Unterbrechungen zwischen den Werten in Tabelle 1 leicht erkennen können, da die innere Schleife endet. Dies kann ein Faktor in Kontrollunterbrechungsberichten sein.
Außerdem ist das Sortieren in der Anwendung normalerweise ein Nein-Nein.
quelle
Verwenden von Primärschlüsseln als Ersatz für Datensatzadressen und Verwenden von Fremdschlüsseln als Ersatz für in Datensätze eingebettete Zeiger.
quelle