Beeinflussen nicht relevante Spalten die Abfragezeit ausgewählter Anweisungen?

10

Ich bin nur Neugierig.

Angenommen, Sie haben eine Tabelle mit 1 Million Datensätzen / Zeilen.

select order_value from store.orders

Macht es einen Unterschied, ob diese Tabelle in der tatsächlichen Abfragezeit 1 Feld, 2 Felder oder 100 Felder enthält? Ich meine alle Felder außer "order_value".

Im Moment schiebe ich Daten in ein Data Warehouse. Manchmal speichere ich Felder in die Tabelle, die "eines Tages in der Zukunft verwendet werden könnten" - aber sie werden momentan von nichts abgefragt. Würden diese "fremden" Felder ausgewählte Anweisungen beeinflussen, die sie weder direkt noch indirekt enthalten (nein * ich meine)?

user45867
quelle
Es gibt unzählige Informationen dazu im Internet. Der Schlüssel ist, die neuesten Informationen zu erhalten, wenn sich die Technologie ändert. Was Sie fragen, hängt so stark von Ihrem speziellen Setup ab, dass es nicht möglich ist, eine sehr gute Antwort zu geben. Ein wichtiger Punkt, an den Sie sich erinnern sollten, ist, dass bei der Umstellung auf SSD viele Dinge, die früher für die Leistung sehr wichtig waren, nicht mehr der Fall sind.
Joe

Antworten:

10

Dies hängt wirklich von Indizes und Datentypen ab.

Am Beispiel der Stapelüberlaufdatenbank sieht die Benutzertabelle folgendermaßen aus:

NÜSSE

Es hat eine PK / CX in der ID-Spalte. Es ist also die Gesamtheit der Tabellendaten, sortiert nach ID.

Mit diesem als einzigem Index muss SQL das Ganze (ohne die LOB-Spalten) in den Speicher lesen, wenn es nicht bereits vorhanden ist.

DBCC DROPCLEANBUFFERS-- Don't run this anywhere near prod.

SET STATISTICS TIME, IO ON 

SELECT u.Id
INTO  #crap1
FROM dbo.Users AS u

Die Statistikzeit und das io-Profil sehen folgendermaßen aus:

Table 'Users'. Scan count 7, logical reads 80846, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2406 ms,  elapsed time = 446 ms.

Wenn ich einen zusätzlichen nicht gruppierten Index nur für Id hinzufüge

CREATE INDEX ix_whatever ON dbo.Users (Id)

Ich habe jetzt einen viel kleineren Index, der meine Anfrage erfüllt.

DBCC DROPCLEANBUFFERS-- Don't run this anywhere near prod.

SELECT u.Id
INTO  #crap2
FROM dbo.Users AS u

Das Profil hier:

Table 'Users'. Scan count 7, logical reads 6587, physical reads 0, read-ahead reads 6549, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 2344 ms,  elapsed time = 384 ms.

Wir können viel weniger Lesevorgänge durchführen und ein wenig CPU-Zeit sparen.

Ohne weitere Informationen zu Ihrer Tabellendefinition kann ich nicht wirklich versuchen, das, was Sie messen möchten, besser zu reproduzieren.

Sie sagen jedoch, dass die anderen Spalten / Felder ebenfalls gescannt werden, sofern für diese einzelne Spalte kein bestimmter Index vorhanden ist? Ist dies nur ein Nachteil des Designs von Rowstore-Tabellen? Warum sollten irrelevante Felder gescannt werden?

Ja, dies gilt speziell für Rowstore-Tabellen. Daten werden durch die Zeile auf Datenseiten gespeichert. Selbst wenn andere Daten auf der Seite für Ihre Abfrage irrelevant sind, muss die gesamte Zeile> Seite> Index in den Speicher eingelesen werden. Ich würde nicht sagen, dass die anderen Spalten so oft "gescannt" werden, wie die Seiten, auf denen sie existieren, gescannt werden, um den für die Abfrage relevanten Einzelwert auf ihnen abzurufen.

Verwenden des alten Telefonbuchbeispiels: Selbst wenn Sie nur Telefonnummern lesen, blättern Sie beim Umblättern Nachname, Vorname, Adresse usw. zusammen mit der Telefonnummer.

Erik Darling
quelle
@ jpmc26 Es kann schlimmer werden, denn wenn die angeforderten Spalten alle Teil eines Index sind, kann die Abfrage nur durch Betrachten des Index bedient werden. Wenn die Spalten nicht indiziert sind, können sie dazu führen, dass der primäre Datensatz und sogar sekundäre Datensätze für nicht gruppierte Tabellen- / Spaltentypen geladen werden.
Christopher Schultz
12

Dies hängt von der Tabellenstruktur und den verfügbaren Indizes ab.

  • Fall A: Allgemeine (Rowstore-) Tabelle, kein Index für (order_value).

    Der einzig mögliche Ausführungsplan besteht darin, die gesamte Tabelle zu lesen (was natürlich sehr unterschiedlich ist, wenn es sich um 2 gegen 200 Spalten handelt, also um einige gegen einige tausend Bytes).

  • Fall B: Allgemeine Tabelle, es gibt einen Index für (order_value)oder einige andere Indizes, die diese Spalte enthalten.

    Es gibt jetzt einen besseren Plan: Scannen Sie den gesamten Index (einen davon) - der natürlich viel enger ist als die gesamte Tabelle, nur ein paar Bytes. Was irrelevant macht, wenn die Tabelle 2 oder 200 Spalten hat. Es wird nur der Index gescannt.

  • Fall C: Es ist eine Columnstore-Tabelle.

    Wie der Name schon sagt, ist die Struktur dieser Tabellen spaltenorientiert und nicht zeilenweise. Es ist kein Index erforderlich, das Tabellendesign selbst eignet sich zum Lesen ganzer Spalten.

ypercubeᵀᴹ
quelle
Mein Wissen ist in dieser Frage etwas grün. Es ist am üblichsten (sagen wir typische SQL Server-Datenbank), Rowstore-Tabellen zu haben, richtig? Warum sollte die gesamte Tabelle gescannt werden, wenn nur eine Spalte / ein Feld zurückgegeben werden muss? Ist dies nur dem Design von Rowstore-Tabellen eigen?
user45867
@ user45867 Ja, die Daten werden in Zeilen gespeichert (mit Ausnahme einiger sehr großer Spalten, die außerhalb gespeichert sind). Wenn SQL Server von der Festplatte liest, liest es ganze Blöcke ein und kann nicht nur den Teil lesen, der eine Spalte enthält.
Ypercubeᵀᴹ