it-swarm.com.de

SQL Server: Indizes einschließlich aller Spalten abdecken?

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?

9
T2PS

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 all Indizes zu tun, würde ich genauso sicher nein sagen.

Es wird 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. Dies macht Ihre Datenbank speicherhungriger: Diese Seiten müssen in den Pufferpool geladen werden, wodurch möglicherweise andere nützliche Seiten ausgeworfen werden, wenn der Arbeitsspeicher niedrig 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 hat der Indexberater von SQL Server (und ähnliche Tools von Drittanbietern) Indizes mit vielen INCLUDEd-Spalten vorgeschlagen Ich würde Ihrem Vorschlag zustimmen, dass die Indizes aus diesem Grund 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 das IO zwischen Festplatte und Speicher.

Denken Sie auch daran, dass der ORM möglicherweise nicht alle Spalten aller Tabellen auswählt, die von einer Abfrage berührt werden, 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 optimieren können als mit einem relativ festen Satz von Hardwareressourcen. Wenn Sie Standard-/Premium-Stufen anstelle von vcore-basierten Preisen verwenden, sind Sie stärker von den IO Kosten im Standard betroffen, da die Prämie deutlich mehr IO 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.

8
David Spillett

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 im Allgemeinen OLTP Datenbanken, die an den Endbenutzer zurückgegebenen Zeilen nicht viel sind. (Generalisierung)

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 Abfragen in dieser Spalte.

Betrachten Sie die folgende Tabelle, die eine ganze Reihe von Spalten zurückgibt: where SelectiveIDField= ...

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

Wenn nur eine Zeile von der Suche nach selectiveIDField zurückgegeben wird, 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 für SelectiveIDField und 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.

5
Randi Vertongen