Wenn ich nur 2/3 Spalten brauche und abfrage SELECT *
anstatt diese Spalten in einer ausgewählten Abfrage bereitzustellen, gibt es Leistungseinbußen in Bezug auf mehr / weniger E / A oder Speicher?
Der Netzwerk-Overhead kann vorhanden sein, wenn ich * ohne Notwendigkeit auswähle.
Zieht das Datenbankmodul bei einer Auswahloperation immer ein Atomtupel von der Festplatte oder nur die Spalten, die bei der Auswahloperation angefordert wurden?
Wenn immer ein Tupel gezogen wird, ist der E / A-Overhead derselbe.
Gleichzeitig kann es zu einem Speicherverbrauch kommen, um die angeforderten Spalten aus dem Tupel zu entfernen, wenn ein Tupel gezogen wird.
Wenn dies der Fall ist, hat select someColumn mehr Speicheraufwand als select *
sql
performance
Neel Basu
quelle
quelle
SELECT
die Ausführung / Verarbeitung von Abfragen von Datenbank zu Datenbank unterschiedlich ist.CREATE VIEW foo_view AS SELECT * FROM foo;
später Spalten zur Tabelle foo hinzufügen, werden diese Spalten nicht automatisch wie erwartet in foo_view angezeigt. Mit anderen Worten, das wird*
in diesem Kontext nur einmal (zum Zeitpunkt der Ansichtserstellung) erweitert, nicht per SELECT. Aufgrund von Komplikationen, die sich aus ALTER TABLE ergeben, würde ich sagen, dass (in der Praxis)*
als schädlich angesehen wird.Antworten:
Es wird immer ein Tupel gezogen (außer in Fällen, in denen die Tabelle vertikal segmentiert wurde - in Spalten aufgeteilt). Um die von Ihnen gestellte Frage zu beantworten, spielt dies aus Sicht der Leistung keine Rolle. Aus vielen anderen Gründen (unten) sollten Sie jedoch immer speziell die gewünschten Spalten nach Namen auswählen.
Es wird immer ein Tupel gezogen, da (in jedem mir bekannten RDBMS eines Anbieters) die zugrunde liegende Speicherstruktur auf der Festplatte für alles (einschließlich Tabellendaten) auf definierten E / A-Seiten basiert (in SQL Server beispielsweise für jede Seite) 8 Kilobyte). Und jedes Lesen oder Schreiben von E / A erfolgt nach Seiten. Das heißt, jedes Schreiben oder Lesen ist eine vollständige Seite mit Daten.
Aufgrund dieser zugrunde liegenden strukturellen Einschränkung muss sich jede Datenzeile in einer Datenbank immer auf einer und nur einer Seite befinden. Es kann nicht mehrere Datenseiten umfassen (mit Ausnahme spezieller Dinge wie Blobs, bei denen die tatsächlichen Blob-Daten in separaten Seitenblöcken gespeichert werden und die tatsächliche Tabellenzeilenspalte dann nur einen Zeiger erhält ...). Diese Ausnahmen sind jedoch nur Ausnahmen und gelten im Allgemeinen nur in besonderen Fällen (für besondere Datentypen oder bestimmte Optimierungen für besondere Umstände).
Selbst in diesen besonderen Fällen gilt im Allgemeinen die tatsächliche Tabellenzeilenzeile selbst (die enthält) Der Zeiger auf die tatsächlichen Daten für den Blob oder was auch immer) muss auf einer einzelnen E / A-Seite gespeichert werden ...
AUSNAHME. Der einzige Ort, an dem
Select *
OK ist, befindet sich in der Unterabfrage nach einerExists
oderNot Exists
Prädikatklausel, wie in:BEARBEITEN: Um den Kommentar von @Mike Sherer anzusprechen: Ja, es ist wahr, sowohl technisch, mit ein wenig Definition für Ihren speziellen Fall, als auch ästhetisch. Erstens muss der Abfrageprozessor aus den gleichen Gründen jede Spalte abrufen, die in einem Index gespeichert ist, und nicht nur die angeforderten, aus denselben Gründen - ALLE E / A müssen in ausgeführt werden Seiten und Indexdaten werden wie Tabellendaten in E / A-Seiten gespeichert. Wenn Sie also "Tupel" für eine Indexseite als die im Index gespeicherten Spalten definieren, ist die Anweisung weiterhin wahr.
und die Aussage ist ästhetisch wahr, weil der Punkt ist, dass sie Daten basierend auf dem abruft, was auf der E / A-Seite gespeichert ist, nicht auf dem, was Sie verlangen, und dies wahr, ob Sie auf die E / A-Seite der Basistabelle oder einen Index zugreifen E / A-Seite.
Weitere Gründe für die Nichtverwendung
Select *
finden Sie unter Warum wird diesSELECT *
als schädlich angesehen? ::quelle
select *
ist der Speicheraufwand geringer als derselect column
gleiche E / A-Aufwand. Also, wenn wir den Netzwerk-Overhead verlassen.select *
wenn weniger Overhead als der vonselect column
Es gibt mehrere Gründe, die Sie niemals (niemals)
SELECT *
im Produktionscode verwenden sollten:Da Sie Ihrer Datenbank keine Hinweise geben, was Sie möchten, muss sie zuerst die Definition der Tabelle überprüfen, um die Spalten in dieser Tabelle zu bestimmen. Diese Suche kostet einige Zeit - nicht viel in einer einzelnen Abfrage - aber sie summiert sich im Laufe der Zeit
Wenn Sie nur 2/3 der Spalten benötigen, wählen Sie 1/3 zu viele Daten aus, die von der Festplatte abgerufen und über das Netzwerk gesendet werden müssen
Wenn Sie sich auf bestimmte Aspekte der Daten verlassen, z. B. die Reihenfolge der zurückgegebenen Spalten, kann es zu einer bösen Überraschung kommen, wenn die Tabelle neu organisiert und neue Spalten hinzugefügt (oder vorhandene entfernt) werden.
Wenn Sie in SQL Server (bei anderen Datenbanken nicht sicher) eine Teilmenge von Spalten benötigen, besteht immer die Möglichkeit, dass ein nicht gruppierter Index diese Anforderung abdeckt (enthält alle erforderlichen Spalten). Mit a geben
SELECT *
Sie diese Möglichkeit von Anfang an auf. In diesem speziellen Fall würden die Daten von den Indexseiten abgerufen (wenn diese alle erforderlichen Spalten enthalten), und somit wären die Festplatten-E / A und der Speicheraufwand im Vergleich zur Durchführung einerSELECT *....
Abfrage viel geringer .Ja, die Eingabe erfordert anfangs etwas mehr Zeit (Tools wie SQL Prompt for SQL Server helfen Ihnen sogar dabei) - aber dies ist wirklich ein Fall, in dem es ausnahmslos eine Regel gibt: Verwenden Sie niemals SELECT * in Ihrem Produktionscode. JE.
quelle
Where Exists (Select * From ...
). Die Verwendung vonSelect *
ist sicherlich kein Problem und wird in einigen Kreisen als bewährte Methode angesehen.IF EXISTS(SELECT *...
ist ein Sonderfall - da dort keine Daten wirklich abgerufen werden, aber es nur eine Überprüfung auf Existenz ist, ist das SELECT * dort kein Problem ...Sie sollten immer nur
select
die Spalten verwenden, die Sie tatsächlich benötigen. Es ist nie weniger effizient, weniger statt mehr auszuwählen, und Sie haben auch weniger unerwartete Nebenwirkungen - wie den Zugriff auf Ihre Ergebnisspalten auf der Clientseite über den Index, und dann werden diese Indizes durch Hinzufügen einer neuen Spalte zur Tabelle falsch.[Bearbeiten]: Bedeutet Zugriff. Dummes Gehirn wacht immer noch auf.
quelle
SELECT *
sie damit zu verwenden.Wenn Sie keine großen Blobs speichern, spielt die Leistung keine Rolle. Der Hauptgrund, SELECT * nicht zu verwenden, besteht darin, dass bei Verwendung von zurückgegebenen Zeilen als Tupel die Spalten in der vom Schema angegebenen Reihenfolge zurückgegeben werden. Wenn sich dies ändert, müssen Sie den gesamten Code korrigieren.
Wenn Sie dagegen den Zugriff im Wörterbuchstil verwenden, spielt es keine Rolle, in welcher Reihenfolge die Spalten wieder angezeigt werden, da Sie immer über den Namen auf sie zugreifen.
quelle
Dies lässt mich sofort an eine Tabelle denken, die ich verwendet habe und die eine Spalte vom Typ enthielt
blob
. Es enthielt normalerweise ein JPEG-Bild mit einerMb
Größe von einigen Sekunden.Unnötig zu erwähnen, dass ich diese
SELECT
Kolumne nicht verwendet habe , es sei denn, ich brauchte sie wirklich . Es war nur ein Ärger, diese Daten im Umlauf zu haben - besonders wenn ich mehrere Zeilen ausgewählt habe.Ich gebe jedoch zu, dass ich sonst normalerweise alle Spalten in einer Tabelle abfrage.
quelle
Während einer SQL-Auswahl verweist die Datenbank immer auf die Metadaten für die Tabelle, unabhängig davon, ob es sich um SELECT * für SELECT a, b, c handelt ... Warum? Denn dort befinden sich die Informationen zur Struktur und zum Layout der Tabelle im System.
Diese Informationen müssen aus zwei Gründen gelesen werden. Erstens, um die Aussage einfach zusammenzustellen. Es muss sichergestellt sein, dass Sie mindestens eine vorhandene Tabelle angeben. Außerdem hat sich möglicherweise die Datenbankstruktur seit der letzten Ausführung einer Anweisung geändert.
Natürlich werden DB-Metadaten im System zwischengespeichert, aber es muss noch verarbeitet werden.
Als Nächstes werden die Metadaten zum Generieren des Abfrageplans verwendet. Dies geschieht jedes Mal, wenn eine Anweisung ebenfalls kompiliert wird. Dies läuft wiederum gegen zwischengespeicherte Metadaten, wird aber immer ausgeführt.
Diese Verarbeitung wird nur dann nicht durchgeführt, wenn die Datenbank eine vorkompilierte Abfrage verwendet oder eine vorherige Abfrage zwischengespeichert hat. Dies ist das Argument für die Verwendung von Bindungsparametern anstelle von wörtlichem SQL. "SELECT * FROM TABLE WHERE key = 1" ist eine andere Abfrage als "SELECT * FROM TABLE WHERE key =?" und die "1" ist an den Anruf gebunden.
DBs sind für ihre Arbeit stark auf das Zwischenspeichern von Seiten angewiesen. Viele moderne DBs sind klein genug, um vollständig in den Speicher zu passen (oder, vielleicht sollte ich sagen, der moderne Speicher ist groß genug, um in viele DBs zu passen). Dann sind Ihre primären E / A-Kosten im Back-End Protokollierung und Seitenlöschung.
Wenn Sie jedoch immer noch auf die Festplatte für Ihre Datenbank zugreifen, besteht eine Hauptoptimierung vieler Systeme darin, sich auf die Daten in Indizes und nicht auf die Tabellen selbst zu verlassen.
Wenn Sie haben:
Wenn Sie dann "ID AUSWÄHLEN, Name VON Kunde WHERE ID = 1" ausführen, ist es sehr wahrscheinlich, dass Ihre Datenbank diese Daten aus dem Index und nicht aus den Tabellen abruft.
Warum? Der Index wird wahrscheinlich trotzdem verwendet, um die Abfrage zu erfüllen (im Vergleich zu einem Tabellenscan), und obwohl 'name' in der where-Klausel nicht verwendet wird, ist dieser Index immer noch die beste Option für die Abfrage.
Jetzt verfügt die Datenbank über alle Daten, die zur Erfüllung der Abfrage erforderlich sind. Es gibt also keinen Grund, die Tabellenseiten selbst aufzurufen. Die Verwendung des Index führt zu weniger Festplattenverkehr, da der Index eine höhere Zeilendichte aufweist als die Tabelle im Allgemeinen.
Dies ist eine handwellige Erklärung einer bestimmten Optimierungstechnik, die von einigen Datenbanken verwendet wird. Viele haben verschiedene Optimierungs- und Optimierungstechniken.
Am Ende ist SELECT * nützlich für dynamische Abfragen, die Sie manuell eingeben müssen. Ich würde es niemals für "echten Code" verwenden. Durch die Identifizierung einzelner Spalten erhält die Datenbank mehr Informationen, mit denen sie die Abfrage optimieren kann, und Sie können Ihren Code besser gegen Schemaänderungen usw. steuern.
quelle
Ich denke, es gibt keine genaue Antwort auf Ihre Frage, da Sie über die Leistung und die Möglichkeit nachdenken, Ihre Apps zu warten.
Select column
ist performativerselect *
, aber wenn Sie ein orientiertes Objektsystem entwickeln, dann werden Sie die Verwendung mögenobject.properties
und Sie können Eigenschaften in jedem Teil von Apps benötigen, dann müssen Sie mehr Methoden schreiben, um Eigenschaften in speziellen Situationen zu erhalten, wenn Sie dies nicht tun Verwendenselect *
und füllen Sie alle Eigenschaften. Ihre Apps müssen eine gute Leistung aufweisen,select *
und in einigen Fällen müssen Sie eine Auswahlspalte verwenden, um die Leistung zu verbessern. Dann haben Sie die bessere von zwei Welten, die Möglichkeit, Apps und Leistung zu schreiben und zu warten, wenn Sie Leistung benötigen.quelle
Die hier akzeptierte Antwort ist falsch. Ich bin darauf gestoßen, als eine andere Frage als Duplikat davon geschlossen wurde (während ich noch meine Antwort schrieb - grr - daher verweist die folgende SQL auf die andere Frage).
Sie sollten immer das SELECT-Attribut, das Attribut .... NOT SELECT * verwenden
Es ist in erster Linie für Leistungsprobleme.
Ist kein sehr nützliches Beispiel. Betrachten Sie stattdessen:
Wenn ein Index aktiviert ist (Name, Telefon), kann die Abfrage gelöst werden, ohne dass die relevanten Werte aus der Tabelle nachgeschlagen werden müssen - es gibt einen abdeckenden Index.
Angenommen, die Tabelle enthält ein BLOB mit einem Bild des Benutzers und einem hochgeladenen Lebenslauf sowie eine Tabelle. Wenn Sie SELECT * verwenden, werden alle diese Informationen in die DBMS-Puffer zurückgeführt (wodurch andere nützliche Informationen aus dem Cache entfernt werden). Dann wird alles an den Client gesendet, wobei die Betriebszeit im Netzwerk und der Speicher auf dem Client für redundante Daten verwendet werden.
Dies kann auch zu Funktionsproblemen führen, wenn der Client die Daten als aufgezähltes Array abruft (z. B. mysql_fetch_array ($ x, MYSQL_NUM) von PHP). Vielleicht war 'Telefon', als der Code geschrieben wurde, die dritte Spalte, die von SELECT * zurückgegeben wurde, aber dann kommt jemand und beschließt, der Tabelle eine E-Mail-Adresse hinzuzufügen, die vor 'Telefon' steht. Das gewünschte Feld wird nun in die 4. Spalte verschoben.
quelle
Es gibt Gründe, Dinge so oder so zu tun. Ich verwende SELECT * häufig in PostgreSQL, da Sie mit SELECT * in PostgreSQL viele Dinge tun können, die Sie mit einer expliziten Spaltenliste nicht tun können, insbesondere in gespeicherten Prozeduren. In ähnlicher Weise kann SELECT * über einem geerbten Tabellenbaum in Informix zu gezackten Zeilen führen, während eine explizite Spaltenliste dies nicht kann, da zusätzliche Spalten in untergeordneten Tabellen ebenfalls zurückgegeben werden.
Der Hauptgrund, warum ich dies in PostgreSQL mache, ist, dass es sicherstellt, dass ich einen wohlgeformten Typ bekomme, der für eine Tabelle spezifisch ist. Dadurch kann ich die Ergebnisse als Tabellentyp in PostgreSQL verwenden. Dies ermöglicht auch viel mehr Optionen in der Abfrage als eine starre Spaltenliste.
Auf der anderen Seite können Sie anhand einer starren Spaltenliste überprüfen, ob sich die Datenbankschemata auf bestimmte Weise nicht geändert haben. Dies kann hilfreich sein. (Ich mache solche Überprüfungen auf einer anderen Ebene.)
In Bezug auf die Leistung verwende ich normalerweise VIEWs und gespeicherte Prozeduren, die Typen zurückgeben (und dann eine Spaltenliste innerhalb der gespeicherten Prozedur). Dies gibt mir die Kontrolle darüber, welche Typen zurückgegeben werden.
Aber denken Sie daran, dass ich SELECT * normalerweise für eine Abstraktionsschicht anstelle von Basistabellen verwende.
quelle
Referenz aus diesem Artikel:
Ohne SELECT *: Wenn Sie zu diesem Zeitpunkt "SELECT *" verwenden, wählen Sie weitere Spalten aus der Datenbank aus, und einige dieser Spalten werden möglicherweise nicht von Ihrer Anwendung verwendet. Dies führt zu zusätzlichen Kosten und einer Belastung des Datenbanksystems und zu mehr Datenübertragungen über das Netzwerk.
Mit SELECT *: Wenn Sie spezielle Anforderungen haben und beim Hinzufügen oder Löschen eine Spalte erstellt haben, die automatisch nach Anwendungscode behandelt wird. 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
Nur um der Diskussion eine Nuance hinzuzufügen, die ich hier nicht sehe: In Bezug auf E / A, wenn Sie eine Datenbank mit spaltenorientiertem Speicher verwenden verwenden, VIEL weniger E / A ausführen, wenn Sie nur bestimmte Fragen stellen Säulen. Wenn wir zu SSDs wechseln, sind die Vorteile im Vergleich zum zeilenorientierten Speicher möglicherweise etwas geringer, aber es gibt a) nur das Lesen der Blöcke, die Spalten enthalten, die Ihnen wichtig sind, b) die Komprimierung, wodurch die Größe der Daten auf der Festplatte und damit die Daten im Allgemeinen erheblich reduziert werden Datenvolumen von der Festplatte gelesen.
Wenn Sie mit spaltenorientiertem Speicher nicht vertraut sind, stammt eine Implementierung für Postgres von Citus Data, eine andere für Greenplum, eine andere für Paraccel und eine andere (lose gesagt) für Amazon Redshift. Für MySQL gibt es Infobright, die mittlerweile fast nicht mehr existierende InfiniDB. Weitere kommerzielle Angebote sind Vertica von HP, Sybase IQ, Teradata ...
quelle
gleich
quelle