SQL Server: Indizes einschließlich aller Spalten abdecken?

9

Unser Team hat eine Anwendung und die zugehörige Datenbank geerbt. Die vorherigen Entwickler haben anscheinend eine Regel durchgesetzt, nach der jeder Index für jede Tabelle eine INCLUDE-Klausel enthält, mit der immer jede Spalte hinzugefügt wird, die ansonsten nicht Teil des Schlüssels ist. Diese Tabellen haben im Durchschnitt zwei bis fünf Indizes oder eindeutige Einschränkungen sowie Fremdschlüssel.

Die Absicht scheint darin zu bestehen, die SELECT-Leistung zu verbessern, unabhängig davon, welche Abfrage in die Datenbank geworfen wird, da der Zugriff über ein ORM erfolgt, das standardmäßig (aber nicht immer) alle Spalten abruft. Wir erwarten, dass die Nebenwirkungen davon erhöhte Speicheranforderungen (möglicherweise erheblich) und zusätzliche Overhead-Zeit für INSERT / UPDATE / DELETE sind.

Die Frage ist, ist das eine vernünftige Strategie? Unser Team hat eine lange Geschichte mit SQL Server, aber keine Mitglieder, die sich als Experten für das interne Verhalten betrachten würden (obwohl die Frage aufgeworfen wurde, ob diese Strategie nicht optimal wäre, wenn sie optimal wäre?). Welche anderen Nebenwirkungen (CPU / Speicher / TempDB-Nutzung des Datenbankservers usw.) sollten wir erwarten, oder sind einige unserer obigen Annahmen falsch?

Darüber hinaus kann die Anwendung sowohl in SQL Server On-Premise (Versionen seit 2012) als auch in Azure SQL installiert werden - sollten wir auf Unterschiede zwischen den beiden oder zusätzliche Nebenwirkungen auf Azure vorbereitet sein Ansatz?

T2PS
quelle

Antworten:

8

Ich habe dies bereits für bestimmte Indizes getan, um häufig ausgeführte Abfragen zu unterstützen. Tatsächlich haben sie mehrere Clustered-Indizes erstellt: Wenn einer dieser Indizes zum Auffinden von Zeilen verwendet wird, ist keine zusätzliche Arbeit erforderlich, um den Rest der Daten im realen Clustered-Index (oder im Heap, wenn kein realer Clustered-Index vorhanden ist) nachzuschlagen. .

Ist das eine vernünftige Strategie?

Für einige Indizes, bei denen bestimmte Abfragemuster unterstützt werden müssen, sicherlich ja.

Aber um dies mit allen Indizes zu tun , würde ich genauso sicher nein sagen.

Es wird viel Platz verschwenden, wo es nicht wirklich benötigt wird, und Einfügungen / Aktualisierungen werden erheblich verlangsamt. Es kann so viele Leseabfragen verlangsamen, wie es auch hilft, da jede Indexseite weniger Datensätze enthält, sodass jede Abfrage, die zum Filtern auf einen Teil des Index verweisen muss, aber nicht alle anderen Spalten verwendet, auf mehr Seiten zugreifen muss. Dadurch wird Ihre Datenbank speicherhungriger: Diese Seiten müssen in den Pufferpool geladen werden, wodurch möglicherweise andere nützliche Seiten ausgeworfen werden, wenn der Arbeitsspeicher knapp ist. Wenn für diese Indizes eine Komprimierung verwendet wird, um die Auswirkungen auf die Speicher- und Speicheranforderungen zu verringern, werden stattdessen die CPUs zusätzlich belastet.

Der Zugriff erfolgt über ein ORM, das standardmäßig (aber nicht immer) alle Spalten abruft

Dies ist ein häufiges Muster mit schlecht optimierter Verwendung eines ORM (oder nur naiver ORMs). In diesen Fällen habe ich gesehen, dass der Indexberater von SQL Server (und ähnliche Tools von Drittanbietern) Indizes mit vielen INCLUDEd-Spalten vorschlägt , daher stimme ich Ihrem zu Vorschlag, dass aus diesem Grund die Indizes auf diese Weise erstellt wurden.

Obwohl all diese Abfragen dadurch möglicherweise etwas schneller und einige erheblich schneller werden, vermute ich, dass in vielen Fällen der Nutzen so gering ist, dass er den zusätzlichen Speicherbedarf, den Ihr gemeinsamer Arbeitssatz, der Speicherplatz auf der Festplatte und der Festplatte benötigen, nicht wert ist die E / A zwischen Festplatte und Speicher.

Denken Sie auch daran, dass der ORM möglicherweise nicht alle Spalten aller Tabellen auswählt, die eine Abfrage berührt, sodass der Vorteil möglicherweise nur für das Hauptziel der aktuellen Anforderung gilt und die größeren Indizes die Abfrage möglicherweise benachteiligen, wenn andere Objekte zum Filtern verwendet werden aber keine Daten zurückgeben ( SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')vielleicht).

Eine weitere Überlegung für den überschüssigen Speicherplatz, insbesondere wenn die Daten groß sind, besteht darin, dass er sich auf Ihre Sicherungsstrategie auswirkt: Speicher- und Übertragungskosten für diese Sicherungen, potenzielle Wiederherstellungszeiten usw.

sollten wir auf Unterschiede zwischen den beiden vorbereitet sein [on-prem & AzureSQL]

Im Allgemeinen denke ich, dass die Überlegungen hier in jedem Fall gleich sein werden, obwohl überschüssige Speicher- / E / A-Kosten, die durch die großen Indizes verursacht werden, in Azure möglicherweise direkter sichtbar sind, wo Sie die Serviceebene und damit die Infrastrukturkosten einfacher anpassen können als mit einem relativ festen Satz von Hardwareressourcen. Wenn Sie Standard- / Premium-Ebenen anstelle von vcore-basierten Preisen verwenden, sind Sie stärker von den Standard-E / A-Kosten betroffen, da Premium deutlich mehr E / A pro DTU enthält. Wenn Sie in Azure Sicherungen oder Redundanzen für mehrere Regionen oder andere nicht lokale Funktionen verwenden, entstehen möglicherweise Bandbreitenkosten, die mit dem zusätzlichen Speicherplatz verbunden sind, den ungewöhnlich große Indizes beanspruchen.

David Spillett
quelle
Wir gingen voran und machten diese Entfernung. Ein Nebeneffekt war, dass bei bestimmten Tabellen SELECTohne Angabe ORDER BYdieselben Zeilen wie zuvor zurückgegeben wurden, jedoch mit einer anderen willkürlichen Reihenfolge.
T2PS
Das ist nicht unerwartet. Die Reihenfolge der Ergebnisse ohne 'ORDER BY' ist per Definition undefiniert und kann sich jederzeit ändern, wenn der Abfrageplaner einen anderen Ansatz wählt. Dies kann entweder aufgrund von Indexänderungen oder aufgrund von Änderungen in Ihren Datenmustern geschehen, wenn diese zunehmen. Andere Faktoren können eine solche Bestelländerung zu einem späteren Zeitpunkt auch ohne diese Änderung bewirken. Wenn Sie sich auch oberflächlich auf die Reihenfolge der Ausgabe einer Anweisung verlassen, müssen Sie ein 'ORDER BY' einfügen, um dies zu gewährleisten.
David Spillett
Oh, auf jeden Fall. Der vorherige Kommentar war eher als Erinnerung für alle gedacht, die diese Antwort später finden.
T2PS
5

Die Frage ist, ist dies eine vernünftige Strategie? .... (obwohl die Frage aufgeworfen wurde, ob diese Strategie, wenn sie optimal wäre, jetzt nicht die Standardeinstellung wäre?)

In den meisten Fällen ist dies keine vernünftige Strategie. Der Grund dafür ist, dass in allgemeinen OLTP-Datenbanken die an den Endbenutzer zurückgegebenen Zeilen nicht viel sein werden. (Verallgemeinerung)

Die Frage, die Sie sich stellen sollten, lautet: Wenn Sie in den Schlüsselspalten suchen, wie viele Zeilen werden von dieser Suchoperation zurückgegeben? Wiederholen Sie dies für die Suchanfragen in dieser Spalte.

Betrachten Sie die folgende Tabelle, in der viele Spalten zurückgegeben werden. where SelectiveIDField= ...

select columnA,columnC, ... columnZ
FROM dbo.BigTable
Where SelectiveIDField= '225122141';

Wenn nur eine Zeile von der Suche zurückgegeben wird selectiveIDField, ist die zusätzliche Schlüsselsuche so eine schlechte Sache? (Vermutlich haben Sie hier Indizes geclustert, andernfalls RID-Suche)

Es wird nur eine zusätzliche Schlüsselsuche, eine zusätzliche Ausführung + der Join-Operator durchgeführt. Selbst wenn es 10 oder sogar 100 sind, wäre es eine so große Auswirkung? Dies hängt auch davon ab, wie oft Ihre Abfrage ausgeführt wird und wie wichtig die Ausführungszeit ist.

Wenn es vernachlässigbar ist, erstellen Sie einfach den Index SelectiveIDFieldund nennen Sie ihn einen Tag. Es sollte die Lesegewinne im Vergleich zu den Schreibverlusten nicht wert sein.

Kurz gesagt, das Erstellen von Indizes für die gesamte Tabelle sollte meiner Meinung nach kein Standardansatz sein, es sei denn, Sie sehen wirklich ein Problem mit einer Abfrage und können es drastisch verbessern, indem Sie einen gesamten Abdeckungsindex hinzufügen.

Randi Vertongen
quelle