it-swarm.com.de

Was ist ein guter Anwendungsfall für SELECT * im Produktionscode?

Aus Gewohnheit benutze ich niemals SELECT * im Produktionscode (ich verwende ihn nur bei Ad-hoc-Ausschussabfragen, normalerweise beim Erlernen des Schemas eines Objekts). Aber ich bin jetzt auf einen Fall gestoßen, in dem ich versucht bin, ihn zu benutzen, mich aber billig fühlen würde, wenn ich es tun würde.

Mein Anwendungsfall befindet sich in einer gespeicherten Prozedur, in der eine lokale temporäre Tabelle erstellt wird, die immer mit der zugrunde liegenden Tabelle übereinstimmen sollte, mit der sie erstellt wurde, wenn die gespeicherte Prozedur ausgeführt wird. Die temporäre Tabelle wird viel später gefüllt, daher wäre ein schneller Hack, um die temporäre Tabelle zu erstellen, ohne ausführlich zu sein, SELECT * INTO #TempTable FROM RealTable WHERE 1 = 0 speziell für eine Tabelle mit Hunderten von Spalten.

Wenn der Verbraucher meiner gespeicherten Prozedur gegenüber dynamischen Ergebnismengen agnostisch ist, gibt es Probleme beim Verkauf meiner Dienste an SELECT *?

33
J.D.

Im Allgemeinen verabscheue ich SELECT * im Produktionscode und war in einer Situation, in der seine Verwendung später zu massiven Nacharbeiten führte. Ihr Fall sieht jedoch nach einer fairen Verwendung aus.

Der Ort, an dem SELECT * ein Muss ist - und sein böser Cousin "INSERT INTO tbl" ohne Spaltenliste - befindet sich in einer Archivierungssituation, in der Zeilen in eine andere Tabelle verschoben werden, die dieselbe Struktur haben muss.

INSERT INTO SalesOrderArchive  -- Note no column list
SELECT *
  FROM SalesOrder
 WHERE OrderDate < @OneYearAgo

DELETE FROM SalesOrder
 WHERE OrderDate < @OneYearAgo

Wenn SalesOrder in Zukunft eine neue Spalte hinzugefügt wird, SalesOrderArchive jedoch nicht, schlägt INSERT fehl. Was sich schlecht anhört, aber eigentlich eine wirklich gute Sache ist! Weil die Alternative viel schlimmer ist. Wenn alle Spalten in INSERT und SELECT aufgelistet wären, wäre INSERT erfolgreich, ebenso wie das folgende DELETE (was effektiv "DELETE *" ist). Erfolgreicher Produktionscode wird nicht beachtet, und es kann lange dauern, bis jemand bemerkt, dass die neue Spalte nicht archiviert, sondern stillschweigend gelöscht wird.

48
Rusty

Was nützt select * in der Produktion?

IMO nur solche Dinge:

z.B

create table #foo(a int, b int, c int, d int)
...
select * from #foo

oder

with q as
(
  select a, b, c
  from ...
)
select *
from q

dh wenn die * ist an eine explizite Spaltenliste gebunden, die im selben Stapel deklariert ist, und wird nur verwendet, um zu vermeiden, dass die Spaltenliste mehrmals wiederholt wird.

Wenn die * bezieht sich auf eine Tabelle oder Ansicht, es gibt einige unangenehme Komplexitäten bei zwischengespeicherten Metadaten, z. B. hier . Und es erspart Ihnen nicht wirklich die Eingabe, da Sie mit SSMS die gesamte Spaltenliste per Drag & Drop verschieben können.

Eine gültige Verwendung von SELECT * tritt auf, wenn es durch EXISTS eingeführt wird.

WHERE EXISTS (SELECT * FROM ...

Wie alle Verwendungen von SELECT *, dies hat den unerwünschten (und hier unnötigen) Nebeneffekt, WITH SCHEMABINDING wird nicht hinzugefügt, wenn sich der Code innerhalb von z. eine Funktion.

Verwandte Fragen und Antworten: EXISTS (SELECT 1 ...) vs EXISTS (SELECT * ...) Das eine oder andere?

Siehe auch:

20
user195591

Ich werde fett sein und es sagen: Es gibt Anwendungsfälle für SELECT * im Produktionscode. Sie können jederzeit sagen: "Ich möchte, dass Änderungen an der Tabelle sofort in einer Änderung meines Ergebnisses berücksichtigt werden Ausgabe "ist ein Fall dafür.

Lassen Sie mich einige Beispiele nennen:

Anwendungsfall 1 - Erstellen Sie eine Ansicht, die die Haupttabelle widerspiegelt, außer dass sie die vertraulichen Unternehmensdaten herausfiltert.

In diesem Fall soll die Ansicht SELECT * sein. Die Ausgabe soll die Haupttabelle widerspiegeln. Die Übereinstimmung des Ausgabelayouts mit dem Tabellenlayout ist eine Funktion und kein Fehler.

...

Anwendungsfall Nr. 2 - Erstellen Sie einen gespeicherten Prozess, der einige Datensätze, die Sie aktualisieren möchten, in eine temporäre Haltetabelle kopiert, falls bei dem Prozess Probleme auftreten (es ist ein bisschen schuppig).

In diesem Fall ist es schrecklich, eine Ausgabe zu haben, die nicht mit der Tabelle selbst übereinstimmt. Dies bedeutet, dass Sie die Daten in der temporären Haltetabelle möglicherweise nicht verwenden können, um zu Ihrem Ausgangspunkt zurückzukehren.

7
Kevin

Was nützt select * in der Produktion?

Wirklich nicht. Bei der Entwicklung auf die von Ihnen erwähnte Weise (wählen Sie oben n * aus) ist dies sinnvoll, entwickelt aber ansonsten schlechte Gewohnheiten und kann zu Problemen führen.

Sie haben den Hauptpunkt angesprochen, warum Sie sollten es verwenden, und das ist die Struktur der tatsächlichen Tabelle, die sich ändern könnte. Das Erstellen einer temporären Tabelle, wie Sie sie erwähnt haben, ist alles in Ordnung, aber wo es Sie später in Ihrem Prozess erreichen könnte, nachdem Sie die temporäre Tabelle mit einigen INSERT Befehlen gefüllt haben, geben Sie die Ergebnismenge mit SELECT *. Jetzt würde Ihre Endanwendung Spalten abrufen, die nicht erwartet werden.

Sie können SELECT ... INTO #TEMP FROM ... Verwenden, um die temporäre Tabelle auch im laufenden Betrieb zu erstellen. Es ist schwer zu wissen, welches für Ihre Situation am besten geeignet ist.

Die meisten anderen Probleme mit SELECT * Scheinen für Ihren Anwendungsfall keine Rolle zu spielen

  • Erstellen einer Ansicht (kann unterbrochen werden, wenn sich die Tabelle ändert)
  • Bindungsprobleme
  • Tabellenscan (da Sie tatsächlich alle Spalten möchten)
  • Abrufen unnötiger Spalten (da Sie anscheinend wieder alle möchten) und ihrer Ordnungsposition
6
scsimon

Meine Antwort auf Ihre Frage lautet "Die meisten/viele Anwendungsfälle".

Ihre Anwendungsfälle zeigen, warum * nicht schrecklich ist. Ihr Schema wird sich ändern. Warum sollten Sie sich darauf einstellen, jedes einzelne zu berühren SP, weil Sie ein Feld hinzufügen müssen?

Wenn Sie ein Feld hinzufügen, warum sollte es meine Benutzeroberfläche interessieren? Wenn Sie ein Feld löschen, spielt es keine Rolle, ob Sie * oder eine CSV verwenden. Sie führen eine wichtige Änderung ein.

"Wenn der Verbraucher meiner gespeicherten Prozedur gegenüber dynamischen Ergebnismengen agnostisch ist, ..."

Hier liegt das wahre Problem mit select *. Wenn Ihr Verbraucher schlecht geschrieben ist, können Probleme auftreten. Wenn Sie beispielsweise Felder [13] als Datum formatieren ...

Einige Fälle, in denen ich mich davor scheuen würde, * auszuwählen :

Latenzminderung - Mein Verbraucher ist weit entfernt und benötigt nur eine relativ kleine Teilmenge von Feldern in den Tabellen.

Joins - Komplexe Abfrage mit mehreren Tabellen. Der Verbraucher benötigt wahrscheinlich nicht alle Felder aus allen Tabellen. Tatsächlich gibt es doppelte Schlüsselspalten, die wahrscheinlich weggelassen werden sollten.

Ich weiß, dass meine Konsumenten schlechten Code schreiben - Wenn Sie eine öffentliche API entwickeln, ist es wahrscheinlich möglich, dass Sie OpenClose ehren und jedes Mal eine neue API-Methode erstellen, wenn sich der Feldsatz ändert. Für mich scheint dies eine schlechte Herangehensweise an dieses Problem zu sein ...

Wie bei allem mit Programmierung gibt es eine Zeit und einen Ort. Es ist immer der Elfenbeinturm gesetzt. Hören Sie offen auf ihre Gedanken. Dann entscheide dich selbst.

1
greg

dies hängt von dem von Ihnen bevorzugten Fehlermechanismus ab.

Wenn eine neue Spalte beim Hinzufügen immer ignoriert werden kann (z. B. Vorname, Nachname von Kunden mit id = @ x auswählen), verwenden Sie niemals select * - je mehr Spalten Sie berühren, desto geringer ist die Wahrscheinlichkeit, dass ein hilfreicher Index angezeigt wird kann gefunden/erstellt werden.

Wenn das Hinzufügen einer neuen Spalte beim stillen Verwerfen schlecht wäre (jede Art von Datenreplikation), verwenden Sie eine nicht angegebene Auswahl (in archiveTable einfügen select * from theTable, wobei isOld = true). Der Codefehler hier ist kein Fehler ist eine Funktion - insbesondere in dem Fall, in dem Sie sowohl die Datenbank als auch den Code steuern, der die Tabelle liest.

Das Umkehren der Fehlermechanismen hier ist schlecht - Sie möchten nicht, dass Ihre Namenssuche fehlschlägt, wenn Sie der Person eine neue Lieblingsfarbe hinzufügen.

sie möchten die Archivierung der Lieblingsfarbe der Person nicht ignorieren, wenn die Spalte nach dem Schreiben des Archivierungscodes hinzugefügt wurde.

Ein Hinweis zu Joins - SQL Server überspringt das Lesen von Spalten, die später nicht verwendet werden

select firtname,email from (select * from profile where isArchived=false)p join (select * from emailaddresses where mostRecentSend < ago(6days))e on p.id=e.profileId

berührt nichts anderes als die Spalten Vorname, ID und E-Mail.

0
Andrew Hill