Was sind häufige Fehler bei der Datenbankentwicklung, die von Anwendungsentwicklern gemacht werden?
Was sind häufige Fehler bei der Datenbankentwicklung, die von Anwendungsentwicklern gemacht werden?
Antworten:
1. Verwenden Sie keine geeigneten Indizes
Dies ist relativ einfach, aber es passiert immer noch. Fremdschlüssel sollten Indizes enthalten. Wenn Sie ein Feld in einem verwenden WHERE
, sollten Sie (wahrscheinlich) einen Index darauf haben. Solche Indizes sollten häufig mehrere Spalten abdecken, basierend auf den Abfragen, die Sie ausführen müssen.
2. Referenzielle Integrität nicht erzwingen
Ihre Datenbank kann hier variieren, aber wenn Ihre Datenbank die referenzielle Integrität unterstützt - was bedeutet, dass alle Fremdschlüssel garantiert auf eine vorhandene Entität verweisen - sollten Sie sie verwenden.
Es ist durchaus üblich, dass dieser Fehler in MySQL-Datenbanken auftritt. Ich glaube nicht, dass MyISAM dies unterstützt. InnoDB tut es. Sie werden Leute finden, die MyISAM verwenden oder die InnoDB verwenden, es aber trotzdem nicht verwenden.
Mehr hier:
3. Verwenden Sie eher natürliche als (primäre) Ersatzprimärschlüssel
Natürliche Schlüssel sind Schlüssel, die auf extern aussagekräftigen Daten basieren, die (angeblich) eindeutig sind. Häufige Beispiele sind Produktcodes, aus zwei Buchstaben bestehende Staatscodes (USA), Sozialversicherungsnummern usw. Ersatz- oder technische Primärschlüssel sind solche, die außerhalb des Systems absolut keine Bedeutung haben. Sie wurden lediglich zur Identifizierung der Entität erfunden und sind in der Regel automatisch inkrementierende Felder (SQL Server, MySQL, andere) oder Sequenzen (insbesondere Oracle).
Meiner Meinung nach sollten Sie immer Ersatzschlüssel verwenden. Dieses Problem ist in folgenden Fragen aufgetreten:
Dies ist ein etwas kontroverses Thema, über das Sie keine allgemeine Einigung erzielen. Während Sie vielleicht einige Leute finden, die denken, dass natürliche Schlüssel in bestimmten Situationen in Ordnung sind, werden Sie keine Kritik an Ersatzschlüsseln finden, außer dass sie wohl unnötig sind. Das ist ein kleiner Nachteil, wenn Sie mich fragen.
Denken Sie daran, dass sogar Länder aufhören können zu existieren (zum Beispiel Jugoslawien).
4. Schreiben von Abfragen, die DISTINCT
funktionieren müssen
Sie sehen dies häufig in ORM-generierten Abfragen. Wenn Sie sich die Protokollausgabe von Hibernate ansehen, sehen Sie, dass alle Abfragen beginnen mit:
SELECT DISTINCT ...
Dies ist eine Abkürzung, um sicherzustellen, dass Sie keine doppelten Zeilen zurückgeben und somit doppelte Objekte erhalten. Manchmal sieht man auch Leute, die das tun. Wenn Sie es zu viel sehen, ist es eine echte rote Fahne. Nicht, dass DISTINCT
das schlecht ist oder keine gültigen Anwendungen hat. Dies ist (in beiden Punkten) der Fall, aber es ist kein Ersatz oder eine Notlösung für das Schreiben korrekter Abfragen.
Aus dem Grund, warum ich UNTERSCHIEDLICH hasse :
Meiner Meinung nach werden die Dinge sauer, wenn ein Entwickler umfangreiche Abfragen erstellt, Tabellen zusammenfügt und plötzlich merkt, dass es so aussieht, als würde er doppelte (oder sogar mehr) Zeilen erhalten und sofort reagieren ... Seine "Lösung" für dieses "Problem" besteht darin, das Schlüsselwort DISTINCT zu verwenden und POOF alle seine Probleme zu beseitigen .
5. Aggregation gegenüber Joins bevorzugen
Ein weiterer häufiger Fehler von Entwicklern von Datenbankanwendungen besteht darin, nicht zu erkennen, wie viel teurer die Aggregation (dh die GROUP BY
Klausel) mit Joins verglichen werden kann.
Um Ihnen eine Vorstellung davon zu geben, wie weit verbreitet dies ist, habe ich hier mehrmals über dieses Thema geschrieben und wurde dafür vielfach abgelehnt. Zum Beispiel:
Aus der SQL-Anweisung - "Join" vs "Gruppieren nach und Haben" :
Erste Abfrage:
SELECT userid FROM userrole WHERE roleid IN (1, 2, 3) GROUP by userid HAVING COUNT(1) = 3
Abfragezeit: 0,312 s
Zweite Abfrage:
SELECT t1.userid FROM userrole t1 JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2 JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3 AND t1.roleid = 1
Abfragezeit: 0,016 s
Das stimmt. Die von mir vorgeschlagene Join-Version ist zwanzigmal schneller als die Gesamtversion.
6. Komplexe Abfragen nicht durch Ansichten vereinfachen
Nicht alle Datenbankanbieter unterstützen Ansichten, aber für diejenigen, die dies tun, können sie Abfragen erheblich vereinfachen, wenn sie mit Bedacht verwendet werden. Zum Beispiel habe ich in einem Projekt ein generisches Party-Modell für CRM verwendet. Dies ist eine äußerst leistungsfähige und flexible Modellierungstechnik, die jedoch zu vielen Verknüpfungen führen kann. In diesem Modell gab es:
Beispiel:
Es gibt also fünf Tische, an denen Ted mit seinem Arbeitgeber verbunden ist. Sie gehen davon aus, dass alle Mitarbeiter Personen (keine Organisationen) sind, und bieten diese Hilfeansicht an:
CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id
Und plötzlich haben Sie eine sehr einfache Ansicht der gewünschten Daten, jedoch in einem hochflexiblen Datenmodell.
7. Eingabe nicht bereinigen
Dies ist eine große. Jetzt mag ich PHP, aber wenn Sie nicht wissen, was Sie tun, ist es wirklich einfach, Websites zu erstellen, die anfällig für Angriffe sind. Nichts fasst es besser zusammen als die Geschichte der kleinen Bobby Tables .
Daten, die vom Benutzer über URLs, Formulardaten und Cookies bereitgestellt werden, sollten immer als feindlich und bereinigt behandelt werden. Stellen Sie sicher, dass Sie das bekommen, was Sie erwarten.
8. Verwenden Sie keine vorbereiteten Anweisungen
Vorbereitete Anweisungen werden erstellt, wenn Sie eine Abfrage abzüglich der in Einfügungen, Aktualisierungen und WHERE
Klauseln verwendeten Daten kompilieren und diese später bereitstellen. Zum Beispiel:
SELECT * FROM users WHERE username = 'bob'
vs.
SELECT * FROM users WHERE username = ?
oder
SELECT * FROM users WHERE username = :username
abhängig von Ihrer Plattform.
Ich habe gesehen, wie Datenbanken auf diese Weise in die Knie gezwungen wurden. Grundsätzlich muss jede moderne Datenbank jedes Mal, wenn sie auf eine neue Abfrage stößt, diese kompilieren. Wenn eine zuvor gesehene Abfrage auftritt, geben Sie der Datenbank die Möglichkeit, die kompilierte Abfrage und den Ausführungsplan zwischenzuspeichern. Indem Sie die Abfrage häufig ausführen, geben Sie der Datenbank die Möglichkeit, dies herauszufinden und entsprechend zu optimieren (z. B. indem Sie die kompilierte Abfrage im Speicher fixieren).
Durch die Verwendung vorbereiteter Anweisungen erhalten Sie auch aussagekräftige Statistiken darüber, wie oft bestimmte Abfragen verwendet werden.
Vorbereitete Anweisungen schützen Sie auch besser vor SQL-Injection-Angriffen.
9. Nicht normalisierend genug
Die Datenbanknormalisierung ist im Grunde der Prozess der Optimierung des Datenbankdesigns oder der Organisation Ihrer Daten in Tabellen.
Erst diese Woche bin ich auf Code gestoßen, bei dem jemand ein Array implodiert und in ein einzelnes Feld in einer Datenbank eingefügt hat. Wenn Sie dies normalisieren, wird das Element dieses Arrays als separate Zeile in einer untergeordneten Tabelle behandelt (dh als Eins-zu-Viele-Beziehung).
Dies wurde auch in der besten Methode zum Speichern einer Liste von Benutzer-IDs angezeigt :
Ich habe in anderen Systemen gesehen, dass die Liste in einem serialisierten PHP-Array gespeichert ist.
Aber mangelnde Normalisierung gibt es in vielen Formen.
Mehr:
10. Zu viel normalisieren
Dies mag wie ein Widerspruch zum vorherigen Punkt erscheinen, aber Normalisierung ist wie viele andere Dinge ein Werkzeug. Es ist ein Mittel zum Zweck und kein Selbstzweck. Ich denke, viele Entwickler vergessen dies und beginnen, ein "Mittel" als "Zweck" zu behandeln. Unit Testing ist ein Paradebeispiel dafür.
Ich habe einmal an einem System gearbeitet, das eine riesige Hierarchie für Kunden hatte, die ungefähr so aussah:
Licensee -> Dealer Group -> Company -> Practice -> ...
so dass Sie ungefähr 11 Tabellen zusammenfügen mussten, bevor Sie aussagekräftige Daten erhalten konnten. Es war ein gutes Beispiel für eine zu weit gehende Normalisierung.
Genauer gesagt kann eine sorgfältige und überlegte Denormalisierung enorme Leistungsvorteile haben, aber Sie müssen dabei wirklich vorsichtig sein.
Mehr:
11. Verwenden Sie exklusive Bögen
Ein exklusiver Bogen ist ein häufiger Fehler, bei dem eine Tabelle mit zwei oder mehr Fremdschlüsseln erstellt wird, wobei einer und nur einer von ihnen ungleich Null sein kann. Großer Fehler. Zum einen wird es umso schwieriger, die Datenintegrität aufrechtzuerhalten. Schließlich hindert auch bei referenzieller Integrität nichts zwei oder mehr dieser Fremdschlüssel daran, gesetzt zu werden (ungeachtet komplexer Überprüfungsbeschränkungen).
Von einem praktischen Leitfaden zum relationalen Datenbankdesign :
Wir haben nachdrücklich von einer exklusiven Lichtbogenkonstruktion abgeraten, wo immer dies möglich ist, aus dem guten Grund, dass das Schreiben von Code umständlich sein und größere Wartungsschwierigkeiten verursachen kann.
12. Führen Sie überhaupt keine Leistungsanalyse für Abfragen durch
Vor allem in der Datenbankwelt herrscht Pragmatismus. Wenn Sie sich an Prinzipien halten, bis sie zu einem Dogma geworden sind, haben Sie höchstwahrscheinlich Fehler gemacht. Nehmen Sie das Beispiel der aggregierten Abfragen von oben. Die aggregierte Version mag "nett" aussehen, aber ihre Leistung ist bedauerlich. Ein Leistungsvergleich hätte die Debatte beenden sollen (aber nicht), aber mehr auf den Punkt gebracht: Es ist unwissend, sogar gefährlich, solche schlecht informierten Ansichten zu äußern.
13. Übermäßiges Vertrauen in UNION ALL und insbesondere in UNION-Konstrukte
Eine SQL-UNION verkettet lediglich kongruente Datensätze, dh sie haben denselben Typ und dieselbe Anzahl von Spalten. Der Unterschied zwischen ihnen besteht darin, dass UNION ALL eine einfache Verkettung ist und nach Möglichkeit bevorzugt werden sollte, während eine UNION implizit ein DISTINCT ausführt, um doppelte Tupel zu entfernen.
UNIONs wie DISTINCT haben ihren Platz. Es gibt gültige Bewerbungen. Aber wenn Sie feststellen, dass Sie viele davon ausführen, insbesondere bei Unterabfragen, dann machen Sie wahrscheinlich etwas falsch. Dies kann ein Fall einer schlechten Abfragekonstruktion oder eines schlecht gestalteten Datenmodells sein, das Sie dazu zwingt, solche Dinge zu tun.
UNIONs können, insbesondere wenn sie in Joins oder abhängigen Unterabfragen verwendet werden, eine Datenbank lahm legen. Versuchen Sie, sie nach Möglichkeit zu vermeiden.
14. Verwenden von ODER-Bedingungen in Abfragen
Dies könnte harmlos erscheinen. Immerhin sind ANDs in Ordnung. ODER sollte auch OK sein, oder? Falsch. Grundsätzlich schränkt eine UND-Bedingung den Datensatz ein, während eine ODER-Bedingung ihn vergrößert , jedoch nicht in einer Weise, die sich für eine Optimierung eignet. Insbesondere, wenn sich die verschiedenen ODER-Bedingungen überschneiden könnten, wodurch der Optimierer gezwungen wird, effektiv eine DISTINCT-Operation für das Ergebnis durchzuführen.
Schlecht:
... WHERE a = 2 OR a = 5 OR a = 11
Besser:
... WHERE a IN (2, 5, 11)
Jetzt kann Ihr SQL-Optimierer die erste Abfrage effektiv in die zweite umwandeln. Aber es könnte nicht. Tu es einfach nicht.
15. Entwerfen Sie ihr Datenmodell nicht so, dass es sich für leistungsstarke Lösungen eignet
Dies ist schwer zu quantifizieren. Es wird typischerweise durch seine Wirkung beobachtet. Wenn Sie feststellen, dass Sie knorrige Abfragen für relativ einfache Aufgaben schreiben oder dass Abfragen zum Herausfinden relativ einfacher Informationen nicht effizient sind, haben Sie wahrscheinlich ein schlechtes Datenmodell.
In gewisser Weise fasst dieser Punkt alle früheren zusammen, aber es ist eher eine warnende Geschichte, dass Dinge wie die Abfrageoptimierung oft zuerst durchgeführt werden, wenn sie an zweiter Stelle durchgeführt werden sollten. In erster Linie sollten Sie sicherstellen, dass Sie über ein gutes Datenmodell verfügen, bevor Sie versuchen, die Leistung zu optimieren. Wie Knuth sagte:
Vorzeitige Optimierung ist die Wurzel allen Übels
16. Falsche Verwendung von Datenbanktransaktionen
Alle Datenänderungen für einen bestimmten Prozess sollten atomar sein. Dh wenn die Operation erfolgreich ist, geschieht dies vollständig. Wenn dies fehlschlägt, bleiben die Daten unverändert. - Es sollte keine Möglichkeit für "halbfertige" Änderungen geben.
Im Idealfall besteht der einfachste Weg, dies zu erreichen, darin, dass das gesamte Systemdesign bestrebt ist, alle Datenänderungen durch einzelne INSERT / UPDATE / DELETE-Anweisungen zu unterstützen. In diesem Fall ist keine spezielle Transaktionsbehandlung erforderlich, da Ihr Datenbankmodul dies automatisch tun sollte.
Wenn für Prozesse jedoch mehrere Anweisungen als Einheit ausgeführt werden müssen, um die Daten in einem konsistenten Zustand zu halten, ist eine entsprechende Transaktionssteuerung erforderlich.
Es wird auch empfohlen, die Feinheiten der Interaktion Ihrer Datenbankkonnektivitätsschicht und des Datenbankmoduls in dieser Hinsicht sorgfältig zu berücksichtigen.
17. Das "satzbasierte" Paradigma nicht verstehen
Die SQL-Sprache folgt einem bestimmten Paradigma, das für bestimmte Arten von Problemen geeignet ist. Ungeachtet verschiedener herstellerspezifischer Erweiterungen hat die Sprache Schwierigkeiten, Probleme zu lösen, die in Sprachen wie Java, C #, Delphi usw. trivial sind.
Dieser Mangel an Verständnis manifestiert sich auf verschiedene Weise.
Bestimmen Sie eine klare Aufteilung der Verantwortung und bemühen Sie sich, das geeignete Tool zur Lösung jedes Problems zu verwenden.
Wichtige Datenbankdesign- und Programmierfehler von Entwicklern
Egoistisches Datenbankdesign und -nutzung. Entwickler behandeln die Datenbank häufig als ihren persönlichen Speicher für persistente Objekte, ohne die Bedürfnisse anderer Stakeholder in den Daten zu berücksichtigen. Dies gilt auch für Anwendungsarchitekten. Ein schlechtes Datenbankdesign und eine schlechte Datenintegrität erschweren es Dritten, mit den Daten zu arbeiten, und können die Lebenszykluskosten des Systems erheblich erhöhen. Reporting und MIS sind in der Regel ein schlechter Cousin im Anwendungsdesign und werden nur nachträglich durchgeführt.
Denormalisierte Daten missbrauchen. Das Übertreiben denormalisierter Daten und der Versuch, sie in der Anwendung zu verwalten, ist ein Rezept für Datenintegritätsprobleme. Verwenden Sie die Denormalisierung sparsam. Wenn Sie einer Abfrage keinen Join hinzufügen möchten, ist dies keine Entschuldigung für die Denormalisierung.
Angst vor dem Schreiben von SQL. SQL ist kein Hexenwerk und kann seine Arbeit eigentlich recht gut erledigen. O / R-Mapping-Layer sind gut darin, 95% der Abfragen zu erledigen, die einfach sind und gut in dieses Modell passen. Manchmal ist SQL der beste Weg, um die Arbeit zu erledigen.
Dogmatische Richtlinien für "Keine gespeicherten Prozeduren". Unabhängig davon, ob Sie gespeicherte Prozeduren für böse halten, hat diese dogmatische Haltung keinen Platz in einem Softwareprojekt.
Datenbankdesign nicht verstehen. Normalisierung ist dein Freund und es ist keine Raketenwissenschaft. Joining und Kardinalität sind ziemlich einfache Konzepte - wenn Sie an der Entwicklung von Datenbankanwendungen beteiligt sind, gibt es wirklich keine Entschuldigung dafür, sie nicht zu verstehen.
Überbeanspruchung und / oder Abhängigkeit von gespeicherten Prozeduren.
Einige Anwendungsentwickler betrachten gespeicherte Prozeduren als direkte Erweiterung des Middle Tier / Front-End-Codes. Dies scheint ein häufiges Merkmal von Microsoft-Stack-Entwicklern zu sein (ich bin eines, aber ich bin daraus gewachsen) und erzeugt viele gespeicherte Prozeduren, die komplexe Geschäftslogik und Workflow-Verarbeitung ausführen. Dies ist anderswo viel besser gemacht.
Gespeicherte Prozeduren sind nützlich, wenn tatsächlich nachgewiesen wurde, dass ein realer technischer Faktor ihre Verwendung erfordert (z. B. Leistung und Sicherheit). Halten Sie beispielsweise die Aggregation / Filterung großer Datenmengen "nah an den Daten".
Ich musste kürzlich helfen, eine große Delphi-Desktopanwendung zu warten und zu verbessern, von der 70% der Geschäftslogik und -regeln in 1400 gespeicherten SQL Server-Prozeduren implementiert waren (der Rest in UI-Ereignishandlern). Dies war ein Albtraum, vor allem aufgrund der Schwierigkeit, effektive Unit-Tests in TSQL einzuführen, mangelnder Kapselung und schlechter Tools (Debugger, Editoren).
Als ich in der Vergangenheit mit einem Java-Team zusammengearbeitet habe, habe ich schnell herausgefunden, dass in dieser Umgebung oft genau das Gegenteil der Fall ist. Ein Java-Architekt sagte mir einmal: "Die Datenbank ist für Daten, nicht für Code."
Heutzutage halte ich es für einen Fehler, gespeicherte Prozesse überhaupt nicht zu berücksichtigen, aber sie sollten sparsam (nicht standardmäßig) in Situationen verwendet werden, in denen sie nützliche Vorteile bieten (siehe die anderen Antworten).
Problem Nummer eins? Sie testen nur auf Spielzeugdatenbanken. Sie haben also keine Ahnung, dass ihr SQL-Code kriecht, wenn die Datenbank groß wird, und jemand muss vorbeikommen und sie später reparieren (das Geräusch, das Sie hören können, ist, dass meine Zähne knirschen).
Keine Indizes verwenden.
Schlechte Leistung durch korrelierte Unterabfragen
Meistens möchten Sie korrelierte Unterabfragen vermeiden. Eine Unterabfrage wird korreliert, wenn innerhalb der Unterabfrage ein Verweis auf eine Spalte aus der äußeren Abfrage vorhanden ist. In diesem Fall wird die Unterabfrage mindestens einmal für jede zurückgegebene Zeile ausgeführt und kann mehrmals ausgeführt werden, wenn andere Bedingungen angewendet werden, nachdem die Bedingung, die die korrelierte Unterabfrage enthält, angewendet wurde.
Verzeihen Sie das erfundene Beispiel und die Oracle-Syntax, aber nehmen wir an, Sie wollten alle Mitarbeiter finden, die in einem Ihrer Geschäfte eingestellt wurden, seit das Geschäft das letzte Mal weniger als 10.000 US-Dollar Umsatz pro Tag erzielt hat.
select e.first_name, e.last_name
from employee e
where e.start_date >
(select max(ds.transaction_date)
from daily_sales ds
where ds.store_id = e.store_id and
ds.total < 10000)
Die Unterabfrage in diesem Beispiel wird von der store_id mit der äußeren Abfrage korreliert und für jeden Mitarbeiter in Ihrem System ausgeführt. Eine Möglichkeit, diese Abfrage zu optimieren, besteht darin, die Unterabfrage in eine Inline-Ansicht zu verschieben.
select e.first_name, e.last_name
from employee e,
(select ds.store_id,
max(s.transaction_date) transaction_date
from daily_sales ds
where ds.total < 10000
group by s.store_id) dsx
where e.store_id = dsx.store_id and
e.start_date > dsx.transaction_date
In diesem Beispiel ist die Abfrage in der from-Klausel jetzt eine Inline-Ansicht (wieder eine Oracle-spezifische Syntax) und wird nur einmal ausgeführt. Abhängig von Ihrem Datenmodell wird diese Abfrage wahrscheinlich viel schneller ausgeführt. Es würde eine bessere Leistung als die erste Abfrage erzielen, wenn die Anzahl der Mitarbeiter zunehme. Die erste Abfrage könnte tatsächlich eine bessere Leistung erzielen, wenn nur wenige Mitarbeiter und viele Geschäfte vorhanden wären (und möglicherweise viele Geschäfte keine Mitarbeiter hatten) und die Tabelle daily_sales auf store_id indiziert wäre. Dies ist kein wahrscheinliches Szenario, zeigt jedoch, wie eine korrelierte Abfrage möglicherweise eine bessere Leistung als eine Alternative erzielen kann.
Ich habe viele Male gesehen, wie Junior-Entwickler Unterabfragen korrelierten, und dies hatte normalerweise erhebliche Auswirkungen auf die Leistung. Wenn Sie jedoch eine korrelierte Unterabfrage entfernen, lesen Sie unbedingt den Erklärungsplan vorher und nachher, um sicherzustellen, dass Sie die Leistung nicht verschlechtern.
Verwenden von Access anstelle einer "echten" Datenbank. Es gibt viele großartige kleine und sogar kostenlose Datenbanken wie SQL Express , MySQL und SQLite , die viel besser funktionieren und skalieren. Apps müssen häufig auf unerwartete Weise skaliert werden.
Verwenden von Excel zum Speichern (großer Datenmengen).
Ich habe Unternehmen gesehen, die Tausende von Zeilen halten und mehrere Arbeitsblätter verwenden (aufgrund des Zeilenlimits von 65535 in früheren Excel-Versionen).
Excel eignet sich gut für Berichte, Datenpräsentationen und andere Aufgaben, sollte jedoch nicht als Datenbank behandelt werden.
Ich möchte hinzufügen: Bevorzugung von "elegantem" Code gegenüber leistungsstarkem Code. Der Code, der am besten gegen Datenbanken funktioniert, ist für den Anwendungsentwickler oft hässlich.
Ich glaube an diesen Unsinn über vorzeitige Optimierung. Datenbanken müssen die Leistung im ursprünglichen Design und in jeder nachfolgenden Entwicklung berücksichtigen. Die Leistung macht meiner Meinung nach 50% des Datenbankdesigns aus (40% sind Datenintegrität und die letzten 10% sind Sicherheit). Datenbanken, die nicht von Grund auf für die Leistung erstellt wurden, weisen eine schlechte Leistung auf, sobald echte Benutzer und echter Datenverkehr gegen die Datenbank gestellt werden. Vorzeitige Optimierung bedeutet nicht keine Optimierung! Es bedeutet nicht, dass Sie Code schreiben sollten, der fast immer schlecht funktioniert, weil Sie es einfacher finden (z. B. Cursor, die in einer Produktionsdatenbank niemals zugelassen werden sollten, es sei denn, alles andere ist fehlgeschlagen). Es bedeutet, dass Sie nicht darauf achten müssen, das letzte bisschen Leistung herauszuholen, bis Sie es brauchen. Es ist viel darüber bekannt, was bei Datenbanken besser funktioniert.
Keine parametrisierten Abfragen verwenden. Sie sind ziemlich praktisch, um SQL Injection zu stoppen .
Dies ist ein spezielles Beispiel für die Nichtbereinigung von Eingabedaten, das in einer anderen Antwort erwähnt wird.
Ich hasse es, wenn Entwickler verschachtelte select-Anweisungen verwenden oder sogar Funktionen verwenden, um das Ergebnis einer select-Anweisung im "SELECT" -Teil einer Abfrage zurückzugeben.
Ich bin tatsächlich überrascht, dass ich das hier nirgendwo anders sehe, vielleicht habe ich es übersehen, obwohl @adam ein ähnliches Problem hat.
Beispiel:
SELECT
(SELECT TOP 1 SomeValue FROM SomeTable WHERE SomeDate = c.Date ORDER BY SomeValue desc) As FirstVal
,(SELECT OtherValue FROM SomeOtherTable WHERE SomeOtherCriteria = c.Criteria) As SecondVal
FROM
MyTable c
Wenn MyTable in diesem Szenario 10000 Zeilen zurückgibt, ist das Ergebnis so, als ob die Abfrage gerade 20001-Abfragen ausgeführt hätte, da die erste Abfrage plus Abfrage jeder anderen Tabelle einmal für jede Ergebniszeile ausgeführt werden musste.
Entwickler können damit in einer Entwicklungsumgebung durchkommen, in der sie nur wenige Datenzeilen zurückgeben und die Untertabellen normalerweise nur eine geringe Datenmenge enthalten. In einer Produktionsumgebung kann diese Art der Abfrage jedoch exponentiell kostspieliger werden Daten werden zu den Tabellen hinzugefügt.
Ein besseres (nicht unbedingt perfektes) Beispiel wäre etwa:
SELECT
s.SomeValue As FirstVal
,o.OtherValue As SecondVal
FROM
MyTable c
LEFT JOIN (
SELECT SomeDate, MAX(SomeValue) as SomeValue
FROM SomeTable
GROUP BY SomeDate
) s ON c.Date = s.SomeDate
LEFT JOIN SomeOtherTable o ON c.Criteria = o.SomeOtherCriteria
Auf diese Weise können Datenbankoptimierer die Daten zusammenmischen, anstatt sie für jeden Datensatz aus der Haupttabelle anzufordern. Wenn ich Code korrigieren muss, bei dem dieses Problem erstellt wurde, kann ich die Geschwindigkeit von Abfragen normalerweise um 100% oder mehr erhöhen mehr bei gleichzeitiger Reduzierung der CPU- und Speicherauslastung.
Für SQL-basierte Datenbanken:
Keine Sicherung durchführen, bevor ein Problem in der Produktionsdatenbank behoben wurde.
Verwenden von DDL-Befehlen für gespeicherte Objekte (wie Tabellen, Ansichten) in gespeicherten Prozeduren.
Angst vor der Verwendung gespeicherter Prozesse oder Angst vor der Verwendung von ORM-Abfragen, wo immer diese effizienter / angemessener zu verwenden sind.
Ignorieren Sie die Verwendung eines Datenbankprofilers, der Ihnen genau sagen kann, in was Ihre ORM-Abfrage endgültig konvertiert wird, und überprüfen Sie daher die Logik oder sogar das Debuggen, wenn Sie ORM nicht verwenden.
Nicht die richtige Normalisierung durchführen . Sie möchten sicherstellen, dass Daten nicht dupliziert werden und dass Sie Daten nach Bedarf in verschiedene Daten aufteilen. Sie müssen auch sicherstellen, dass Sie der Normalisierung nicht zu weit folgen , da dies die Leistung beeinträchtigt.
Behandeln der Datenbank nur als Speichermechanismus (dh als Bibliothek verherrlichter Sammlungen) und daher ihrer Anwendung untergeordnet (Ignorieren anderer Anwendungen, die die Daten gemeinsam nutzen)
1 - Unnötige Verwendung einer Funktion für einen Wert in einer where-Klausel, wobei das Ergebnis dieses Index nicht verwendet wird.
Beispiel:
where to_char(someDate,'YYYYMMDD') between :fromDate and :toDate
anstatt
where someDate >= to_date(:fromDate,'YYYYMMDD') and someDate < to_date(:toDate,'YYYYMMDD')+1
Und in geringerem Maße: Den Werten, die sie benötigen, keine Funktionsindizes hinzufügen ...
2 - Keine Prüfeinschränkungen hinzufügen, um die Gültigkeit der Daten sicherzustellen. Einschränkungen können vom Abfrageoptimierer verwendet werden und tragen WIRKLICH dazu bei, dass Sie Ihren Invarianten vertrauen können. Es gibt einfach keinen Grund, sie nicht zu benutzen.
3 - Hinzufügen von nicht normalisierten Spalten zu Tabellen aus purer Faulheit oder Zeitdruck. Die Dinge sind normalerweise nicht so gestaltet, sondern entwickeln sich zu diesen. Das Endergebnis ist ohne Zweifel eine Menge Arbeit, die versucht, das Chaos zu beseitigen, wenn Sie bei zukünftigen Entwicklungen von der verlorenen Datenintegrität gebissen werden.
Denken Sie daran, eine Tabelle ohne Daten ist sehr billig neu zu gestalten. Eine Tabelle mit ein paar Millionen Datensätzen ohne Integrität ... nicht so billig neu zu gestalten. Daher wird die korrekte Gestaltung beim Erstellen der Spalte oder Tabelle in Pik abgeschrieben.
4 - nicht so sehr über die Datenbank an sich, aber in der Tat ärgerlich. Die Codequalität von SQL ist mir egal. Die Tatsache, dass Ihr SQL in Text ausgedrückt wird, macht es nicht in Ordnung, die Logik in Haufen von String-Manipulationsalgorithmen zu verbergen. Es ist durchaus möglich, SQL in Textform so zu schreiben, dass sie von Ihrem Programmierkollegen tatsächlich gelesen werden kann.
Dies wurde bereits gesagt, aber: Indizes, Indizes, Indizes . Ich habe so viele Fälle von Web-Apps mit schlechter Leistung gesehen, die behoben wurden, indem einfach ein wenig Profilerstellung durchgeführt wurde (um zu sehen, welche Tabellen häufig betroffen waren) und dann ein Index für diese Tabellen hinzugefügt wurde. Dies erfordert nicht einmal viel SQL-Schreibwissen, und der Gewinn ist enorm.
Vermeiden Sie Datenvervielfältigungen wie die Pest. Einige Leute befürworten, dass eine kleine Verdoppelung nicht schadet und die Leistung verbessert. Hey, ich sage nicht, dass Sie Ihr Schema in die dritte Normalform quälen müssen, bis es so abstrakt ist, dass nicht einmal die DBAs wissen, was los ist. Wenn Sie eine Reihe von Namen, Postleitzahlen oder Versandcodes duplizieren, werden die Kopien möglicherweise nicht mehr miteinander synchronisiert. Es wird passieren. Und dann treten Sie sich selbst, während Sie das wöchentliche Wartungsskript ausführen.
Und zum Schluss: Verwenden Sie eine klare, konsistente und intuitive Namenskonvention. So wie ein gut geschriebener Code lesbar sein sollte, sollte ein gutes SQL-Schema oder eine gute SQL-Abfrage lesbar sein und Ihnen praktisch sagen , was es tut, auch ohne Kommentare. Sie werden sich in sechs Monaten bedanken, wenn Sie die Tische warten müssen. "SELECT account_number, billing_date FROM national_accounts"
ist unendlich einfacher zu bearbeiten als "SELECT ACCNTNBR, BILLDAT FROM NTNLACCTS".
Der häufigste Fehler, den ich seit zwanzig Jahren gesehen habe: nicht vorausplanen. Viele Entwickler erstellen eine Datenbank und Tabellen und ändern und erweitern die Tabellen dann kontinuierlich, während sie die Anwendungen erstellen. Das Endergebnis ist oft ein Durcheinander und ineffizient und später schwer zu bereinigen oder zu vereinfachen.
a) Hardcodierung von Abfragewerten in Zeichenfolge
b) Einfügen des Datenbankabfragecodes in die Aktion "OnButtonPress" in einer Windows Forms-Anwendung
Ich habe beide gesehen.
Ich denke, dass sie DBAs und Datenmodellierer / Designer sind, wenn sie in diesen Bereichen keinerlei formale Belehrung haben.
Zu denken, dass ihr Projekt keinen DBA erfordert, weil das alles einfach / trivial ist.
Nicht ordnungsgemäße Unterscheidung zwischen Arbeiten, die in der Datenbank ausgeführt werden sollen, und Arbeiten, die in der App ausgeführt werden sollen.
Backups nicht validieren oder nicht sichern.
Einbetten von Raw SQL in ihren Code.
Hier ist ein Link zum Video " Klassische Datenbankentwicklungsfehler und fünf Möglichkeiten, sie zu überwinden " von Scott Walz
Sie haben kein Verständnis für das Parallelitätsmodell der Datenbanken und wie sich dies auf die Entwicklung auswirkt. Es ist einfach, Indizes hinzuzufügen und Abfragen nachträglich zu optimieren. Anwendungen, die ohne angemessene Berücksichtigung von Hotspots, Ressourcenkonflikten und korrektem Betrieb entwickelt wurden (vorausgesetzt, das, was Sie gerade gelesen haben, ist noch gültig!), Können jedoch erhebliche Änderungen in der Datenbank und der Anwendungsebene erfordern, um später korrigiert zu werden.
Ich verstehe nicht, wie ein DBMS unter der Haube funktioniert.
Sie können einen Steuerknüppel nicht richtig fahren, ohne zu verstehen, wie eine Kupplung funktioniert. Und Sie können nicht verstehen, wie eine Datenbank verwendet wird, ohne zu verstehen, dass Sie wirklich nur in eine Datei auf Ihrer Festplatte schreiben.
Speziell:
Wissen Sie, was ein Clustered Index ist? Haben Sie darüber nachgedacht, als Sie Ihr Schema entworfen haben?
Wissen Sie, wie man Indizes richtig verwendet? Wie verwende ich einen Index wieder? Wissen Sie, was ein Covering Index ist?
So toll, Sie haben Indizes. Wie groß ist 1 Zeile in Ihrem Index? Wie groß wird der Index sein, wenn Sie viele Daten haben? Wird das leicht in die Erinnerung passen? Wenn nicht, ist es als Index nutzlos.
Haben Sie EXPLAIN jemals in MySQL verwendet? Großartig. Seien Sie jetzt ehrlich zu sich selbst: Haben Sie auch nur die Hälfte von dem verstanden, was Sie gesehen haben? Nein, hast du wahrscheinlich nicht. Repariere das.
Verstehst du den Abfrage-Cache? Wissen Sie, warum eine Abfrage nicht zwischengespeichert werden kann?
Verwenden Sie MyISAM? Wenn Sie eine Volltextsuche benötigen, ist MyISAM's sowieso Mist. Verwenden Sie Sphinx. Dann wechseln Sie zu Inno.