Warum ist SELECT *
schlechte Praxis? Würde es nicht bedeuten, dass weniger Code geändert werden muss, wenn Sie eine neue Spalte hinzufügen, die Sie möchten?
Ich verstehe, dass dies SELECT COUNT(*)
bei einigen DBs ein Leistungsproblem ist, aber was ist, wenn Sie wirklich jede Spalte wollen?
SELECT COUNT(*)
schlecht zu sein ist unglaublich alt und veraltet . Für Informationen überSELECT *
- siehe: stackoverflow.com/questions/1960036/…SELECT COUNT(*)
gibt eine andere Antwort als, esSELECT COUNT(SomeColumn)
sei denn, die Spalte ist eine NOT NULL-Spalte. Und der Optimierer kann eineSELECT COUNT(*)
spezielle Behandlung geben - und das normalerweise auch. Beachten Sie auch, dassWHERE EXISTS(SELECT * FROM SomeTable WHERE ...)
eine Sonderfallbehandlung erfolgt.Antworten:
Es gibt wirklich drei Hauptgründe:
Ineffizienz beim Verschieben von Daten zum Verbraucher. Wenn Sie SELECT * auswählen, rufen Sie häufig mehr Spalten aus der Datenbank ab, als Ihre Anwendung wirklich benötigt, um zu funktionieren. Dies führt dazu, dass mehr Daten vom Datenbankserver auf den Client übertragen werden, wodurch der Zugriff verlangsamt und die Belastung Ihrer Computer erhöht wird. Außerdem wird mehr Zeit für die Übertragung über das Netzwerk benötigt. Dies gilt insbesondere dann, wenn jemand zugrunde liegenden Tabellen neue Spalten hinzufügt, die nicht vorhanden waren und nicht benötigt wurden, als die ursprünglichen Verbraucher ihren Datenzugriff codierten.
Indizierungsprobleme. Stellen Sie sich ein Szenario vor, in dem Sie eine Abfrage auf ein hohes Leistungsniveau einstellen möchten. Wenn Sie * verwenden und mehr Spalten zurückgeben, als Sie tatsächlich benötigen, muss der Server häufig teurere Methoden zum Abrufen Ihrer Daten ausführen, als dies sonst der Fall wäre. Zum Beispiel könnten Sie keinen Index erstellen, der einfach die Spalten in Ihrer SELECT-Liste abdeckt, und selbst wenn Sie dies tun würden (einschließlich aller Spalten [ Schauder ]), der nächste, der vorbeikam und dem zugrunde liegenden eine Spalte hinzufügte Eine Tabelle würde dazu führen, dass das Optimierungsprogramm Ihren optimierten Abdeckungsindex ignoriert, und Sie würden wahrscheinlich feststellen, dass die Leistung Ihrer Abfrage ohne ersichtlichen Grund erheblich sinken würde.
Bindungsprobleme. Wenn Sie SELECT * auswählen, können Sie zwei gleichnamige Spalten aus zwei verschiedenen Tabellen abrufen. Dies kann Ihren Datenkonsumenten oft zum Absturz bringen. Stellen Sie sich eine Abfrage vor, die zwei Tabellen verbindet, die beide eine Spalte mit dem Namen "ID" enthalten. Wie würde ein Verbraucher wissen, welches welches war? SELECT * kann auch Ansichten verwirren (zumindest in einigen Versionen von SQL Server), wenn sich die zugrunde liegenden Tabellenstrukturen ändern - die Ansicht wird nicht neu erstellt, und die Daten, die zurückkommen, können Unsinn sein . Und das Schlimmste daran ist, dass Sie darauf achten können, Ihre Spalten so zu benennen, wie Sie möchten, aber der nächste, der mitkommt, kann möglicherweise nicht wissen, dass er sich Sorgen machen muss, eine Spalte hinzuzufügen, die mit Ihrer bereits entwickelten kollidiert Namen.
Aber es ist nicht alles schlecht für SELECT *. Ich benutze es großzügig für diese Anwendungsfälle:
Ad-hoc-Abfragen. Wenn ich versuche, etwas zu debuggen, insbesondere von einer schmalen Tabelle, mit der ich vielleicht nicht vertraut bin, ist SELECT * oft mein bester Freund. Es hilft mir nur zu sehen, was los ist, ohne eine Menge Nachforschungen anstellen zu müssen, wie die zugrunde liegenden Spaltennamen lauten. Dies wird ein größeres "Plus", je länger die Spaltennamen werden.
Wenn * "eine Zeile" bedeutet. In den folgenden Anwendungsfällen ist SELECT * in Ordnung, und Gerüchte, dass es sich um einen Performance-Killer handelt, sind nur urbane Legenden, die vor vielen Jahren eine gewisse Gültigkeit hatten, aber jetzt nicht:
In diesem Fall bedeutet * "Zeilen zählen". Wenn Sie anstelle von * einen Spaltennamen verwenden, werden die Zeilen gezählt, in denen der Wert dieser Spalte nicht null war . COUNT (*) bringt für mich das Konzept, dass Sie Zeilen zählen , auf den Punkt und vermeidet seltsame Randfälle, die dadurch verursacht werden, dass NULL-Werte aus Ihren Aggregaten entfernt werden.
Gleiches gilt für diese Art von Abfrage:
In jeder Datenbank, die ihr Geld wert ist, bedeutet * nur "eine Zeile". Es spielt keine Rolle, was Sie in die Unterabfrage eingeben. Einige Leute verwenden die ID von b in der SELECT-Liste, oder sie verwenden die Nummer 1, aber IMO sind diese Konventionen ziemlich unsinnig. Was Sie meinen, ist "Zählen Sie die Zeile", und das bedeutet *. Die meisten Abfrageoptimierer da draußen sind klug genug, dies zu wissen. (Um ehrlich zu sein, weiß ich nur , dass dies bei SQL Server und Oracle der Fall ist.)
quelle
*
besteht darin, dass in einigen Situationen die Cache-Systeme von MySQL besser genutzt werden können. Wenn Sie eine große Anzahl ähnlicherselect
Abfragen ausführen, die unterschiedliche Spaltennamen (,, ...) mit a anfordernselect A where X
,select B where X
kannselect * where X
der Cache eine größere Anzahl von Abfragen verarbeiten, was zu einer erheblichen Leistungssteigerung führen kann. Es ist ein anwendungsspezifisches Szenario, aber es lohnt sich, daran zu denken.SELECT *
Entwickler die beteiligten Tabellenschemata überprüfen , um die betroffenen / verfügbaren Spalten zu ermitteln, z. B. innerhalb einesforeach
oderserialize
. Die Aufgabe, wiederholt nach Schemas zu suchen, um festzustellen, was gerade passiert, erhöht zwangsläufig die Gesamtzeit, die sowohl für das Debuggen als auch für die Entwicklung von zugehörigem Code erforderlich ist.Das Sternchen "*" in der SELECT-Anweisung steht für alle Spalten in den Tabellen, die an der Abfrage beteiligt sind.
Performance
Die
*
Kurzschrift kann langsamer sein, weil:SELECT *
über das Kabel zu senden , riskiert einen vollständigen TabellenscanInstandhaltung
Bei Verwendung von
SELECT *
:SELECT *
wird ein Fehler ausgeblendet, der darauf wartet, dass er auftritt, wenn die Spaltenreihenfolge einer Tabelle geändert wurde.Design
SELECT *
ist ein Anti-Muster :Wann sollte "SELECT *" verwendet werden?
Es ist akzeptabel,
SELECT *
wenn jede Spalte in den beteiligten Tabellen explizit benötigt wird, im Gegensatz zu jeder Spalte, die beim Schreiben der Abfrage vorhanden war. Die Datenbank erweitert das * intern in die vollständige Liste der Spalten - es gibt keinen Leistungsunterschied.Andernfalls listen Sie explizit jede Spalte auf, die in der Abfrage verwendet werden soll - vorzugsweise unter Verwendung eines Tabellenalias.
quelle
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 Ihnen schreiben, gehen
SELECT *
Sie das Risiko ein, dass irgendwann jemand eine Textspalte hinzufügt, wodurch Ihre Abfrage langsamer ausgeführt wird, obwohl Sie diese Spalte tatsächlich nicht benötigen.Wenn Sie die neue Spalte tatsächlich verwenden möchten, müssen Sie wahrscheinlich ohnehin noch viele andere Änderungen an Ihrem Code vornehmen. Sie sparen nur
, new_column
- nur ein paar Zeichen beim Tippen.quelle
*
kann sich unerwartet ändern und dies kann in der Anwendung selbst zu Chaos führen: Spalten, auf die durch Ordnungszahlen verwiesen wird (z. B. sqldatareader.getstring (2)), werden plötzlich abgerufen eine andere Spalte, jedeINSERT ... SELECT *
wird brechen und so weiter und so fort.SELECT *
es nicht darum, wenige Zeichen zu speichern. Es geht darum, Stunden an Debugging-Zeit zu sparen, da leicht vergessen wird, neu hinzugefügte Spalten anzugeben.Wenn Sie die Spalten in einer SELECT-Anweisung benennen, werden sie in der angegebenen Reihenfolge zurückgegeben und können daher sicher durch einen numerischen Index referenziert werden. Wenn Sie "SELECT *" verwenden, erhalten Sie die Spalten möglicherweise in beliebiger Reihenfolge und können die Spalten daher nur sicher nach Namen verwenden. Wenn Sie nicht im Voraus wissen, was Sie mit einer neuen Spalte tun möchten, die der Datenbank hinzugefügt wird, ist es am wahrscheinlichsten, sie zu ignorieren. Wenn Sie neue Spalten ignorieren, die der Datenbank hinzugefügt werden, hat das Abrufen keinerlei Vorteile.
quelle
select *
und anschließende Verwenden der Spalten nach Index wäre schrecklich, aber das Verwendenselect X, Y, Z
oderselect A,B,C
Übergeben des resultierenden Datenlesegeräts an Code, der erwartet, dass mit den Daten in den Spalten 0, 1 und 2 etwas zu tun ist, scheint ein durchaus vernünftiger Weg zu sein Lassen Sie denselben Code entweder auf X, Y, Z oder A, B, C einwirken. Beachten Sie, dass die Indizes von Spalten eher von ihrer Position in der SELECT-Anweisung als von ihrer Reihenfolge in der Datenbank abhängen.In vielen Situationen verursacht SELECT * Fehler zur Laufzeit in Ihrer Anwendung und nicht zur Entwurfszeit. Es verbirgt das Wissen über Spaltenänderungen oder fehlerhafte Referenzen in Ihren Anwendungen.
quelle
Wenn Sie wirklich jede Spalte möchten, habe ich keinen Leistungsunterschied zwischen select (*) und der Benennung der Spalten festgestellt. Der Treiber zum Benennen der Spalten kann einfach darin bestehen, explizit anzugeben, welche Spalten in Ihrem Code erwartet werden.
Oft möchten Sie jedoch nicht jede Spalte, und die Auswahl (*) kann zu unnötiger Arbeit für den Datenbankserver führen und dazu, dass unnötige Informationen über das Netzwerk übertragen werden müssen. Es ist unwahrscheinlich, dass ein erkennbares Problem auftritt, wenn das System nicht stark ausgelastet ist oder die Netzwerkverbindung langsam ist.
quelle
Stellen Sie sich vor, Sie reduzieren die Kopplung zwischen der App und der Datenbank.
Um den Aspekt "Codegeruch" zusammenzufassen:
SELECT *
Erstellt eine dynamische Abhängigkeit zwischen der App und dem Schema. Die Einschränkung der Verwendung ist eine Möglichkeit, die Abhängigkeit genauer zu definieren. Andernfalls besteht bei einer Änderung der Datenbank eine höhere Wahrscheinlichkeit, dass Ihre Anwendung abstürzt.quelle
Wenn Sie der Tabelle Felder hinzufügen, werden diese automatisch in alle Ihre Abfragen aufgenommen, die Sie verwenden
select *
. Dies mag praktisch erscheinen, führt jedoch dazu, dass Ihre Anwendung langsamer wird, da Sie mehr Daten abrufen, als Sie benötigen, und Ihre Anwendung tatsächlich irgendwann abstürzt.Die Anzahl der Daten, die Sie in jeder Zeile eines Ergebnisses abrufen können, ist begrenzt. Wenn Sie Ihren Tabellen Felder hinzufügen, sodass ein Ergebnis diese Grenze überschreitet, wird beim Versuch, die Abfrage auszuführen, eine Fehlermeldung angezeigt.
Dies ist die Art von Fehlern, die schwer zu finden sind. Sie nehmen an einer Stelle eine Änderung vor, die an einer anderen Stelle explodiert, an der die neuen Daten überhaupt 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 im Ergebnis angezeigt werden sollen, sind Sie vor einem solchen Overhead-Überlauf geschützt.
quelle
Referenz aus diesem Artikel.
Gehen Sie niemals mit "SELECT *",
Ich habe nur einen Grund gefunden, "SELECT *" zu verwenden.
Wenn Sie spezielle Anforderungen haben und beim Hinzufügen oder Löschen eine dynamische Umgebung erstellt haben, wird die Spalte automatisch nach 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.
quelle
Im Allgemeinen müssen Sie die Ergebnisse
SELECT * ...
in Datenstrukturen verschiedener Typen einpassen. Ohne Angabe der Reihenfolge, in der die Ergebnisse eingehen, kann es schwierig sein, alles richtig auszurichten (und dunkelere Felder sind viel leichter zu übersehen).Auf diese Weise können Sie Ihren Tabellen aus verschiedenen Gründen Felder hinzufügen (auch in der Mitte), ohne den SQL-Zugriffscode in der gesamten Anwendung zu beschädigen.
quelle
Verwenden ,
SELECT *
wenn Sie nur ein paar Spalten brauchen viel mehr Daten übertragen bedeutet , als Sie benötigen. Dies erhöht die Verarbeitung in der Datenbank und erhöht die Latenz beim Abrufen der Daten zum Client. Hinzu kommt, dass beim Laden mehr Speicher benötigt wird, in einigen Fällen deutlich mehr, z. B. bei großen BLOB-Dateien. Es geht hauptsächlich um Effizienz.Darüber hinaus ist es jedoch einfacher, bei der Betrachtung der Abfrage zu erkennen, welche Spalten geladen werden, ohne nachschlagen zu müssen, was in der Tabelle enthalten ist.
Ja, wenn Sie eine zusätzliche Spalte hinzufügen, ist 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 das Potenzial, dass Sie diejenigen erhalten, die Sie nicht verwenden. Nicht wollen / erwarten kann Probleme verursachen. Wenn Sie beispielsweise alle Spalten abrufen und sich dann auf die Reihenfolge in einer Schleife verlassen, um Variablen zuzuweisen, und dann eine hinzufügen, oder wenn sich die Spaltenreihenfolgen ändern (dies tritt beim Wiederherstellen aus einer Sicherung auf), kann dies alles abwerfen.
Dies ist auch die gleiche Art von Argumentation, warum Sie, wenn Sie eine machen
INSERT
, immer die Spalten angeben sollten.quelle
Ich glaube nicht, dass es dafür wirklich eine pauschale 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 Vorteile 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 Einzelhandelssoftware), sodass nicht das große Risiko bestand, dass jemand ein riesiges BLOB-Feld in eine Tabelle schob.
quelle
Durch Auswahl mit Spaltennamen wird die Wahrscheinlichkeit erhöht, dass das Datenbankmodul über Indizes auf die Daten zugreifen kann, anstatt die Tabellendaten abzufragen.
SELECT * setzt Ihr System unerwarteten Leistungs- und Funktionsänderungen aus, wenn sich Ihr 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.
quelle
Es gibt auch einen pragmatischeren Grund: Geld. Wenn Sie eine Cloud-Datenbank verwenden und für verarbeitete Daten bezahlen müssen, gibt es keine Erklärung für das Lesen von Daten, die Sie sofort verwerfen.
Zum Beispiel: BigQuery :
und Kontrollprojektion - Vermeiden Sie SELECT * :
quelle
Verstehen Sie Ihre Anforderungen, bevor Sie das Schema entwerfen (falls möglich).
Erfahren Sie mehr über die Daten, 1) Indizierung 2) Art des verwendeten Speichers, 3) Vendor Engine oder Funktionen; dh ... Caching, In-Memory-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 Arbeitslast nicht unterstützen kann, sollten Sie neu bewerten, wie die Anforderungen in der Arbeitslast 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 spezifischen benannten Spalten erstellen (im Vergleich zu '*' auswählen). Überprüfen Sie Ihre Daten und Ihr Schema regelmäßig, um sicherzustellen, dass Sie nie auf das "Garbage-In" -> "Garbage-Out" -Syndrom stoßen.
Vorausgesetzt, es gibt keine andere Lösung. Sie können Folgendes berücksichtigen. Es gibt immer mehrere Lösungen für ein Problem.
1) Indizierung: Mit select * wird ein Tabellenscan ausgeführt. Abhängig von verschiedenen Faktoren kann dies eine Festplattensuche und / oder einen Konflikt mit anderen Abfragen beinhalten. Wenn die Tabelle für mehrere Zwecke bestimmt ist, stellen Sie sicher, dass alle Abfragen performant sind, und führen Sie sie unterhalb Ihrer Zielzeiten aus. Wenn eine große Datenmenge vorhanden ist und Ihr Netzwerk oder eine andere Ressource nicht optimiert 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. Die E / A-Zeiten und die Belastung des Systems / der CPU variieren.
3) Kann der DBA die Datenbank / Tabellen für eine höhere Leistung optimieren? Aus irgendeinem Grund haben die Teams entschieden, dass die Auswahl '*' die beste Lösung für das Problem ist. Kann die Datenbank oder Tabelle in den Speicher geladen werden? (Oder eine andere Methode ... Vielleicht wurde die Antwort so konzipiert, dass sie mit einer Verzögerung von 2-3 Sekunden reagiert? --- während eine Werbung abgespielt wird, um die Einnahmen des Unternehmens zu erzielen ...)
4) Beginnen Sie an der Basislinie. Verstehen Sie Ihre Datentypen und wie die Ergebnisse dargestellt werden. Bei kleineren Datentypen reduziert die Anzahl der Felder die in der Ergebnismenge zurückgegebene Datenmenge. Dadurch bleiben Ressourcen für andere Systemanforderungen verfügbar. Die Systemressourcen sind normalerweise begrenzt. Arbeiten Sie immer unter diesen Grenzen, um Stabilität und vorhersehbares Verhalten zu gewährleisten.
5) Größe der Tabelle / Daten. Wählen Sie '*' ist bei winzigen Tabellen üblich. Sie passen normalerweise in den Speicher und die Reaktionszeiten sind schnell. Nochmals .... überprüfen Sie Ihre Anforderungen. Plan für Feature Creep; Planen Sie immer den aktuellen und möglichen zukünftigen Bedarf.
6) Häufigkeit der Abfragen. Beachten Sie andere Workloads im System. Wenn diese Abfrage jede Sekunde ausgelöst wird und die Tabelle winzig 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 Gigabyte / Terabyte Daten handelt, sollten Sie möglicherweise zusätzliche Ressourcen bereitstellen, um sicherzustellen, dass andere Workloads nicht betroffen sind.
7) Zugehörige Workloads. Verstehen Sie, wie die Ressourcen verwendet werden. Ist das Netzwerk / System / Datenbank / Tabelle / Anwendung dediziert oder gemeinsam genutzt? Wer sind die Stakeholder? Ist dies für Produktion, Entwicklung oder Qualitätssicherung? Ist dies eine vorübergehende "schnelle Lösung". Haben Sie das Szenario getestet? Sie werden überrascht sein, wie viele Probleme heute auf der aktuellen Hardware auftreten können. (Ja, die Leistung ist schnell ... aber das Design / die Leistung ist immer noch beeinträchtigt.) Muss das System 10.000 Abfragen pro Sekunde gegenüber 5-10 Abfragen pro Sekunde ausführen? Ist der Datenbankserver dediziert oder führen andere Anwendungen die Überwachung für die gemeinsam genutzte Ressource aus? Einige Anwendungen / Sprachen; O / S verbrauchen 100% des Speichers und verursachen verschiedene Symptome / Probleme.
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 Sie müssen sich nicht einmal darum kümmern.
quelle