it-swarm.com.de

Indizierte Ansichten für Aggregate verwenden - zu gut um wahr zu sein?

Wir haben ein Data Warehouse mit einer ziemlich großen Datensatzanzahl (10 bis 20 Millionen Zeilen) und führen häufig Abfragen aus, die Datensätze zwischen bestimmten Daten zählen, oder Datensätze mit bestimmten Flags, z.

SELECT
    f.IsFoo,
    COUNT(*) AS WidgetCount
FROM Widgets AS w
JOIN Flags AS f
    ON f.FlagId = w.FlagId
WHERE w.Date >= @startDate
GROUP BY f.IsFoo

Die Leistung ist nicht schlecht, kann aber relativ träge sein (vielleicht 10 Sekunden in einem kalten Cache).

Kürzlich entdeckte ich, dass ich GROUP BY In indizierten Ansichten verwenden kann, und probierte daher etwas Ähnliches wie das Folgende aus

CREATE VIEW TestView
WITH SCHEMABINDING
AS
    SELECT
        Date,
        FlagId,
        COUNT_BIG(*) AS WidgetCount
    FROM Widgets
    GROUP BY Date, FlagId;
GO

CREATE UNIQUE CLUSTERED INDEX PK_TestView ON TestView
(
    Date,
    FlagId
);

Infolgedessen ist die Leistung meiner ersten Abfrage jetzt <100 ms und die resultierende Ansicht und der Index sind <100.000 (obwohl unsere Zeilenanzahl groß ist, bedeutet der Bereich von Datumsangaben und Flag-IDs, dass diese Ansicht nur 1000-2000 Zeilen enthält).

Ich dachte, dass dies möglicherweise die Leistung von Schreibvorgängen in die Widget-Tabelle verdreifachen würde, aber nein - die Leistung von Einfügungen und Aktualisierungen in diese Tabelle wird, soweit ich das beurteilen kann, so gut wie nicht beeinflusst (außerdem wird diese Tabelle als Data Warehouse nur selten aktualisiert wie auch immer)

Für mich scheint das viel zu schön, um wahr zu sein - oder? Worauf muss ich achten, wenn ich indizierte Ansichten auf diese Weise verwende?

28
Justin

Wie Sie bereits bemerkt haben, materialisiert die Ansicht selbst nur eine kleine Anzahl von Zeilen. Selbst wenn Sie die gesamte Tabelle aktualisieren, ist die mit der Aktualisierung der Ansicht verbundene zusätzliche E/A vernachlässigbar. Sie haben wahrscheinlich bereits den größten Schmerz gespürt, den Sie beim Erstellen der Ansicht spüren werden. Der nächstgelegene ist, wenn Sie der Basistabelle eine Unmenge Zeilen mit einer Reihe neuer IDs hinzufügen, für die neue Zeilen in der Ansicht erforderlich sind.

Das ist nicht gut, um wahr zu sein. Sie verwenden indizierte Ansichten genau so, wie sie verwendet werden sollten - oder zumindest eine der effektivsten Möglichkeiten: Sie zahlen für zukünftige Abfrageaggregationen zum Zeitpunkt des Schreibens. Dies funktioniert am besten, wenn das Ergebnis viel kleiner als die Quelle ist und natürlich, wenn die Aggregationen häufiger angefordert werden als die zugrunde liegenden Daten aktualisiert werden (in DW häufiger als in OLTP im Allgemeinen).

Leider halten viele Leute das Indizieren einer Ansicht für magisch - ein Index macht nicht alle Ansichten effizienter, insbesondere Ansichten, die einfach Tabellen verbinden und/oder die gleiche Anzahl von Zeilen wie die Quelle erzeugen (oder sogar multiplizieren). In diesen Fällen ist die E/A in der Ansicht dieselbe oder sogar schlechter als die ursprüngliche Abfrage, nicht nur, weil dieselben oder mehrere Zeilen vorhanden sind, sondern häufig werden auch mehr Spalten gespeichert und materialisiert. Das Materialisieren dieser Daten im Voraus bringt also keine Vorteile, da E/A, Netzwerk und Client-Verarbeitung/-Rendering selbst bei SSDs immer noch die primären Engpässe bei der Rückgabe großer Ergebnismengen an den Client bleiben. Die Einsparungen, die Sie durch das Vermeiden des Joins zur Laufzeit erzielen, sind im Vergleich zu allen anderen Ressourcen, die Sie noch verwenden, nicht messbar.

Achten Sie wie bei nicht gruppierten Indizes nur darauf, dass Sie nicht zu viel tun. Wenn Sie einer Tabelle 10 verschiedene indizierte Ansichten hinzufügen, werden Sie größere Auswirkungen auf den Schreibbereich Ihrer Workload haben, insbesondere wenn die Gruppierungsspalte (n) nicht (in) dem Clustering-Schlüssel sind.

Meine Güte, ich wollte über dieses Thema bloggen.

29
Aaron Bertrand

Aarons Antworten deckten diese Frage gut ab. Zwei Dinge hinzuzufügen:

  1. Aggregationsindizierte Ansichten können zu zeilenübergreifenden Konflikten und Deadlocks führen. Normalerweise blockieren zwei Einfügungen nicht (außer bei eher seltenen Bedingungen wie Sperreneskalation oder Sperren-Hash-Kollisionen). Wenn jedoch beide Einfügungen dieselbe Gruppe in der Ansicht ansprechen, werden sie miteinander konkurrieren. Der gleiche Punkt steht für alles andere, was Sperren erfordert (DML, Sperrenhinweise).
  2. Indizierte Ansichten, die nicht aggregiert werden, können ebenfalls nützlich sein. Mit ihnen können Sie Spalten aus mehreren Tabellen indizieren. Auf diese Weise können Sie effizient nach einer Tabelle filtern und nach einer Spalte aus einer verknüpften Tabelle sortieren. Dieses Muster kann die vollständige Tabellenverknüpfung in winzige zeitkonstante Abfragen konvertieren.

Ich habe sowohl Aggregations- als auch Join-Ansichten mit extremem Nutzen verwendet.

Alles in allem scheint Ihr Anwendungsfall ein perfekter Fall zu sein. Indizierte Ansichten sind eine Technik, die weit unterausgenutzt ist.

19
usr