Warum wird "Select * from table" als schlechte Praxis angesehen?

96

Gestern diskutierte ich mit einem "Hobby" -Programmierer (ich selbst bin ein professioneller Programmierer). Wir sind auf einige seiner Arbeiten gestoßen, und er sagte, dass er immer alle Spalten in seiner Datenbank abfragt (sogar auf / in Produktionsserver / Code).

Ich habe versucht, ihn davon abzubringen, war aber noch nicht so erfolgreich. Meiner Meinung nach sollte ein Programmierer nur abfragen, was tatsächlich aus Gründen der "Hübschheit", Effizienz und des Datenverkehrs benötigt wird. Irre ich mich mit meiner Ansicht?

der Speck
quelle
1
Ich würde sagen, was ist, wenn sich der Inhalt der Tabelle ändert? Spalten hinzufügen / entfernen? Sie wählen immer noch * .. aus, damit Ihnen Dinge fehlen oder Sie mehr Daten abrufen, als Sie benötigen.
JF es
2
@JFit Das ist ein Teil davon, aber weit weg von der ganzen Geschichte.
Jwenting
6
Und gute Gründe hier: Warum wird select * als schädlich eingestuft?
Ellie Kesselman
@gnat Kann eine Frage wirklich als Duplikat einer geschlossenen Frage betrachtet werden? (
zB

Antworten:

67

Überlegen Sie, was Sie zurückerhalten und wie Sie diese an Variablen in Ihrem Code binden.

Denken Sie nun darüber nach, was passiert, wenn jemand das Tabellenschema aktualisiert, um eine Spalte hinzuzufügen (oder zu entfernen), auch wenn Sie diese nicht direkt verwenden.

Die Verwendung von select *, wenn Sie Abfragen von Hand eingeben, ist in Ordnung, nicht wenn Sie Abfragen für Code schreiben.

gbjbaanb
quelle
8
Leistung, Netzwerklast usw. usw. sind weitaus wichtiger als die Bequemlichkeit, die Spalten in der gewünschten Reihenfolge und mit dem gewünschten Namen wiederherzustellen.
Jwenting
21
@jwenting wirklich? Leistung ist wichtiger als Korrektheit? Wie auch immer, ich sehe nicht, dass "select *" eine bessere Leistung erbringt, als nur die gewünschten Spalten auszuwählen.
Gbjbaanb
9
@Bratch: In realen Produktionsumgebungen haben Sie möglicherweise Hunderte von Anwendungen, die dieselben Tabellen verwenden, und es gibt keine Möglichkeit, alle diese Anwendungen ordnungsgemäß zu verwalten. Sie haben ein korrektes Gefühl, aber praktisch scheitert das Argument nur an der Realität der Arbeit in Kopien. Schemaänderungen an aktiven Tabellen werden ständig durchgeführt.
user1068
18
Ich verstehe den Punkt in dieser Antwort nicht. Wenn Sie einer Tabelle eine Spalte hinzufügen, funktionieren sowohl SELECT * als auch SELECT [Spalten]. Der einzige Unterschied besteht darin, dass, wenn der Code an die neue Spalte gebunden werden muss, SELECT [Spalten] geändert werden muss SELECT * wird nicht. Wenn eine Spalte aus einer Tabelle entfernt wird, wird SELECT * am Bindungspunkt unterbrochen, während SELECT [Spalten] beim Ausführen der Abfrage unterbrochen wird. Aus meiner Sicht ist SELECT * die flexiblere Option, da Änderungen an der Tabelle nur Änderungen an der Bindung erforderlich machen. Vermisse ich etwas?
TallGuy
11
Greifen Sie dann auf die Spalten mit dem Namen @gbjbaanb zu. Alles andere wäre offensichtlich dumm, wenn Sie die Spaltenreihenfolge nicht in der Abfrage angegeben hätten.
immibis
179

Schemaänderungen

  • Abrufen nach Reihenfolge --- Wenn der Code die Spalte # als Methode zum Abrufen der Daten abruft, werden die Spaltennummern durch eine Änderung des Schemas neu angepasst. Dies wird die Anwendung durcheinander bringen und es werden schlimme Dinge passieren.
  • Abrufen nach Name --- Wenn der Code Spalten nach Namen abruft, z. B. foo, und eine andere Tabelle in der Abfrage eine Spalte hinzufügt foo, kann die Art und Weise, wie dies behandelt wird, Probleme verursachen, wenn versucht wird, die richtige foo Spalte abzurufen.

In beiden Fällen kann eine Schemaänderung Probleme beim Extrahieren der Daten verursachen.

Ferner prüfen , ob eine Spalte , die benutzt wurde, wird entfernt aus der Tabelle. Das select * from ...klappt immer noch aber fehlerfrei beim Versuch die Daten aus der Ergebnismenge zu ziehen. Wenn die Spalte in der Abfrage angegeben ist, wird die Abfrage fehlschlagen und stattdessen eine eindeutige Angabe darüber geben, wo und was das Problem ist.

Datenaufwand

Mit einigen Spalten kann eine erhebliche Datenmenge verknüpft sein. Durch Auswahl von Zurück *werden alle Daten abgerufen . Ja, hier ist der varchar(4096)Wert für 1000 Zeilen, die Sie zurück ausgewählt haben. Dies gibt Ihnen zusätzliche mögliche 4 Megabyte an Daten, die Sie nicht benötigen, die aber trotzdem über die Leitung gesendet werden.

In Bezug auf die Schemaänderung ist das Varchar dort möglicherweise nicht vorhanden, als Sie die Tabelle zum ersten Mal erstellt haben, jetzt ist es dort.

Nichtvermittlung von Absichten

Wenn Sie "Zurück" auswählen *und 20 Spalten erhalten, aber nur zwei davon benötigen, vermitteln Sie nicht die Absicht des Codes. Wenn man sich die Abfrage ansieht, weiß select *man nicht, worauf es ankommt. Kann ich die Abfrage so ändern, dass stattdessen dieser andere Plan verwendet wird, um sie zu beschleunigen, indem diese Spalten nicht berücksichtigt werden? Ich weiß es nicht, weil die Absicht der Rückgabe der Abfrage nicht klar ist.


Schauen wir uns einige SQL-Fiddles an, die diese Schemaänderungen etwas genauer untersuchen.

Zunächst die ursprüngliche Datenbank: http://sqlfiddle.com/#!2/a67dd/1

DDL:

create table one (oneid int, data int, twoid int);
create table two (twoid int, other int);

insert into one values (1, 42, 2);
insert into two values (2, 43);

SQL:

select * from one join two on (one.twoid = two.twoid);

Und die Spalten, die Sie zurückerhalten oneid=1, data=42sind twoid=2, und other=43.

Was passiert nun, wenn ich einer Tabelle eine Spalte hinzufüge? http://sqlfiddle.com/#!2/cd0b0/1

alter table one add column other text;

update one set other = 'foo';

Und meine Ergebnisse aus der gleichen Abfrage nach wie vor sind oneid=1, data=42, twoid=2, und other=foo.

Eine Änderung in einer der Tabellen unterbricht die Werte von a select *und plötzlich wird Ihre Bindung von 'other' an ein int einen Fehler auslösen, und Sie wissen nicht, warum.

Wenn stattdessen Ihre SQL-Anweisung war

select 
    one.oneid, one.data, two.twoid, two.other
from one join two on (one.twoid = two.twoid);

Die Änderung an Tabelle eins hätte Ihre Daten nicht gestört. Diese Abfrage wird vor und nach der Änderung gleich ausgeführt.


Indizierung

Wenn Sie eine select * fromausführen, ziehen Sie alle Zeilen aus allen Tabellen, die den Bedingungen entsprechen. Sogar Tische, die dir wirklich egal sind. Während dies bedeutet, dass mehr Daten übertragen werden, lauert ein weiteres Leistungsproblem weiter unten im Stapel.

Indizes. (bezogen auf SO: Wie verwende ich den Index in der select-Anweisung? )

Wenn Sie viele Spalten zurückziehen, ignoriert das Datenbankplanoptimierungsprogramm möglicherweise die Verwendung eines Index, da Sie trotzdem alle diese Spalten abrufen müssen und es mehr Zeit in Anspruch nehmen würde, den Index und dann alle Spalten in der Abfrage abzurufen als wäre es nur ein kompletter Tabellenscan zu machen.

Wenn Sie nur den Nachnamen eines Benutzers auswählen (den Sie häufig verwenden und auf dem Sie einen Index haben), kann die Datenbank nur einen Index-Scan durchführen (nur Index-Scan für Postgres-Wiki , vollständiger MySQL- Tabellenscan vs vollständiger Index-Scan , Nur-Index-Scan: Vermeiden des Tabellenzugriffs ).

Es gibt eine ganze Reihe von Optimierungen, wenn möglich, nur aus Indizes zu lesen. Die Informationen können auf jeder Indexseite schneller abgerufen werden, da Sie auch weniger davon abrufen - Sie ziehen nicht alle anderen Spalten für die Indexseite ab select *. Es ist möglich, dass ein Nur-Index-Scan Ergebnisse in der Größenordnung von 100x schneller zurückgibt (Quelle: Wählen Sie * ist schlecht ).

Dies bedeutet nicht, dass ein vollständiger Index-Scan großartig ist, er ist immer noch ein vollständiger Scan - aber er ist besser als ein vollständiger Tabellenscan. Sobald Sie alle Möglichkeiten select *ausloten, die der Leistung schaden, finden Sie immer wieder neue.

Verwandte Lesung

Gemeinschaft
quelle
2
@Tonny Ich würde zustimmen - aber als ich (zuerst) antwortete, hätte ich nie gedacht, dass diese Frage so viel Diskussion und Kommentar erzeugen würde! Es ist offensichtlich, nur nach benannten Spalten abzufragen, nicht wahr ?!
Gbjbaanb
3
Das Aufbrechen aller Elemente durch Hinzufügen einer Spalte ist auch ein guter Grund, warum Code immer auf Spalten in einem Datenbereich zugreifen sollte, und nicht
Julia Hayward,
1
@ gbjbaanb Es ist für mich. Aber viele Leute kommen, um SQL-Abfragen zu schreiben, ohne einen formalen Hintergrund / eine Ausbildung. Für sie ist es vielleicht nicht offensichtlich.
Tonny
1
@Aaronaught Ich habe es mit dem zusätzlichen Bit zu den Indizierungsproblemen aktualisiert. Gibt es noch andere Punkte, die ich für die Unrichtigkeit von ansprechen sollte select *?
3
Wow, die akzeptierte Antwort war so schlecht darin, irgendetwas zu erklären, dass ich sie herabgestimmt habe. Erstaunt, dass dies nicht die akzeptierte Antwort ist. +1.
Ben Lee
38

Ein weiteres Problem: Wenn es sich um eine JOINAbfrage handelt und Sie Abfrageergebnisse in einem assoziativen Array abrufen (wie dies in PHP der Fall sein könnte), ist dies fehleranfällig.

Die Sache ist, dass

  1. Wenn die Tabelle fooSpalten idund enthältname
  2. wenn tabelle barspalten hat idund address,
  3. und in Ihrem Code, den Sie verwenden SELECT * FROM foo JOIN bar ON foo.id = bar.id

raten Sie mal, was passiert, wenn jemand nameder barTabelle eine Spalte hinzufügt .

Der Code funktioniert plötzlich nicht mehr ordnungsgemäß, da die nameSpalte jetzt zweimal in den Ergebnissen angezeigt wird. Wenn Sie die Ergebnisse in einem Array speichern , überschreiben die Daten von second name( bar.name) die ersten name( foo.name)!

Es ist ein ziemlich böser Fehler, weil es sehr nicht offensichtlich ist. Es kann eine Weile dauern, bis das herausgefunden ist, und die Person, die der Tabelle eine weitere Spalte hinzufügt, kann solche unerwünschten Nebenwirkungen auf keinen Fall vorhersehen.

(Wahre Geschichte).

Behalten Sie also nicht die *Kontrolle darüber, welche Spalten Sie abrufen, und verwenden Sie gegebenenfalls Aliase.

Konrad Morawski
quelle
Okay, in diesem Fall (was ich für selten halte) könnte es ein großes Problem sein. Sie können dies jedoch dennoch vermeiden (und die meisten Leute werden es wahrscheinlich tun), indem Sie mit dem Platzhalter fragen und einfach einen Alias ​​für die identischen Spaltennamen hinzufügen.
die Speckerei
4
Theoretisch, aber wenn Sie aus Bequemlichkeit einen Platzhalter verwenden, verlassen Sie sich darauf, dass dieser Ihnen automatisch alle vorhandenen Spalten anzeigt und Sie sich nie die Mühe machen, die Abfrage zu aktualisieren, wenn die Tabellen wachsen. Wenn Sie jede einzelne Spalte angeben, müssen Sie zu der Abfrage gehen, um Ihrer SELECTKlausel eine weitere hinzuzufügen. In diesem Fall erkennen Sie hoffentlich, dass der Name nicht eindeutig ist. Übrigens glaube ich nicht, dass es in Systemen mit großen Datenbanken so selten ist. Wie gesagt, ich habe einmal ein paar Stunden damit verbracht, diesen Fehler in einem großen Schlammball von PHP-Code zu jagen. Und ich habe gerade einen anderen Fall gefunden: stackoverflow.com/q/17715049/168719
Konrad Morawski
3
Ich habe letzte Woche eine Stunde damit verbracht, dies durch einen Beraterkopf zu bringen. Er soll ein SQL-Guru sein ... Seufz ...
Tonny
22

In vielen Fällen kann es durchaus legitim sein, jede Spalte abzufragen.

Nicht immer jede Spalte abfragen.

Es ist mehr Arbeit für Ihre Datenbank-Engine, die ihre internen Metadaten durchsuchen muss, um herauszufinden, mit welchen Spalten sie sich befassen muss, bevor sie mit dem eigentlichen Geschäft fortfahren kann, die Daten tatsächlich zu erhalten und an Sie zurückzusenden. OK, es ist nicht der größte Overhead der Welt, aber Systemkataloge können ein spürbarer Engpass sein.

Es ist mehr Arbeit für Ihr Netzwerk, weil Sie eine beliebige Anzahl von Feldern zurückziehen, wenn Sie nur ein oder zwei von ihnen möchten. Wenn jemand [anderes] ein paar Dutzend zusätzliche Felder hinzufügt, die alle große Textblöcke enthalten, geht der Durchsatz plötzlich durch den Boden - ohne ersichtlichen Grund. Dies wird noch schlimmer, wenn Ihre "where" -Klausel nicht besonders gut ist und Sie auch viele Zeilen zurückziehen - das ist möglicherweise eine Menge Daten, die über das Netzwerk zu Ihnen gelangen (dh sie werden langsam sein).

Es ist mehr Arbeit für Ihre Anwendung, all diese zusätzlichen Daten abzurufen und zu speichern, die ihr höchstwahrscheinlich egal sind.

Sie laufen Gefahr, dass Spalten ihre Reihenfolge ändern. OK, Sie sollten sich darüber keine Gedanken machen müssen (und auch nicht, wenn Sie nur die gewünschten Spalten auswählen), aber wenn Sie alle auf einmal abrufen, beschließt jemand anderes, die Spaltenreihenfolge in der Tabelle neu zu ordnen , dieser sorgfältig ausgearbeitete CSV-Export, den Sie den Konten im Flur geben, geht plötzlich ganz in den Topf - wieder ohne ersichtlichen Grund.

Übrigens, ich habe oben ein paar Mal "jemand anderes" gesagt. Denken Sie daran, dass Datenbanken von Natur aus Mehrbenutzer sind. Sie haben möglicherweise nicht die Kontrolle über sie, die Sie zu tun glauben.

Phill W.
quelle
3
Ich würde denken, dass das Abfragen jeder Spalte für Dinge wie schema-agnostische Tabellenanzeigefunktionen legitim sein kann. Keine schrecklich häufige Situation, aber im Kontext von Tools, die nur für den internen Gebrauch bestimmt sind, können solche Dinge nützlich sein.
Supercat
1
@supercat Das ist nur der EINZIGE gültige Anwendungsfall für ein "SELECT *", den ich mir vorstellen kann. Und selbst dann würde ich es vorziehen, die Abfrage auf "SELECT TOP 10 *" (in MS SQL) zu beschränken oder "LIMIT 10" (mySQL) oder "WHERE ROWNUM <= 10" (Oracle) hinzuzufügen. In diesem Fall geht es in der Regel eher um "welche Spalten und einige Beispieldaten" als um den vollständigen Inhalt.
Tonny
@Tonny: SQL Server hat die Standardskripten geändert, um die TOPEinschränkung hinzuzufügen . Ich bin nicht sicher, wie wichtig das ist, wenn der Code so viele Zeichen liest, wie er anzeigen soll, und dann die Abfrage freigibt. Ich denke, die Antworten auf Anfragen werden etwas träge verarbeitet, obwohl ich die Details nicht kenne. In jedem Fall denke ich, anstatt zu sagen, dass es "nicht legitim" ist, wäre es besser zu sagen, dass "... in weitaus weniger legitim ist "; Grundsätzlich würde ich die legitimen Fälle als solche zusammenfassen, bei denen der Benutzer eine bessere Vorstellung davon hat, was für ihn von Bedeutung ist als der Programmierer.
Supercat
@supercat Dem kann ich zustimmen. Und ich mag es wirklich, wie Sie es in Ihrem letzten Satz ausgedrückt haben. Daran muss ich mich erinnern.
Tonny
11

Die kurze Antwort lautet: Es hängt davon ab, welche Datenbank sie verwenden. Relationale Datenbanken sind für das schnelle, zuverlässige und atomare Extrahieren der benötigten Daten optimiert . Bei großen Datenmengen und komplexen Abfragen ist dies viel schneller und wahrscheinlich sicherer als SELECTING * und entspricht den Verknüpfungen auf der "Code" -Seite. In Schlüsselwertgeschäften sind solche Funktionen möglicherweise nicht implementiert oder sie sind nicht ausgereift genug, um in der Produktion verwendet zu werden.

Trotzdem können Sie die von Ihnen verwendete Datenstruktur mit SELECT * füllen und den Rest im Code verarbeiten. Wenn Sie jedoch skalieren möchten, können Sie Leistungsengpässe feststellen.

Der nächste Vergleich ist das Sortieren von Daten: Sie können Quicksort oder Bubblesort verwenden, und das Ergebnis ist korrekt. Wird aber nicht optimiert und wird definitiv Probleme haben, wenn Sie Parallelität einführen und atomar sortieren müssen.

Natürlich ist es billiger, RAM und CPUs hinzuzufügen, als in einen Programmierer zu investieren, der SQL-Abfragen ausführen kann und sogar ein vages Verständnis dafür hat, was ein JOIN ist.

Lorenzog
quelle
SQL lernen! Es ist nicht so schwer. Es ist die "Muttersprache" von Datenbanken weit und breit. Es ist mächtig. Es ist elegant. Es hat den Test der Zeit bestanden. Und es gibt keine Möglichkeit, einen Join auf der "Code" -Seite zu schreiben, der effizienter ist als der Join in der Datenbank, es sei denn, Sie sind wirklich unfähig, SQL-Joins auszuführen. Beachten Sie, dass Sie zum Ausführen eines "Code-Joins" alle Daten aus beiden Tabellen in einem einfachen 2-Tabellen-Join abrufen müssen. Oder ziehen Sie Indexstatistiken und verwenden diese, um zu entscheiden, welche Tabellendaten vor dem Beitritt abgerufen werden sollen? Das hätte ich nicht gedacht ... Lerne, die Datenbank richtig zu benutzen, Leute.
Craig
@Craig: SQL ist in relationalen Datenbanken weit verbreitet. Dies ist jedoch weit davon entfernt, die einzige Art von Datenbank zu sein ... und es gibt einen Grund, warum modernere Datenbankansätze oft als NoSQL bezeichnet werden. : P Niemand, den ich kenne, würde SQL ohne viel Ironie als "elegant" bezeichnen. In Bezug auf relationale Datenbanken sind weniger als viele der Alternativen zum Scheitern verurteilt.
CHAO
@cHao Ich bin mir seit Jahrzehnten der verschiedenen anderen Arten von Datenbanken bewusst . Die Pick "nosql" -Datenbank gibt es schon immer. "NoSQL" ist nicht einmal ein neues Konzept. ORMs gab es auch schon immer und sie waren immer langsam. Langsam! = Gut. In Bezug auf Eleganz (LINQ?) Können Sie mich nicht davon überzeugen, dass dies für eine where-Klausel angemessen oder elegant ist: Customer customer = this._db.Customers.Where( “it.ID = @ID”, new ObjectParameter( “ID”, id ) ).First();Siehe Time to Take Offense auf Seite 2.
Craig,
@Craig: Lass mich noch nicht mal mit ORM anfangen. Fast jedes System da draußen macht es fürchterlich und die Abstraktion leckt überall. Das liegt daran, dass relationale DB-Datensätze keine Objekte sind - bestenfalls sind sie die serialisierbaren Eingeweide eines Teils eines Objekts. Aber was LINQ betrifft, möchten Sie wirklich dorthin gehen? Das SQLish-Äquivalent ist so etwas wie var cmd = db.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM Customers WHERE ID = @ID"; cmd.Parameters.AddWithValue("@ID", id); var result = cmd.ExecuteReader();.... und dann fahren Sie fort, um einen Kunden aus jeder Zeile zu erstellen. LINQ schlägt die Hose aus.
CHAO
@Craig: Zugegeben, es ist nicht so elegant, wie es sein könnte. Aber es wird nie so elegant sein, wie ich es gerne hätte, bis es .net-Code in SQL konvertieren kann. :) An welcher Stelle könnte man sagen var customer = _db.Customers.Where(it => it.id == id).First();.
CHAO
8

IMO, es geht darum, explizit oder implizit zu sein. Wenn ich Code schreibe, möchte ich, dass er funktioniert, weil ich ihn zum Laufen gebracht habe, nicht nur, weil alle Teile einfach da sind. Wenn Sie alle Datensätze abfragen und Ihr Code funktioniert, besteht die Tendenz, dass Sie fortfahren. Wenn sich später etwas ändert und Ihr Code jetzt nicht mehr funktioniert, ist es ein großer Aufwand, viele Abfragen und Funktionen zu debuggen, die nach einem Wert suchen, der vorhanden sein sollte, und die einzigen Referenzwerte sind *.

Auch in einem N-Tier-Ansatz ist es immer noch am besten, Störungen des Datenbankschemas in der Datenschicht zu isolieren. Wenn Ihre Datenebene * an die Geschäftslogik und höchstwahrscheinlich an die Präsentationsebene übergeben wird, erweitern Sie Ihren Debugging-Bereich exponentiell.

zkent
quelle
3
Dies ist wahrscheinlich einer der wichtigsten Gründe, und es hat nur einen winzigen Bruchteil der Stimmen. Die Wartbarkeit einer Codebasis mit verschmutzt select *ist viel schlechter!
Eamon Nerbonne
6

Denn wenn die Tabelle neue Spalten erhält, erhalten Sie all diese, auch wenn Sie sie nicht benötigen. mit varcharsdieser kann eine Menge zusätzlicher Daten werden , die von der DB zu reisen braucht

Einige DB-Optimierungen extrahieren möglicherweise auch die Datensätze mit nicht fester Länge in eine separate Datei, um den Zugriff auf die Teile mit fester Länge zu beschleunigen

Ratschenfreak
quelle
1

Abgesehen von dem Overhead, den Sie in erster Linie vermeiden möchten, würde ich sagen, dass Sie als Programmierer nicht auf die vom Datenbankadministrator festgelegte Spaltenreihenfolge angewiesen sind. Sie wählen jede Spalte aus, auch wenn Sie alle benötigen.

dj bazzie wazzie
quelle
3
Stimmen Sie zu, aber ich würde auch empfehlen, auf jeden Fall Werte aus einer Ergebnismenge anhand des Spaltennamens zu ziehen.
Rory Hunter
Abgeordnet, getragen. Verwenden Sie die Spaltennamen, unabhängig von der Spaltenreihenfolge. Die Spaltenreihenfolge ist eine spröde Abhängigkeit. Die Namen sollten (wie Sie hoffen) von einem tatsächlichen Entwurfsaufwand abgeleitet worden sein, oder Sie aliasen explizit zusammengesetzte Spalten oder Berechnungen oder widersprüchliche Spaltennamen in Ihrer Abfrage und verweisen auf den expliziten Alias, den Sie angegeben haben. Aber sich auf die Bestellung zu verlassen, ist so ziemlich nur Klebeband und Gebet ...
Craig
1

Ich sehe keinen Grund, warum Sie es nicht für den Zweck verwenden sollten, für den es erstellt wurde - alle Spalten aus einer Datenbank abrufen. Ich sehe drei Fälle:

  1. Eine Spalte wird der Datenbank hinzugefügt und Sie möchten, dass sie auch im Code enthalten ist. a) Mit * wird bei einer korrekten Meldung fehlgeschlagen. b) Ohne * wird funktionieren, aber nicht tun, was Sie erwarten, was ziemlich schlecht ist.

  2. Eine Spalte wird in der Datenbank hinzugefügt und soll nicht im Code enthalten sein. a) Mit * wird fehlschlagen; Dies bedeutet, dass * nicht mehr gilt, da seine Semantik "alle abrufen" bedeutet. b) Ohne * wird funktionieren.

  3. Eine Spalte wird entfernt. Code schlägt in beiden Fällen fehl.

Jetzt ist der häufigste Fall Fall 1 (da Sie * verwendet haben, was bedeutet, dass Sie höchstwahrscheinlich alle möchten); Ohne * können Sie Code haben, der gut funktioniert, aber nicht das tut, was erwartet wird, was sehr viel schlimmer ist, als der Code, der mit einer richtigen Fehlermeldung fehlschlägt .

Ich berücksichtige nicht den Code, der die Spaltendaten basierend auf dem Spaltenindex abruft, der meiner Meinung nach fehleranfällig ist. Es ist viel logischer, es basierend auf dem Spaltennamen abzurufen.

m3th0dman
quelle
Ihre Prämisse ist falsch. Select *war eher als Annehmlichkeit für Ad-hoc-Abfragen gedacht, nicht für Zwecke der Anwendungsentwicklung. Oder zur Verwendung in statistischen Konstrukten, bei select count(*)denen das Abfragemodul entscheidet, ob ein Index verwendet wird, welcher Index verwendet werden soll usw., und Sie keine tatsächlichen Spaltendaten zurückgeben. Oder zur Verwendung in Klauseln wie where exists( select * from other_table where ... ): Dies ist wiederum eine Aufforderung an die Abfrage-Engine, den effizientesten Pfad selbst auszuwählen, und die Unterabfrage wird nur zum Einschränken der Ergebnisse der Hauptabfrage verwendet. Etc.
Craig
@Craig Ich glaube, jedes Buch / Tutorial über SQL sagt, dass select *es die Semantik hat, alle Spalten abzurufen. Wenn Ihre Anwendung dies wirklich benötigt, sehe ich keine Gründe, warum Sie es nicht verwenden sollten. Können Sie auf einen Verweis (Oracle, IBM, Microsoft usw.) verweisen, in dem der Zweck, für den der select *Build erstellt wurde, darin besteht, nicht alle Spalten abzurufen?
m3th0dman
Natürlich select *gibt es die Möglichkeit, alle Spalten abzurufen ... als praktische Funktion für Ad-hoc-Abfragen, nicht weil dies in Produktionssoftware eine großartige Idee ist. Die Gründe sind in den Antworten auf dieser Seite bereits ziemlich gut erläutert, weshalb ich keine eigene detaillierte Antwort erstellt habe: •) Leistungsprobleme, wiederholtes Sammeln von Daten über das Netzwerk, die Sie nie verwenden, •) Probleme mit Spalten-Aliasing, •) Abfrage - Plan - Optimierung Ausfälle (Fehler verwenden , um Indizes in einigen Fällen), •) ineffizient Server I / O in Fällen , in denen ausgewählte begrenzt haben könnte allein Indizes verwendet, usw.
Craig
Vielleicht gibt es hier oder da einen Randfall, der die Verwendung select *in einer tatsächlichen Produktionsanwendung rechtfertigt , aber die Natur eines Randfalls ist, dass dies nicht der übliche Fall ist. :-)
Craig
@Craig Die Gründe sind gegen das Abrufen aller Spalten aus einer Datenbank, nicht gegen die Verwendung select *; Was ich gesagt habe, wenn Sie wirklich alle Spalten brauchen, sehe ich keinen Grund, warum Sie nicht verwenden sollten select *; Obwohl es nur wenige Szenarien geben muss, in denen alle Spalten benötigt werden.
m3th0dman
1

Stellen Sie sich das so vor ... wenn Sie alle Spalten einer Tabelle mit nur wenigen kleinen Zeichenfolgen oder numerischen Feldern abfragen, ergibt dies insgesamt 100.000 Daten. Schlechtes Training, aber es wird funktionieren. Fügen Sie nun ein einzelnes Feld hinzu, das beispielsweise ein Bild oder ein 10-MB-Word-Dokument enthält. Jetzt wird Ihre schnelle Abfrage sofort und auf mysteriöse Weise schlecht ausgeführt, nur weil der Tabelle ein Feld hinzugefügt wurde. Möglicherweise benötigen Sie dieses riesige Datenelement nicht, aber weil Sie Select * from Tablees trotzdem erhalten haben.

Kevin Mitchell
quelle
6
dies scheint lediglich den Punkt zu wiederholen, der bereits vor einigen Stunden in einer ersten Antwort und in einigen anderen Antworten gemacht wurde
Mücke