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.
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.
4. Schreiben von Abfragen, die DISTINCTfunktionieren 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 DISTINCTdas 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.
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 BYKlausel) 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:
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:
Partei : Menschen und Organisationen;
Parteirolle : Dinge, die diese Parteien getan haben, zum Beispiel Arbeitnehmer und Arbeitgeber;
Parteirollenbeziehung : Wie diese Rollen miteinander zusammenhängen.
Beispiel:
Ted ist eine Person, ein Subtyp der Partei;
Ted hat viele Rollen, von denen eine Mitarbeiter ist;
Intel ist eine Organisation, die ein Subtyp einer Partei ist.
Intel hat viele Rollen, von denen eine der Arbeitgeber ist.
Intel beschäftigt Ted, was bedeutet, dass es eine Beziehung zwischen ihren jeweiligen Rollen gibt.
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 WHEREKlauseln 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 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.
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).
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.
Starten Sie eine Transaktion vor der ersten Anweisung.
Übernehmen Sie die Transaktion nach der letzten Anweisung.
Führen Sie bei einem Fehler ein Rollback der Transaktion durch. Und sehr NB! Vergessen Sie nicht, alle Anweisungen zu überspringen / abzubrechen, die nach dem Fehler folgen.
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.
Unangemessenes Auferlegen von zu viel prozeduraler oder zwingender Logik auf die Datenbank.
Unangemessener oder übermäßiger Gebrauch von Cursorn. Besonders wenn eine einzige Abfrage ausreichen würde.
Falsch angenommen, dass bei mehrzeiligen Aktualisierungen einmal pro Zeile ein Brand ausgelöst wird.
Bestimmen Sie eine klare Aufteilung der Verantwortung und bemühen Sie sich, das geeignete Tool zur Lösung jedes Problems zu verwenden.
In den MySQL-Anweisungen zu Fremdschlüsseln haben Sie Recht, dass MyISAM sie nicht unterstützt, aber Sie implizieren, dass die bloße Verwendung von MyISAM ein schlechtes Design ist. Ein Grund, warum ich MyISAM verwendet habe, ist, dass InnoDB keine FullText-Suche unterstützt, und ich halte das nicht für unangemessen.
Derek H
1
Ich muss nach # 6 fragen. Die Verwendung solcher Ansichten ist eine meiner Lieblingsbeschäftigungen, aber ich habe kürzlich zu meinem Entsetzen erfahren, dass bei MySQL-Indizes für die zugrunde liegenden Tabellen nur dann eingehalten wird, wenn die Struktur der Ansicht die Verwendung des Zusammenführungsalgorithmus zulässt. Andernfalls wird eine temporäre Tabelle verwendet und alle Ihre Indizes sind unbrauchbar. Es ist noch alarmierender, wenn Sie feststellen, dass eine Reihe von Vorgängen dieses Verhalten verursachen. Es ist eine großartige Möglichkeit, eine Abfrage von 0,01 Sekunden in eine Abfrage von 100 Sekunden umzuwandeln. Hat hier noch jemand Erfahrung damit? Überprüfen Sie die Links in meinem nächsten Kommentar.
Peter Bailey
5
Stimme # 3 überhaupt nicht zu. Ja, Länder können aufhören zu existieren, aber der Ländercode wird weiterhin dasselbe darstellen. Gleiches gilt für Währungscodes oder US-Bundesstaaten. In diesen Fällen ist es dumm, einen Ersatzschlüssel zu verwenden, und es entsteht mehr Aufwand für Ihre Abfragen, da Sie einen zusätzlichen Join hinzufügen müssen. Ich würde sagen, dass es sicherer ist zu sagen, dass Sie wahrscheinlich einen Ersatz für benutzerspezifische Daten verwenden sollten (also nicht Länder, Währungen und US-Bundesstaaten).
Thomas
1
RE: # 11 Die zur Durchsetzung der Datenintegrität erforderliche Überprüfungsbeschränkung ist trivial. Es gibt andere Gründe, dieses Design zu vermeiden, aber die Notwendigkeit einer "komplexen" Prüfbeschränkung gehört nicht dazu.
Thomas
2
Mit # 3 bist du nicht ehrlich. Der künstliche Schlüssel hat mehr Nachteile als "Sie brauchen ihn möglicherweise nicht". Insbesondere können Sie mit einem natürlichen Schlüssel die Reihenfolge steuern, in der Daten in Ihrer Tabelle auf die Festplatte geschrieben werden. Wenn Sie wissen, wie Ihre Tabelle abgefragt wird, können Sie sie indizieren, damit Zeilen, auf die gleichzeitig zugegriffen wird, auf derselben Seite landen. Darüber hinaus können Sie die Datenintegrität mithilfe eines eindeutigen zusammengesetzten Index erzwingen. Wenn Sie dies benötigen, müssen Sie es zusätzlich zu Ihrem künstlichen Schlüsselindex hinzufügen. Wenn der zusammengesetzte Index Ihr Schlüssel ist, werden 2 Fliegen mit einer Klappe geschlagen.
Shane H
110
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.
Man könnte argumentieren, dass Transaktionen in der Transaktionsdatenbank und in der Berichterstellung und MIS in einer separaten Analysedatenbank durchgeführt werden sollten. Daher erhalten Sie das Beste aus beiden Welten und jeder ist glücklich (mit Ausnahme des armen Bechers, der das Datentransformationsskript schreiben muss, um das letztere aus dem ersteren zu erstellen).
Chris Simpson
Nicht nur der schlechte Becher, der die ETL schreibt - jeder, der Daten aus dem System verwendet, die Daten von schlechter Qualität in der MIS-Anwendung, die eingepackt sind, weil mehrere Schlüsselbeziehungen nicht tatsächlich an der Quelle aufgezeichnet wurden, sondern jeder, der an den daraus resultierenden endlosen Abstimmungsbündeln beteiligt ist von der schlechten Datenqualität.
ConcernedOfTunbridgeWells
Ich könnte unmöglich mehr mit Punkt eins nicht einverstanden sein. Datenbanken dienen der Persistenz und nicht der Kommunikation zwischen Prozessen. Es gibt fast immer bessere Lösungen für dieses Problem. Sofern dies nicht ausdrücklich vorgeschrieben ist, sollten Sie die Datenbank unbedingt so behandeln, als würde sie niemand außer Ihrer Anwendung jemals verwenden. Selbst wenn es eine explizite Anforderung gibt, führen Sie eine User Story- und Ursachenanalyse durch, und Sie werden häufig einen viel besseren Weg finden, um die Absicht des Anforderers zu erfüllen. Andererseits arbeite ich in einer Firma, in der der Ausdruck CQRS etwas verbreitet ist
George Mauer
3
Triviales Beispiel: Ich habe ein Verwaltungssystem für Versicherungspolicen und muss den Status von 5 Millionen Schadensfällen in ein abgetretenes Rückversicherungssystem laden, um mögliche Rückforderungen zu berechnen. Bei den Systemen handelt es sich um ältere Client-Server-COTS-Pakete, die für die Schnittstelle zu noch älteren Mainframe-Systemen ausgelegt sind. Beide müssen zu Zwecken der Finanzkontrolle abgeglichen werden. Diese Arbeit wird einmal im Monat erledigt. Nach Ihrer Logik würde ich eine Reihe von User Stories schreiben, in denen die Anforderungen definiert werden, und die Anbieter bitten, ein Zitat zum Hinzufügen eines Web-Service-Wrappers zu ihren vorhandenen Produkten zu zitieren.
ConcernedOfTunbridgeWells
2
Dann ist Ihr DBA entweder faul oder inkompetent.
ConcernedOfTunbridgeWells
80
Keine Versionskontrolle für das Datenbankschema verwenden
Direkt gegen eine Live-Datenbank arbeiten
Fortgeschrittene Datenbankkonzepte (Indizes, Clustered-Indizes, Einschränkungen, materialisierte Ansichten usw.) nicht lesen und verstehen.
Wenn Sie die Skalierbarkeit nicht testen ... Testdaten von nur 3 oder 4 Zeilen geben Ihnen niemals ein reales Bild der realen Live-Leistung
Ich zweitens, schwer, # 1 und # 2. Jedes Mal, wenn ich eine Änderung an der Datenbank vornehme, speichere ich das Schema und versioniere es. Ich habe drei Datenbanken eingerichtet, eine Entwickler-Datenbank, eine Staging-Datenbank und eine Live-Datenbank - NICHTS wird jemals in der Live-Datenbank "getestet" !!
Ixmatus
Hier bei Red Gate haben wir Schritte unternommen, um Ihren ersten Punkt mit SQL Source Control zu verbessern! Aufgrund von Gesprächen, die ich während meiner Recherchen geführt habe, denke ich, dass die Leute nicht mehr gegen Produktionsdatenbanken entwickeln, aber oft werden "Notfall" -Korrekturen vorgenommen, die im Allgemeinen den Weg zurück in Entwicklungsumgebungen finden, was ein weiteres Problem darstellt.
David Atkinson
46
Ü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).
Gespeicherte Prozeduren neigen dazu, in jedem Projekt, in dem sie verwendet werden, zu einer Insel der Verletzung zu werden. Daher stellen einige Entwickler die Regel "Keine gespeicherten Prozeduren" auf. Es sieht also so aus, als gäbe es einen offenen Konflikt zwischen ihnen. Ihre Antwort ist ein gutes Argument dafür, wann Sie tatsächlich den einen oder anderen Weg wählen sollten.
Warren P
Vorteile: Sicherheit - Sie müssen Anwendungen nicht die Möglichkeit geben, "aus ... zu löschen". Optimierungen - Datenbankadministratoren können die Abfragen optimieren, ohne die gesamte Anwendung neu kompilieren / bereitstellen zu müssen. Analyse - Es ist einfach, eine Reihe von Prozessen nach einer Änderung des Datenmodells neu zu kompilieren, um sicherzustellen, dass sie noch gültig sind. und schließlich, wenn man bedenkt, dass SQL von der Datenbank-Engine (nicht von Ihrer Anwendung) ausgeführt wird, wird das Konzept "Datenbank ist für Daten, nicht für Code" nur verzögert.
NotMe
Sie würden also Ihre Geschäftslogik in die Benutzeroberfläche einbinden, wo sie von den zu manipulierenden Daten getrennt wurde? Dies scheint keine so gute Idee zu sein, zumal die Datenmanipulation am effizientesten ist, wenn sie vom Datenbankserver und nicht von Roundtrips über die Benutzeroberfläche ausgeführt wird. Dies bedeutet auch, dass die Steuerung der Anwendung schwieriger ist, da Sie sich nicht darauf verlassen können, dass die Datenbank die Kontrolle über ihre Daten hat und möglicherweise unterschiedliche Versionen einer Benutzeroberfläche mit unterschiedlichen Datenmanipulationen vorhanden sind. Nicht gut. Ich lasse nichts meine Daten berühren, außer durch eine gespeicherte Prozedur.
David T. Macknet
Wenn die Geschäftslogik von der Benutzeroberfläche getrennt werden muss, können mehrschichtige Architekturen verwendet werden. Oder eine Bibliothek mit Geschäftsobjekten und Logik, die von verschiedenen Apps / Benutzeroberflächen verwendet wird. Gespeicherte Prozeduren sperren Ihre Daten- / Geschäftslogik an eine bestimmte Datenbank. Das Ändern einer Datenbank ist in diesem Fall sehr kostspielig. Und enorme Kosten sind schlecht.
Auch
@too: Das Ändern einer Datenbank ist in den meisten Fällen sehr kostspielig. Denken Sie nicht daran, die Leistungs- und Sicherheitsfunktionen eines bestimmten DBMS zu verlieren. Darüber hinaus erhöhen zusätzliche Ebenen die Komplexität und verringern die Leistung, und zusätzliche Ebenen sind an Ihre spezielle Sprache gebunden. Schließlich ist es wahrscheinlicher, dass sich die verwendete Sprache ändert als ein Datenbankserver.
NotMe
41
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).
Die Größe der Datenbank ist relevant, aber ein größeres Problem ist das Laden - selbst wenn Sie an einem realen Dataset testen, testen Sie nicht die Leistung Ihrer Abfragen, wenn die Datenbank unter Produktionslast steht, was ein echter Augenöffner sein kann.
Davidcl
Ich würde sagen, dass die Datenbankgröße ein größeres Problem ist als das Laden. Ich habe oft gesehen, dass wichtige Indizes fehlten - es gab nie Leistungsprobleme bei Tests, weil die gesamte Datenbank in den Speicher passte
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.
Toller Punkt, und um einen Ihrer verwandten Punkte hervorzuheben - testen Sie Ihre Änderungen. Erfahren Sie, wie Sie EXPLAIN-Pläne verwenden (und sehen, was die Datenbank tatsächlich tut, um Ihre Abfrage auszuführen, und was sie kostet), Ihre Tests an einem großen Dataset durchführen und Ihr SQL für eine Optimierung nicht zu komplex und unlesbar / nicht wartbar machen das verbessert die tatsächliche Leistung nicht wirklich.
Rob Whelan
21
Nach meiner Erfahrung:
Keine Kommunikation mit erfahrenen Datenbankadministratoren.
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.
Vergessen, Beziehungen zwischen den Tabellen einzurichten. Ich erinnere mich, dass ich das aufräumen musste, als ich anfing, bei meinem derzeitigen Arbeitgeber zu arbeiten.
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.
+1 - Bei der Datenbankprogrammierung wird das Verhalten mechanischer Komponenten optimiert. Beachten Sie jedoch, dass Knuth sagt, dass vorzeitige Optimierung in 97% der Fälle die Wurzel allen Übels ist (oder entsprechende Worte). Das Datenbankdesign ist ein Bereich, in dem Sie wirklich im Voraus darüber nachdenken müssen.
ConcernedOfTunbridgeWells
2
Ähm ... Sie sprechen von einer Optimierung, die nicht verfrüht ist. Beim Datenbankdesign (und auch beim Anwendungsdesign) ist von Anfang an eine gewisse Berücksichtigung der tatsächlichen Nutzung erforderlich. Knuths Regel ist eigentlich nicht trivial zu befolgen, da Sie entscheiden müssen, was verfrüht ist und was nicht - es kommt wirklich darauf an, "keine Optimierungen ohne Daten durchzuführen". Die frühen leistungsbezogenen Entscheidungen, über die Sie sprechen , enthalten Daten. Bestimmte Designs setzen der zukünftigen Leistung unannehmbare Grenzen, und Sie können sie berechnen.
Rob Whelan
13
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.
Außer dass die Desinfektionseingabe falsch ist. Desinfizieren bedeutet, es an einem Ort zu platzieren, an dem es gefährlich sein kann. Parametrisierung bedeutet, es aus dem Weg des Schadens herauszuhalten.
Dustin
12
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.
CLUSTERED INDEXES nicht nutzen oder die falschen Spalten für CLUSTER auswählen.
Kein SERIAL-Datentyp (Autonumber) als PRIMARY KEY zum Verbinden mit einem FOREIGN KEY (INT) in einer Eltern / Kind-Tabellenbeziehung.
Keine Aktualisierung von Statistiken für eine Tabelle, wenn viele Datensätze eingefügt oder gelöscht wurden.
Keine Neuorganisation (dh Entladen, Löschen, Neuerstellen, Laden und erneutes Indizieren) von Tabellen, wenn viele Zeilen eingefügt oder gelöscht wurden (einige Engines behalten gelöschte Zeilen in einer Tabelle mit einem Löschflag physisch bei.)
FRAGMENT ON EXPRESSION (falls unterstützt) auf großen Tischen mit hohen Transaktionsraten nicht nutzen.
Auswahl des falschen Datentyps für eine Spalte!
Keine Auswahl eines richtigen Spaltennamens.
Keine neuen Spalten am Ende der Tabelle hinzufügen.
Keine richtigen Indizes zur Unterstützung häufig verwendeter Abfragen erstellen.
Erstellen von Indizes für Spalten mit wenigen möglichen Werten und Erstellen unnötiger Indizes.
... mehr hinzugefügt werden.
Ein Streit: 2) ist eigentlich eine schlechte Praxis. Ich verstehe, worauf Sie hinaus wollen - Sie möchten einen eindeutigen Index für diese automatische Nummerierung und diesen als Ersatzschlüssel verwenden. Der Primärschlüssel sollte jedoch keine Autonummer sein, da dies nicht das ist, was ein Primärschlüssel ist: Ein Primärschlüssel ist "worum es in dem Datensatz geht", der (mit Ausnahme von Dingen wie Verkaufstransaktionen) NICHT die Autonummer ist, sondern ein eindeutiges Bit von Informationen über die zu modellierende Entität.
David T. Macknet
Der Hauptgrund für die Verwendung der automatischen Nummerierung für Primär- und Fremdschlüssel besteht darin, sicherzustellen, dass ein Eltern-Kind-Join unabhängig von Änderungen in anderen Spalten beibehalten werden kann. Die Verwendung eines anderen Primärschlüssels wie Kundenname oder anderer Daten kann riskant sein!
Frank R.
@ David: Ich stehe korrigiert da! .. es ist nicht notwendig, Autonummer als Primärschlüssel zu verwenden, man kann immer noch eine indizierte serielle Spalte im Elternteil haben, die den Ersatz im Kind verbindet, um sicherzustellen, dass die Beziehung nicht getrennt wird, während eine andere vorhanden ist Spalte als sinnvolle Primärseite zum Auffinden der Zeile!
Frank R.
Letztendlich geht es um Semantik ... und Microsoft bevorzugt, dass Primärschlüssel bedeutungslos und nicht aussagekräftig sind. Die Debatten darüber toben weiter, aber ich falle in das "bedeutungsvolle" Lager. :)
David T. Macknet
9
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.
Wie weit ist zu weit? Wenn keine Daten dupliziert werden, wie können Sie diese weiterführen?
Finnw
Normalisierung ist ein Gleichgewicht zwischen dem Entfernen redundanter Daten und der Erhöhung der Flexibilität gegenüber einer verringerten Leistung und einer erhöhten Komplexität. Das richtige Gleichgewicht zu finden, erfordert Erfahrung und ändert sich im Laufe der Zeit. Siehe en.wikipedia.org/wiki/Database_normalization für Informationen darüber, wann zu denormalisieren ist
Nathan Voxland
8
Behandeln der Datenbank nur als Speichermechanismus (dh als Bibliothek verherrlichter Sammlungen) und daher ihrer Anwendung untergeordnet (Ignorieren anderer Anwendungen, die die Daten gemeinsam nutzen)
Eine Folge davon ist, dass zu viel Abfragearbeit in die Anwendung verlagert wird, anstatt sie in der Datenbank zu belassen, in die sie gehört. LINQ ist diesbezüglich besonders schlecht.
3Dave
8
Ein ORM wie Hibernate wird aus Gründen wie "Es ist zu magisch" oder "Nicht in meiner Datenbank" sofort verworfen .
Verlassen Sie sich zu stark auf ein ORM wie Hibernate und versuchen Sie, es dort einzusetzen, wo es nicht angemessen ist.
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.
Ich kann mir die Schrecken vorstellen, die in diesen Situationen auftreten ... Schemaless-Datenbanken eignen sich viel besser für Rapid Prototyping und iterative Entwicklung, aber wie alles andere ist diese Flexibilität mit verschiedenen Kompromissen verbunden.
Zsolt Török
4
a) Hardcodierung von Abfragewerten in Zeichenfolge
b) Einfügen des Datenbankabfragecodes in die Aktion "OnButtonPress" in einer Windows Forms-Anwendung
"Einfügen des DB-Abfragecodes in die Aktion" OnButtonPress "in einer Windows Form-Anwendung" Was ist hier der Datenbankfehler?
rekursiv
@recursive: Es ist eine große SQL-Injection-Schwachstelle. Jeder kann beliebiges SQL an Ihren Server senden und es wird wörtlich ausgeführt.
Bill Karwin
Einverstanden mit @recursive. Diese haben wirklich nichts mit DB-Problemen zu tun.
p.campbell
b) ist ein Architekturfehler. Das Codieren von Abfragen direkt in Ihrer App ist natürlich sowieso eine schlechte Idee.
3Dave
4
Achten Sie nicht genug auf die Verwaltung von Datenbankverbindungen in Ihrer Anwendung. Dann stellen Sie fest, dass die Anwendung, der Computer, der Server und das Netzwerk verstopft sind.
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.
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.
Eine bessere Analogie könnte sein, dass man ein Schaltgetriebe nicht richtig beheben kann, ohne eine Kupplung zu verstehen. Viele Leute fahren einen Schalthebel richtig, ohne zu wissen, wie eine Kupplung funktioniert.
Michael Easter
3
Verwenden eines ORM für Massenaktualisierungen
Mehr Daten als nötig auswählen. Wiederum normalerweise bei Verwendung eines ORM
SQL in einer Schleife abfeuern.
Keine guten Testdaten haben und Leistungseinbußen nur bei Live-Daten feststellen.
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üssenSie sehen dies häufig in ORM-generierten Abfragen. Wenn Sie sich die Protokollausgabe von Hibernate ansehen, sehen Sie, dass alle Abfragen beginnen mit:
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 :
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" :
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:
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:vs.
oder
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 :
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:
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 :
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:
Besser:
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:
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.
quelle
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.
quelle
quelle
Ü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).
quelle
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).
quelle
Keine Indizes verwenden.
quelle
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.
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.
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.
quelle
Nach meiner Erfahrung:
Keine Kommunikation mit erfahrenen Datenbankadministratoren.
quelle
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.
quelle
Vergessen, Beziehungen zwischen den Tabellen einzurichten. Ich erinnere mich, dass ich das aufräumen musste, als ich anfing, bei meinem derzeitigen Arbeitgeber zu arbeiten.
quelle
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.
quelle
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.
quelle
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.
quelle
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:
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:
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.
quelle
Für SQL-basierte Datenbanken:
... mehr hinzugefügt werden.
quelle
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.
quelle
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.
quelle
Behandeln der Datenbank nur als Speichermechanismus (dh als Bibliothek verherrlichter Sammlungen) und daher ihrer Anwendung untergeordnet (Ignorieren anderer Anwendungen, die die Daten gemeinsam nutzen)
quelle
quelle
1 - Unnötige Verwendung einer Funktion für einen Wert in einer where-Klausel, wobei das Ergebnis dieses Index nicht verwendet wird.
Beispiel:
anstatt
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.
quelle
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".quelle
Keine entsprechende SELECT-Abfrage ausführen, bevor die DELETE-Abfrage ausgeführt wird (insbesondere in Produktionsdatenbanken)!
quelle
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.
quelle
a) Hardcodierung von Abfragewerten in Zeichenfolge
b) Einfügen des Datenbankabfragecodes in die Aktion "OnButtonPress" in einer Windows Forms-Anwendung
Ich habe beide gesehen.
quelle
Achten Sie nicht genug auf die Verwaltung von Datenbankverbindungen in Ihrer Anwendung. Dann stellen Sie fest, dass die Anwendung, der Computer, der Server und das Netzwerk verstopft sind.
quelle
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.
quelle
Hier ist ein Link zum Video " Klassische Datenbankentwicklungsfehler und fünf Möglichkeiten, sie zu überwinden " von Scott Walz
quelle
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.
quelle
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.
quelle
quelle