„SELECT * FROM …“ – Was passiert da eigentlich?

Die meistgenutzte SQL-Abfrage – und gleichzeitig die gefährlichste.
Fast jeder, der schon einmal mit SQL gearbeitet hat, kennt diese Abfrage:

SELECT * FROM tabelle;

Sie ist kurz, leicht zu tippen und liefert sofort Ergebnisse. Genau deshalb ist sie so beliebt – besonders in den ersten Gehversuchen mit einer Datenbank oder wenn es schnell gehen muss.

In der Praxis sieht man SELECT * überall:

  • beim schnellen Prototyping
  • in Debug-Skripten
  • in Tools, die „einfach mal alles anzeigen“ sollen

Doch hinter dieser Bequemlichkeit lauern Probleme. Was auf den ersten Blick wie eine harmlose Standardabfrage aussieht, kann in produktiven Anwendungen zu einem echten Performance-Killer werden – und in manchen Fällen sogar ein Sicherheitsrisiko darstellen.

Das Ziel dieses Artikels: Wir schauen uns an, was wirklich passiert, wenn du SELECT * schreibst. Schritt für Schritt verfolgen wir den Lebenszyklus der Abfrage – von der Eingabe im SQL-Editor bis hin zum fertigen Resultset, das die Datenbank dir zurückgibt. Dabei decken wir auf, warum diese scheinbar harmlose Abfrage oft mehr Schaden als Nutzen bringt und wie du es besser machen kannst.

SQL * FROM

Die Anatomie der Abfrage: Syntax & Semantik

Um zu verstehen, warum SELECT * mehr ist als nur eine bequeme Abkürzung, müssen wir den Befehl in seine Einzelteile zerlegen und einen Blick auf die Prozesse werfen, die im Hintergrund ablaufen.

Zerlegung des Befehls

SELECT *: Das Sternchen ist kein „Platzhalter“, der später einfach ersetzt wird. Es ist ein Metazeichen, das der Datenbank sagt: „Hole alle sichtbaren Spalten dieser Tabelle oder View“. Welche Spalten das genau sind, hängt vom zugrunde liegenden Schema und den Benutzerrechten ab. FROM …: Dieser Teil bestimmt, aus welcher Tabelle oder View die Daten geholt werden. Der Query-Parser identifiziert hier die Datenquelle und verknüpft sie mit den Metadaten im Datenbanksystem.

Implizite Prozesse

  • Autorisierungsprüfung: Bevor die Abfrage überhaupt ausgeführt wird, prüft die Datenbank, ob der aktuelle Benutzer Lese-Rechte auf die angegebene Tabelle oder View besitzt.
  • Schema-Lookup: Das System ermittelt anhand der Metadaten, welche Spalten das * konkret umfasst. Dabei werden auch Spalten ausgeschlossen, auf die der Benutzer keinen Zugriff hat.
Schon bevor auch nur eine Datenzeile gelesen wird, hat die Datenbank also mehrere Schritte hinter sich – und jeder davon kostet Zeit und Ressourcen.

Hinter den Kulissen: Die Reise durch die Datenbank-Engine

Eine SQL-Abfrage wie SELECT * durchläuft mehrere interne Phasen, bevor du überhaupt ein Ergebnis siehst. Jede dieser Phasen hat ihre eigenen Aufgaben – und ihre eigenen Fallstricke.

Phase 1: Parsing & Validierung

  • Syntax-Check: Der Parser prüft, ob die Abfrage formal korrekt ist. Das Ergebnis ist ein sogenannter Abstract Syntax Tree (AST), der die Struktur des Befehls darstellt.
  • Metadata-Resolver: Das Sternchen wird in eine konkrete Liste von Spaltennamen aufgelöst. Dazu liest die Engine das Schema der Tabelle oder View.

Phase 2: Optimierung

Jetzt versucht der Optimizer, die Abfrage so effizient wie möglich auszuführen. SELECT * macht ihm diese Arbeit oft schwer:
  • Kein Column Pruning: Die Engine kann keine unnötigen Spalten weglassen, weil du explizit alle angefordert hast.
  • Blockierte Index-Only-Scans: Wenn nicht alle Spalten im Index enthalten sind, muss die Engine zusätzliche Daten aus dem Hauptspeicher oder von der Festplatte laden.
Am Ende erzeugt der Optimizer einen Execution Plan – z. B. einen Full Table Scan oder einen Index Scan, je nach Daten und Indizes.

Phase 3: Ausführung

  • Daten-Retrieval: Die Engine liest die benötigten Datenseiten aus dem Speicher (Buffer Pool) oder von der Festplatte (Heap Files, Pages).
  • Resultset-Konstruktion: Im Arbeitsspeicher wird das Ergebnis vorbereitet, bevor es an den Client gesendet wird.
Auch wenn dieser Ablauf in Millisekunden geschieht, summieren sich ineffiziente Abfragen in großen Systemen schnell zu einem spürbaren Performanceproblem.

Die versteckten Kosten von SELECT *

Auf den ersten Blick scheint SELECT * unschuldig – doch in der Praxis bringt es oft mehr Kosten als Nutzen. Diese versteckten Nachteile zeigen sich vor allem in produktiven Systemen.

Performance-Fallen

  • Netzwerk-Last: Jede unnötige Spalte erhöht die Menge an Daten, die vom Server zum Client übertragen werden muss – besonders kritisch bei großen BLOBs oder Textfeldern.
  • Cache-Ineffizienz: Durch überflüssige Daten werden wertvolle Plätze im Buffer Pool belegt, sodass wirklich relevante Daten schneller verdrängt werden.

Sicherheitsrisiken

  • Unbeabsichtigtes Auslesen sensibler Daten: Mit SELECT * kannst du leicht Spalten wie Passwörter, API-Keys oder personenbezogene Daten (PII) in den Ergebnissen haben – auch wenn du sie gar nicht benötigst.

Wartungs-Albtraum

  • Anfälligkeit bei Schema-Änderungen: Wenn neue Spalten hinzugefügt werden, ändert sich die Struktur des Resultsets – das kann bestehende Anwendungen oder Integrationen unbemerkt brechen.

Diese Probleme machen SELECT * in produktiven Umgebungen riskant. Die Bequemlichkeit beim Schreiben der Abfrage kann dich später teuer zu stehen kommen.

Wann ist SELECT * trotzdem sinnvoll?

Auch wenn SELECT * oft problematisch ist, gibt es Situationen, in denen es durchaus legitim und sogar praktisch sein kann – vorausgesetzt, die Rahmenbedingungen stimmen.

Legitime Anwendungsfälle

  • Ad-hoc-Analysen: Wenn du in einem CLI-Tool oder einer SQL-Konsole schnell alle Daten sehen möchtest, ohne den Query langfristig zu speichern.
  • CTEs oder Subqueries mit fest definiertem Schema: Wenn du weißt, dass die Spaltenliste unverändert bleibt, kann SELECT * innerhalb dieser isolierten Abfrage vertretbar sein.
  • Schema-Migrationstests: Um sicherzustellen, dass alle Spalten wie erwartet vorhanden und lesbar sind.

Die goldene Regel

Nutze SELECT * nur in kontrollierten Umgebungen – niemals im produktiven Anwendungscode. Dort sollte immer eine explizite Spaltenliste stehen.

Best Practices: Alternativen & Optimierungen

Um die Risiken und Performance-Probleme von SELECT * zu vermeiden, gibt es erprobte Best Practices. Sie helfen, die Abfragen effizient, sicher und wartbar zu gestalten.

Präzise Spaltenlisten

Anstatt alles auszuwählen, definiere explizit, welche Spalten du brauchst:

SELECT id, name, email FROM users;

Vorteile:

  • Reduzierung von I/O und Netzwerktraffic
  • Ermöglicht Index-Only-Scans, wenn alle Spalten im Index enthalten sind
  • Erhöht die Wartbarkeit und Vorhersagbarkeit der Abfrage

Views für häufige Zugriffe

Wenn du regelmäßig bestimmte Spalten benötigst, lohnt sich eine View:

CREATE VIEW v_users AS
SELECT id, name, email
FROM users;

Die Anwendung kann dann die View abfragen, ohne jedes Mal SELECT * zu verwenden, und du behältst die Kontrolle über die ausgewählten Spalten.

Tools & Tricks

  • SQL-IDEs mit Auto-Vervollständigung: Hilft, die Versuchung zu vermeiden, * zu nutzen, weil alle Spalten leicht auswählbar sind.
  • EXPLAIN PLAN: Analysiere Execution Plans für SELECT * vs. explizite Spalten, um Optimierungspotenzial zu erkennen.

Zusammenfassung & Key Takeaways

SELECT * ist praktisch, aber oft riskant. Man könnte sagen: Es ist wie Wildschießen – man trifft vieles, aber selten das Richtige.

Kernbotschaften

  • Performance: * bedeutet Daten-Overfetching und kann Abfragen stark verlangsamen.
  • Sicherheit: Implizites Auslesen von Metadaten kann sensible Informationen unabsichtlich preisgeben.
  • Robustheit: Explizite Spaltenlisten machen deinen Code widerstandsfähig gegen Schema-Änderungen und unerwartete Resultset-Layouts.

Fazit: Nutze SELECT * nur in kontrollierten, temporären Szenarien. In produktiven Anwendungen solltest du immer genau die Spalten auswählen, die du wirklich benötigst.