Datenbankentwickler haben es nicht leicht, ganz egal, ob sie SQL Server, Oracle, DB2, MySQL, PostgreSQL oder SQLite verwenden. Immerhin sind die Herausforderungen ähnlich. Insbesondere schlecht geschriebene Abfragen können eigentlich vorteilhafte Datenbankfunktionen zunichtemachen und dazu führen, dass Systemressourcen ohne Not verschwendet werden.
Im Folgenden lesen Sie, welche SQL-, beziehungsweise Datenbank-Verfehlungen Sie vermeiden sollten, damit Ihnen das erspart bleibt.
1. Blind abfragen
In der Regel ist eine SQL Query darauf ausgelegt, die Daten abzurufen, die für einen bestimmten Task nötig sind. Wenn Sie eine Abfrage wiederverwenden, die für die meisten Ihrer Use Cases geeignet ist, mag das zunächst von außen betrachtet ganz gut funktionieren. Es kann jedoch sein, dass "unter der Haube" zu viele Daten abgefragt werden, was zu Lasten von Performance und Ressourcen geht - sich aber erst dann bemerkbar macht, wenn skaliert werden soll.
Empfehlung: Prüfen Sie Queries, die wiederverwendet werden sollen, und passen Sie diese an den jeweiligen Anwendungsfall an.
2. Views verschachteln
Views bieten eine standardisierte Möglichkeit, Daten zu betrachten und ersparen den Benutzern, sich mit komplexen Queries beschäftigen zu müssen. Wenn Views allerdings dazu genutzt werden, um andere Views abzufragen ("Nesting views"), wird es problematisch. Views zu verschachteln, zieht gleich mehrere Nachteile nach sich:
Es werden mehr Daten abgefragt als nötig.
Es verschleiert den Arbeitsaufwand, der nötig ist, um einen bestimmten Datensatz abzufragen.
Es erschwert dem Optimizer, die resultierenden Queries zu optimieren.
Empfehlung: Sehen Sie davon ab, Views zu verschachteln. Es empfiehlt sich, bestehende Verschachtelungen umzuschreiben, um nur die jeweils benötigten Daten abzufragen.
3. All-in-One-Transaktionen
Angenommen, Sie wollen Daten aus zehn Tabellen löschen. In dieser Situation könnten Sie der Versuchung erliegen, sämtliche Löschvorgänge in einer einzigen Transaktion durchzuführen. Lassen Sie es.
Empfehlung: Behandeln Sie stattdessen die Operationen für jede Tabelle separat. Wenn Sie Löschvorgänge über Tabellen hinweg atomar ausführen müssen, können Sie diese in viele kleinere Transaktionen aufsplitten. Wenn Sie beispielsweise 10.000 Zeilen in 20 Tabellen löschen müssen, können Sie die ersten tausend Zeilen in einer Transaktion für alle 20 Tabellen löschen, dann die nächsten tausend in einer weiteren Transaktion - und so weiter. Das ist ein guter Anwendungsfall für einen Task-Queue-Mechanismus in Ihrer Geschäftslogik, mit dem sich solche Vorgänge managen lassen.
4. Volatil clustern
Global Unique Identifiers (GUIDs) sind Zufallszahlen und dienen dazu, Objekten eine eindeutige Kennung zuzuweisen. Diverse Datenbanken unterstützen dieses Schema als nativen Spaltentyp. GUIDs sollten allerdings nicht verwendet werden, um die Zeilen, in denen sie enthalten sind, zu clustern. Da es sich um Zufallszahlen handelt, führt das dazu, dass die Tabelle durch das Clustering stark fragmentiert wird. Das kann wiederum dazu führen, dass Tabellenoperationen um mehrere Größenordnungen langsamer laufen.
Empfehlung: Clustern Sie nicht auf Spalten mit hohem Randomness-Anteil. Beschränken Sie sich auf Datums- oder ID-Spalten - das funktioniert am besten.
5. Zeilen ineffizient zählen
Um zu bestimmen, ob bestimmte Daten innerhalb einer Tabelle existieren, sind Befehle wie SELECT COUNT(ID) FROM table1
oft ineffizient. Einige Datenbanken sind zwar in der Lage, SELECT COUNT()
-Operationen intelligent zu optimieren, aber eben nicht alle. Der bessere Ansatz (wenn Ihr SQL-Dialekt das unterstützt):
IF EXISTS (SELECT 1 from table1 LIMIT 1) BEGIN ... END
Empfehlung: Wenn es Ihnen um die Anzahl der Zeilen geht, können Sie auch eine entsprechende Statistiken aus der Systemtabelle abrufen. Einige Datenbankanbieter ermöglichen auch spezielle Queries: In MySQL können Sie mit SHOW TABLE STATUS
beispielsweise Statistiken über alle Tabellen einholen - einschließlich der Zeilenzahl.
6. Trigger falsch nutzen
Trigger sind praktisch, weisen aber eine wesentliche Einschränkung auf: Sie müssen in derselben Transaktion wie die ursprüngliche Operation ausgeführt werden. Wenn Sie einen Trigger erstellen, um eine Tabelle zu ändern, während eine andere Tabelle geändert wird, werden beide gesperrt - zumindest, bis der Trigger beendet ist.
Empfehlung: Wenn Sie einen Trigger verwenden müssen, stellen Sie sicher, dass er nicht mehr Ressourcen sperrt, als vertretbar ist. Ein gespeicherter Prozess könnte an dieser Stelle die bessere Lösung sein - er kann Trigger-ähnliche Operationen über mehrere Transaktionen hinweg unterbrechen.
7. Negativ abfragen
SELECT * FROM Users WHERE Users.Status <> 2
- eine Query wie diese ist problematisch. Ein Index für die Spalte "Users.Status
" ist zwar nützlich, allerdings führen solche negativen Suchabfragen für gewöhnlich zu einem Tabellenscan.
Empfehlung: Die bessere Lösung besteht darin, Ihre Abfragen so zu gestalten, die Indizes effizient nutzen. Zum Beispiel: SELECT * FROM Users WHERE User.ID NOT IN (Select Users.ID FROM USERS WHERE Users.Status=2).
Auf diese Weise können Sie die Indizes für die ID- und Status-Spalten nutzen, um nicht benötigte Daten herauszufiltern - ohne Tabellen zu scannen. (fm)
Dieser Beitrag basiert auf einem Artikel unserer US-Schwesterpublikation Infoworld.