it-swarm.com.de

Warum wird SELECT * als schädlich eingestuft?

Warum ist SELECT * schlechte Praxis? Wäre es nicht weniger Code, der geändert werden müsste, wenn Sie eine neue Spalte hinzufügen, die Sie wollten?

Ich verstehe, dass SELECT COUNT(*) ein Leistungsproblem in einigen DBs ist, aber was wäre, wenn Sie wirklich jede Spalte wollten?

214

Es gibt wirklich drei Hauptgründe:

  • Ineffizienz beim Übertragen von Daten an den Verbraucher. Wenn Sie * auswählen, rufen Sie oft mehr Spalten aus der Datenbank ab, als Ihre Anwendung wirklich funktionieren muss. Dies führt dazu, dass mehr Daten vom Datenbankserver auf den Client übertragen werden, wodurch der Zugriff verlangsamt und die Auslastung Ihrer Maschinen erhöht wird. Außerdem nimmt das Netzwerk mehr Zeit in Anspruch. Dies ist insbesondere der Fall, wenn jemand neue Tabellen zu zugrundeliegenden Tabellen hinzufügt, die nicht vorhanden waren und nicht benötigt wurden, als die ursprünglichen Verbraucher ihren Datenzugriff codierten.

  • Probleme bei der Indexierung. Stellen Sie sich ein Szenario vor, in dem Sie eine Abfrage auf ein hohes Leistungsniveau abstimmen möchten. Wenn Sie * verwenden und mehr Spalten zurückgeben würden, als Sie tatsächlich benötigten, müsste der Server häufig aufwendigere Methoden zum Abrufen Ihrer Daten verwenden, als dies ansonsten der Fall wäre. Beispielsweise können Sie keinen Index erstellen, der einfach die Spalten in Ihrer SELECT-Liste abdeckt, und selbst wenn Sie (einschließlich aller Spalten [shudder]) den nächsten Typ, der gekommen ist, gefunden haben Wenn Sie der zugrundeliegenden Tabelle eine Spalte hinzufügen, ignoriert das Optimierungsprogramm Ihren optimierten Deckungsindex, und Sie werden wahrscheinlich feststellen, dass die Leistung Ihrer Abfrage ohne erkennbaren Grund erheblich sinkt.

  • Bindungsprobleme. Wenn Sie * auswählen, können Sie zwei Spalten mit demselben Namen aus zwei verschiedenen Tabellen abrufen. Dies kann Ihren Datenverbraucher oft zum Absturz bringen. Stellen Sie sich eine Abfrage vor, die zwei Tabellen verbindet, die beide eine Spalte namens "ID" enthalten. Wie würde ein Verbraucher wissen, welcher welcher war? SELECT * kann auch Ansichten verwirren (zumindest in einigen Versionen von SQL Server), wenn zugrunde liegende Tabellenstrukturen geändert werden - Die Ansicht wird nicht neu erstellt, und die zurückkommenden Daten können Unsinn sein . Und das Schlimmste daran ist, dass Sie darauf achten können, Ihre Spalten zu benennen, wie Sie möchten, aber der nächste Typ, der mitkommt, hat möglicherweise keine Möglichkeit zu wissen, dass er sich Sorgen machen muss, eine Spalte hinzuzufügen, die mit Ihrer bereits entwickelten zusammenstößt Namen.

Aber es ist nicht alles schlecht für SELECT *. Ich verwende es großzügig für diese Anwendungsfälle:

  • Ad-hoc-Anfragen. Beim Versuch, etwas zu debuggen, vor allem an einem schmalen Tisch, mit dem ich vielleicht nicht vertraut bin, ist SELECT * oft mein bester Freund. Es hilft mir, einfach zu sehen, was los ist, ohne eine gründliche Recherche über die zugrunde liegenden Spaltennamen durchführen zu müssen. Je länger die Spaltennamen werden, desto größer ist das "Plus".

  • When * bedeutet "eine Reihe". In den folgenden Anwendungsfällen ist SELECT * in Ordnung, und die Gerüchte, dass es sich um einen Leistungskiller handelt, sind nur städtische Legenden, die vor vielen Jahren Gültigkeit gehabt haben könnten, aber jetzt nicht:

    SELECT COUNT(*) FROM table;
    

    in diesem Fall bedeutet * "Zeilen zählen". Wenn Sie anstelle von * einen Spaltennamen verwenden würden, würde würde die Zeilen zählen, in denen der Spaltenwert nicht null war. COUNT (*) setzt für mich wirklich das Konzept, dass Sie Zeilen zählen, und Sie vermeiden seltsame Edge-Fälle, die durch das Entfernen von NULL-Werten aus Ihren Aggregaten verursacht werden. 

    Dasselbe gilt für diese Art von Abfrage:

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);
    

    * * * * * * * * * * * * * In jeder Datenbank, die es wert ist, bedeutet "Salz" nur "eine Reihe". Es ist egal, was Sie in die Unterabfrage stellen. Einige Leute verwenden die b-ID in der SELECT-Liste oder sie verwenden die Nummer 1. Aber diese Konventionen sind im IMO ziemlich unsinnig. Was Sie damit meinen, ist "Zähle die Reihe", und das bedeutet *. Die meisten Abfrageoptimierer sind intelligent genug, um dies zu wissen. (Obwohl ich, um ehrlich zu sein, nur know dies für SQL Server und Oracle wahr ist.)

279
Dave Markle

Das Sternchen "*" in der SELECT-Anweisung ist eine Abkürzung für alle Spalten in der Tabelle, die an der Abfrage beteiligt sind. 

Performance

Die *-Abkürzung kann langsamer sein, weil:

  • Nicht alle Felder sind indiziert, so dass eine vollständige Überprüfung der Tabelle erforderlich ist - weniger effizient
  • Was Sie zum Versenden von SELECT * über das Kabel speichern, kann einen vollständigen Tabellenscan erfordern
  • Rückgabe von mehr Daten als erforderlich
  • Die Rückgabe von nachfolgenden Spalten mit dem Datentyp mit variabler Länge kann zu einem Suchaufwand führen

Instandhaltung

Bei Verwendung von SELECT *:

  • Jemand, der mit der Codebase nicht vertraut ist, würde gezwungen sein, in der Dokumentation nachzusehen, welche Spalten zurückgegeben werden, bevor er kompetente Änderungen vornehmen kann. Den Code lesbarer zu machen, die Mehrdeutigkeit und Arbeit zu minimieren, die für Personen erforderlich sind, die nicht mit dem Code vertraut sind, spart auf lange Sicht mehr Zeit und Aufwand.
  • Wenn der Code von der Spaltenreihenfolge abhängt, wird mit SELECT * ein Fehler ausgeblendet, der wartet, wenn eine Spaltenreihenfolge einer Tabelle geändert wurde.
  • Auch wenn Sie zum Zeitpunkt der Abfrage jede Spalte benötigen, ist dies in der Zukunft möglicherweise nicht der Fall
  • die Verwendung erschwert die Profilerstellung

Design

SELECT * ist einanti-pattern:

  • Der Zweck der Abfrage ist weniger offensichtlich. Die von der Anwendung verwendeten Spalten sind undurchsichtig
  • Dabei wird die Modularitätsregel gebrochen, wann immer dies möglich ist. Explicit ist fast überall besser. 

Wann sollte "SELECT *" verwendet werden?

Es ist akzeptabel, SELECT * zu verwenden, wenn explizit jede Spalte in der betreffenden Tabelle benötigt wird, im Gegensatz zu jeder Spalte, die zum Zeitpunkt der Abfrage vorhanden war. Die Datenbank erweitert intern * in die vollständige Spaltenliste - es gibt keinen Leistungsunterschied.

Andernfalls listen Sie explizit jede Spalte auf, die in der Abfrage verwendet werden soll - vorzugsweise während eines Tabellenalias.

84
OMG Ponies

Selbst wenn Sie jetzt jede Spalte auswählen möchten, möchten Sie möglicherweise nicht jede Spalte auswählen, nachdem jemand eine oder mehrere neue Spalten hinzugefügt hat. Wenn Sie die Abfrage mit SELECT * schreiben, gehen Sie das Risiko ein, dass irgendwann jemand eine Textspalte hinzufügt, wodurch die Abfrage langsamer ausgeführt wird, obwohl Sie diese Spalte nicht wirklich benötigen.

Wäre es nicht weniger Code, der geändert werden müsste, wenn Sie eine neue Spalte hinzufügen, die Sie wollten?

Die Chancen stehen gut, dass Sie, wenn Sie die neue Spalte tatsächlich verwenden möchten, trotzdem einige andere Änderungen an Ihrem Code vornehmen müssen. Sie speichern nur , new_column - nur ein paar Zeichen der Eingabe.

18
Mark Byers

Wenn Sie die Spalten in einer SELECT-Anweisung benennen, werden sie in der angegebenen Reihenfolge zurückgegeben und können daher sicher über den numerischen Index referenziert werden. Wenn Sie "SELECT *" verwenden, erhalten Sie die Spalten möglicherweise in beliebiger Reihenfolge und können die Spalten daher nur nach Name verwenden. Wenn Sie nicht im Voraus wissen, was Sie mit einer neuen Spalte tun möchten, die in die Datenbank eingefügt wird, ist es wahrscheinlich, dass Sie diese ignorieren. Wenn Sie neue Spalten ignorieren, die der Datenbank hinzugefügt werden, hat das Abrufen von Spalten keinerlei Vorteile.

4
supercat

Stellen Sie sich vor, dass die Kopplung zwischen der App und der Datenbank reduziert wird.

Um den Aspekt des Codegeruchs zusammenzufassen:
SELECT * erstellt eine dynamische Abhängigkeit zwischen der App und dem Schema. Das Einschränken der Verwendung ist eine Möglichkeit, die Abhängigkeit genauer zu definieren. Andernfalls besteht bei einer Änderung der Datenbank die Wahrscheinlichkeit, dass die Anwendung abstürzt. 

3
Kelly S. French

In vielen Situationen verursacht SELECT * Fehler zur Laufzeit in Ihrer Anwendung und nicht zur Entwurfszeit. Es verbirgt das Wissen über Spaltenänderungen oder fehlerhafte Verweise in Ihren Anwendungen.

3
Andrew Lewis

Wenn Sie wirklich jede Spalte wünschen, habe ich keinen Leistungsunterschied zwischen select (*) und Benennung der Spalten gesehen. Der Treiber für die Benennung der Spalten kann lediglich dazu dienen, explizit anzugeben, welche Spalten Sie in Ihrem Code erwarten.

Oft möchten Sie jedoch nicht jede Spalte, und select (*) kann zu unnötigen Arbeiten für den Datenbankserver führen und unnötige Informationen müssen über das Netzwerk geleitet werden. Es ist unwahrscheinlich, dass ein wahrnehmbares Problem auftritt, wenn das System nicht stark ausgelastet ist oder die Netzwerkverbindung langsam ist.

3
brabster

Wenn Sie der Tabelle Felder hinzufügen, werden diese automatisch in alle Ihre Abfragen eingefügt, in denen Sie select * verwenden. Dies mag praktisch erscheinen, aber dadurch wird Ihre Anwendung langsamer, da Sie mehr Daten abrufen, als Sie benötigen, und tatsächlich wird Ihre Anwendung irgendwann abstürzen.

Die Anzahl der Daten, die Sie in jeder Zeile eines Ergebnisses abrufen können, ist begrenzt. Wenn Sie Ihren Tabellen Felder hinzufügen, sodass das Ergebnis diese Grenze überschreitet, wird eine Fehlermeldung angezeigt, wenn Sie versuchen, die Abfrage auszuführen.

Dies ist die Art von Fehlern, die schwer zu finden sind. Sie nehmen eine Änderung an einem Ort vor, der an einem anderen Ort explodiert, an dem die neuen Daten nicht verwendet werden. Es kann sogar eine weniger häufig verwendete Abfrage sein, so dass es eine Weile dauert, bis jemand sie verwendet, was es noch schwieriger macht, den Fehler mit der Änderung zu verbinden.

Wenn Sie angeben, welche Felder Sie im Ergebnis wünschen, sind Sie vor dieser Art von Overhead-Überlauf geschützt.

3
Guffa

Im Allgemeinen müssen Sie die Ergebnisse Ihres SELECT * ... in Datenstrukturen verschiedener Typen einpassen. Wenn Sie nicht angeben, in welcher Reihenfolge die Ergebnisse eintreffen, kann es schwierig sein, alles richtig aufzustellen (und obskure Felder sind viel einfacher zu übersehen).

Auf diese Weise können Sie Ihren Tabellen (auch in der Mitte) aus verschiedenen Gründen Felder hinzufügen, ohne den SQL-Zugriffscode in der gesamten Anwendung zu beschädigen.

1
jkerian

Wenn Sie SELECT * verwenden, wenn Sie nur ein paar Spalten benötigen, bedeutet dies, dass mehr Daten übertragen werden, als Sie benötigen. Dadurch wird die Datenbank verarbeitet und die Latenz beim Abrufen der Daten an den Client erhöht. Hinzu kommt, dass beim Laden mehr Speicherplatz benötigt wird, in manchen Fällen sogar erheblich mehr, beispielsweise bei großen BLOB-Dateien. Dabei geht es hauptsächlich um die Effizienz.

Darüber hinaus ist es bei der Abfrage einfacher zu erkennen, welche Spalten geladen werden, ohne nachsehen zu müssen, was in der Tabelle enthalten ist.

Ja, wenn Sie eine zusätzliche Spalte hinzufügen, wäre dies schneller, aber in den meisten Fällen möchten/müssen Sie Ihren Code mithilfe der Abfrage ändern, um die neuen Spalten trotzdem zu akzeptieren, und es besteht die Möglichkeit, dass Sie den von Ihnen erstellten bekommen. t wollen/können Probleme verursachen. Wenn Sie beispielsweise alle Spalten abrufen, verlassen Sie sich bei der Zuweisung von Variablen auf die Reihenfolge in einer Schleife, fügen Sie dann eine hinzu, oder ändern Sie die Spaltenreihenfolge (oder sehen Sie, dass dies beim Wiederherstellen aus einem Backup der Fall ist), kann alles abgeworfen werden.

Dies ist auch die gleiche Begründung, weshalb Sie bei einer INSERT immer die Spalten angeben sollten.

1
Tarka

Ich glaube nicht, dass es wirklich eine generelle Regel geben kann. In vielen Fällen habe ich SELECT * vermieden, aber ich habe auch mit Datenframeworks gearbeitet, bei denen SELECT * sehr vorteilhaft war.

Wie bei allen Dingen gibt es Nutzen und Kosten. Ich denke, dass ein Teil der Nutzen-Kosten-Gleichung darin besteht, wie viel Kontrolle Sie über die Datenstrukturen haben. In Fällen, in denen SELECT * gut funktionierte, wurden die Datenstrukturen streng kontrolliert (es handelte sich um Software für den Einzelhandel). Es bestand also kein großes Risiko, dass jemand ein riesiges BLOB-Feld in eine Tabelle sneek. 

1
JMarsch

Referenz aus diesem Artikel.

Gehen Sie niemals mit "SELECT *"

Ich habe nur einen Grund gefunden, "SELECT *" zu verwenden.

Wenn Sie spezielle Anforderungen haben und eine dynamische Umgebung erstellt haben, wird die Spalte beim Hinzufügen oder Löschen automatisch durch Anwendungscode behandelt. In diesem speziellen Fall müssen Sie den Anwendungs- und Datenbankcode nicht ändern. Dies wirkt sich automatisch auf die Produktionsumgebung aus. In diesem Fall können Sie „SELECT *“ verwenden.

1
Anvesh

GRÜNDE, WARUM NICHT ZU VERWENDEN? SELECT * FROM TABLE: -

  1. Unnötige E/A

  2. Erhöhen Sie den Netzwerkverkehr

  3. Fragile Ansichten

  4. Konflikt bei Join-Abfragen

  5. Mehr Anwendungsspeicher

  6. Riskant beim Kopieren von Daten

  7. Hängt von der Spaltenreihenfolge ab

Verwenden Sie immer Spaltennamen, um eine Datenbank mit großem Umfang zu erhalten.

0
shaurya uppal

Verstehen Sie Ihre Anforderungen vor dem Entwurf des Schemas (wenn möglich).

Erfahren Sie mehr über die Daten, 1) Indizierung 2) Art des verwendeten Speichers, 3) Vendor Engine oder Features; dh ... Zwischenspeicherung, speicherinterne Funktionen 4) Datentypen 5) Größe der Tabelle 6) Häufigkeit der Abfrage 7) zugehörige Workloads, wenn die Ressource gemeinsam genutzt wird 8) Test

A) Die Anforderungen variieren. Wenn die Hardware die erwartete Workload nicht unterstützen kann, sollten Sie erneut prüfen, wie die Anforderungen in der Workload bereitgestellt werden. Bezüglich der Additionsspalte zur Tabelle. Wenn die Datenbank Ansichten unterstützt, können Sie eine indizierte (?) Ansicht der spezifischen Daten mit den bestimmten benannten Spalten erstellen (vs. '*' auswählen). Überprüfen Sie regelmäßig Ihre Daten und Ihr Schema, um sicherzustellen, dass Sie niemals das Syndrom "Garbage-in" -> "Garbage-out" treffen.

Angenommen, es gibt keine andere Lösung; Sie können Folgendes berücksichtigen. Es gibt immer mehrere Lösungen für ein Problem.

1) Indizierung: Der select * führt einen Tablescan aus. Abhängig von verschiedenen Faktoren kann dies eine Suche nach einem Datenträger und/oder einen Konflikt mit anderen Abfragen beinhalten. Wenn die Tabelle mehrzweckfähig ist, stellen Sie sicher, dass alle Abfragen performant sind und unter Ihren Zielzeiten ausgeführt werden. Wenn eine große Datenmenge vorhanden ist und das Netzwerk oder die andere Ressource nicht abgestimmt ist; Sie müssen dies berücksichtigen. Die Datenbank ist eine gemeinsam genutzte Umgebung.

2) Art der Lagerung. Dh: wenn Sie SSDs, Festplatten oder Speicher verwenden. I/O-Zeiten und die Belastung des Systems/der CPU variieren.

3) Kann der Datenbankadministrator die Datenbank/Tabellen auf höhere Leistung einstellen? Aus welchem ​​Grund auch immer, die Teams haben entschieden, dass das '*' die beste Lösung für das Problem ist. kann der DB oder die Tabelle in den Speicher geladen werden. (Oder eine andere Methode ... vielleicht wurde die Antwort darauf ausgelegt, mit einer Verzögerung von 2-3 Sekunden zu reagieren? ---, während eine Anzeige abgespielt wird, um den Umsatz des Unternehmens zu erzielen ...)

4) Beginnen Sie an der Grundlinie. Verstehen Sie Ihre Datentypen und wie die Ergebnisse dargestellt werden. Kleinere Datentypen, Anzahl der Felder, reduzieren die in der Ergebnismenge zurückgegebene Datenmenge. Dadurch stehen Ressourcen für andere Systemanforderungen zur Verfügung. Die Systemressourcen haben normalerweise ein Limit. 'immer' arbeiten unterhalb dieser Grenzen, um Stabilität und vorhersehbares Verhalten zu gewährleisten.

5) Größe der Tabelle/Daten. select '*' ist bei kleinen Tabellen üblich. Sie passen normalerweise in den Speicher und die Antwortzeiten sind schnell. Nochmal ... überprüfen Sie Ihre Anforderungen. Planen für das Feature-Kriechen; Planen Sie immer für die aktuellen und möglichen zukünftigen Bedürfnisse. 

6) Häufigkeit von Anfragen/Abfragen. Beachten Sie andere Workloads im System. Wenn diese Abfrage jede Sekunde ausgelöst wird und die Tabelle klein ist. Die Ergebnismenge kann so gestaltet werden, dass sie im Cache/Speicher bleibt. Wenn es sich bei der Abfrage jedoch um einen häufigen Stapelprozess mit Gigabytes/Terabytes an Daten handelt, sollten Sie möglicherweise zusätzliche Ressourcen bereitstellen, um sicherzustellen, dass andere Workloads nicht betroffen sind.

7) Zugehörige Workloads. Verstehen, wie die Ressourcen verwendet werden. Ist das Netzwerk/System/die Datenbank/Tabelle/Anwendung dediziert oder wird es gemeinsam genutzt? Wer sind die Stakeholder? Ist das für Produktion, Entwicklung oder Qualitätssicherung? Ist dies eine vorübergehende "schnelle Lösung"? Hast du das Szenario getestet? Sie werden überrascht sein, wie viele Probleme die aktuelle Hardware heute haben kann. (Ja, die Leistung ist schnell ... aber das Design/die Leistung wird immer noch beeinträchtigt.) Muss das System 10-KB-Abfragen pro Sekunde ausführen, gegenüber 5-10 Abfragen pro Sekunde. Ist der Datenbankserver dediziert oder führen andere Anwendungen eine Überwachung der gemeinsam genutzten Ressource durch. Einige Anwendungen/Sprachen; O/S verbraucht 100% des Speichers, was zu verschiedenen Symptomen/Problemen führt.

8) Test: Testen Sie Ihre Theorien und verstehen Sie so viel wie möglich. Ihr ausgewähltes '*' - Problem kann eine große Sache sein oder es ist etwas, worüber Sie sich nicht einmal Sorgen machen müssen.

0
kllee

Es gibt auch einen pragmatischeren Grund: Geld. Wenn Sie die Cloud-Datenbank verwenden und für die verarbeiteten Daten bezahlen müssen, gibt es keine Erklärung für das Lesen von Daten, die Sie sofort löschen werden.

Zum Beispiel: BigQuery :

Preisanfrage

Abfragepreise beziehen sich auf die Kosten für die Ausführung Ihrer SQL-Befehle und benutzerdefinierten Funktionen. BigQuery berechnet für Abfragen eine Metrik: die Anzahl der verarbeiteten Bytes.

und Projektion kontrollieren - SELECT * vermeiden :

Best Practice: Projektion steuern - Nur die Spalten abfragen, die Sie benötigen.

Die Projektion bezieht sich auf die Anzahl der Spalten, die von Ihrer Abfrage gelesen werden. Beim Projizieren von überschüssigen Spalten entstehen zusätzliche (verschwendete) E/A und Materialisierung (Schreibergebnisse).

Die Verwendung von SELECT * ist die teuerste Methode zum Abfragen von Daten. Wenn Sie SELECT * verwenden, führt BigQuery eine vollständige Prüfung aller Spalten in der Tabelle durch.

0
Lukasz Szozda

Die Auswahl mit dem Spaltennamen erhöht die Wahrscheinlichkeit, dass das Datenbankmodul auf die Daten aus Indizes zugreifen kann, anstatt die Tabellendaten abzufragen.

SELECT * setzt Ihr System unerwarteten Leistungs- und Funktionsänderungen vor, wenn sich das Datenbankschema ändert, da der Tabelle neue Spalten hinzugefügt werden, obwohl Ihr Code nicht bereit ist, diese neuen Daten zu verwenden oder zu präsentieren.

0