In einer früheren Frage von mir, ist es eine gute Idee zu deaktivieren Sperreneskalation während neue berechnete Spalten zu einer Tabelle hinzufügen? , Ich erstelle eine berechnete Spalte:
ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
ISNULL(
CASE WHEN sintMarketID = 2
AND strType = 'CARD'
AND strTier1 LIKE 'GG%'
THEN 1
ELSE 0
END
, 0)
AS BIT
) PERSISTED;
Die berechnete Spalte lautet PERSISTED
laut computed_column_definition (Transact-SQL) :
BESTÄNDIG
Gibt an, dass das Datenbankmodul die berechneten Werte physisch in der Tabelle speichert und die Werte aktualisiert, wenn andere Spalten aktualisiert werden, von denen die berechnete Spalte abhängt. Durch Markieren einer berechneten Spalte als PERSISTED kann ein Index für eine berechnete Spalte erstellt werden, die deterministisch, aber nicht genau ist. Weitere Informationen finden Sie unter Indizes für berechnete Spalten. Berechnete Spalten, die als Partitionierungsspalten einer partitionierten Tabelle verwendet werden, müssen explizit als PERSISTED gekennzeichnet werden. computed_column_expression muss bei Angabe von PERSISTED deterministisch sein.
Wenn ich jedoch versuche, einen Index für meine Spalte zu erstellen, wird die folgende Fehlermeldung angezeigt:
CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo)
INCLUDE (strTier3)
WHERE isUsGift = 1;
Der gefilterte Index 'FIX_tblBGiftVoucherItem_incl' kann für die Tabelle 'dbo.tblBGiftVoucherItem' nicht erstellt werden, da die Spalte 'isUsGift' im Filterausdruck eine berechnete Spalte ist. Schreiben Sie den Filterausdruck so um, dass er diese Spalte nicht enthält.
Wie kann ich einen gefilterten Index für eine berechnete Spalte erstellen?
oder
Gibt es eine alternative Lösung?
quelle
WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')
.Antworten:
Leider ist es ab SQL Server 2014 nicht möglich, einen
Filtered Index
Filter zu erstellen, bei dem sich der Filter in einer berechneten Spalte befindet (unabhängig davon, ob er beibehalten wird oder nicht).Seit 2009 ist ein Connect Item geöffnet. Bitte stimmen Sie ab. Vielleicht wird Microsoft dies eines Tages beheben.
Aaron Bertrand hat einen Artikel, der eine Reihe anderer Probleme mit gefilterten Indizes behandelt .
quelle
Obwohl Sie keinen gefilterten Index für eine persistierte Spalte erstellen können, gibt es eine relativ einfache Problemumgehung, die Sie möglicherweise verwenden können.
Als Test habe ich eine einfache Tabelle mit einer
IDENTITY
Spalte und einer fortgesetzten berechneten Spalte basierend auf der Identitätsspalte erstellt:Dann habe ich eine schemagebundene Ansicht basierend auf der Tabelle mit einem Filter für die berechnete Spalte erstellt:
Als Nächstes habe ich einen Clustered-Index für die schemagebundene Ansicht erstellt, wodurch die in der Ansicht gespeicherten Werte beibehalten werden, einschließlich des Werts der berechneten Spalte:
Fügen Sie einige Testdaten in die Tabelle ein:
Erstellen Sie ein Statistikelement und einen Index für die Ansicht:
Das Ausführen von
SELECT
Anweisungen für die Tabelle mit der persistierten Spalte kann jetzt automatisch die persistierte Ansicht verwenden, wenn das Abfrageoptimierungsprogramm dies für sinnvoll erachtet:Der tatsächliche Ausführungsplan für die obige Abfrage zeigt, dass das Abfrageoptimierungsprogramm ausgewählt hat, die permanente Ansicht zu verwenden, um die Ergebnisse zurückzugeben:
Möglicherweise haben Sie die explizite Konvertierung in der
WHERE
obigen Klausel bemerkt . Diese explizite MethodeCONVERT(INT, 26)
ermöglicht es dem Abfrageoptimierer, das Statistikobjekt ordnungsgemäß zu verwenden, um die Anzahl der Zeilen zu schätzen, die von der Abfrage zurückgegeben werden. Wenn wir die Abfrage mit schreibenWHERE pv.TestComputedColumn = 26
, schätzt das Abfrageoptimierungsprogramm die Anzahl der Zeilen möglicherweise nicht richtig, da 26 tatsächlich als a betrachtet wirdTINY INT
. Dies kann dazu führen, dass SQL Server die permanente Ansicht nicht verwendet. Implizite Konvertierungen können sehr schmerzhaft sein, und es lohnt sich, für Vergleiche und Verknüpfungen stets die richtigen Datentypen zu verwenden.Natürlich gelten alle Standard-Fallstricke, die sich aus der Verwendung der Schemabindung ergeben, für das obige Szenario. Dies kann die Verwendung dieser Problemumgehung in allen Szenarien verhindern. Beispielsweise ist es nicht mehr möglich, die Basistabelle zu ändern, ohne zuvor die Schemabindung aus der Ansicht zu entfernen. Dazu müssen Sie den Clustered-Index aus der Ansicht entfernen.
Wenn Sie nicht über SQL Server Enterprise Edition verfügen, verwendet das Abfrageoptimierungsprogramm die persistierte Ansicht nicht automatisch für Abfragen, bei denen der
WITH (NOEXPAND)
Hinweis nicht direkt auf die Ansicht verweist . Um den Vorteil der Verwendung der beständigen Ansicht in Nicht-Enterprise Edition-Versionen zu erkennen, müssen Sie die obige Abfrage in etwa wie folgt umschreiben:Vielen Dank an Ian Ringrose für den Hinweis auf die oben genannte Einschränkung der Enterprise Edition und an Paul White für den
(NOEXPAND)
Hinweis.Diese Antwort von Paul enthält einige interessante Details zum Abfrageoptimierer in Bezug auf dauerhafte Ansichten.
quelle
TestComputedColumn
. Da der Clustered-Index jedoch alle Daten für die Tabelle / Ansicht enthält, habe ich entschieden, dass es wahrscheinlich besser ist, eine monoton ansteigende Zahl als Clustering-Schlüssel zu verwenden. Beachten Sie, dass ich diese Vermutung nicht wirklich getestet habe und sie für einige Variationen des Repros möglicherweise falsch ist.Von
Create Index
und seinerwhere
Klausel ist dies nicht möglich:Quelle: MSDN
quelle
Bevor wir Spalten berechnet hatten, haben wir Trigger verwendet , um den Spaltenwert zu berechnen, wenn die Zeile geändert oder eingefügt wurde.
(Ein Trigger kann auch verwendet werden, um die PK des Elements aus einer zweiten Tabelle einzufügen / zu entfernen, die dann in Abfragen verwendet wurde.)
quelle
Dies ist ein Versuch, die Arbeit von Max Vernon zu verbessern . In seiner Lösung schlägt er vor, 2 Indizes für die Ansicht und ein Statistikobjekt zu verwenden.
Der 1. Index wird geclustert, was tatsächlich erforderlich ist, da im Gegensatz zu einem nicht geclusterten Index für eine Tabelle ein Fehler generiert wird, wenn versucht wird, einen nicht geclusterten Index für die Ansicht zu erstellen, ohne zuvor einen geclusterten Index zu haben.
Der 2. Index ist ein nicht gruppierter Index, der als Index hinter der Abfrage verwendet wird. Im Kommentarbereich seiner Antwort fragte ich, was passieren würde, wenn anstelle eines nicht gruppierten Index ein gruppierter Index verwendet würde.
Die folgende Analyse versucht, diese Frage zu beantworten.
Ich verwende genau denselben Code, außer dass ich keinen nicht gruppierten Index für die Ansicht erstelle.
Ich erstelle auch kein Statistikobjekt. Wenn Sie den folgenden Code mit SQL Server Management Studio (SSMS) eingeben, sollten Sie sich bewusst sein, dass möglicherweise rote, verzerrte Linien angezeigt werden, die wie Fehler aussehen. Dies sind (wahrscheinlich) keine Fehler, sondern ein Problem mit der Intellisense.
Sie können entweder Intellisense deaktivieren oder die Fehler ignorieren und die Befehle ausführen. Sie sollten fehlerfrei vervollständigt werden.
Der folgende Ausführungsplan (ohne Sicht / Indexsicht) wird erstellt, nachdem die folgende Abfrage für die Tabelle ausgeführt wurde:
Dies gibt eine Vergleichsbasis. Beachten Sie, dass nach Abschluss der Abfrage ein Statistikobjekt erstellt wurde (_WA_Sys_00000003_1FCDBCEB). Das Statistikobjekt PK_PersistedViewTest wurde beim Erstellen des Clustered Table Index erstellt.
Als Nächstes werden die gefilterte Ansicht und der Clustered-Index für diese Ansicht erstellt:
Versuchen wir nun erneut, die Abfrage auszuführen, diesmal jedoch gegen die Ansicht:
Der neue Ausführungsplan lautet nun:
Wenn der neue Plan nach dem Hinzufügen der Ansicht und des Clustered-Index für diese Ansicht angenommen werden soll, scheinen die Statistiken darauf hinzudeuten, dass sich die für die Ausführung der Abfrage erforderliche Zeit verdoppelt hat. Beachten Sie außerdem, dass nach der Ausführung der Abfrage kein neues Statistikobjekt zur Unterstützung des neuen Index erstellt wurde, das sich von der Abfrage in der Tabelle unterscheidet.
Der Abfrageplan schlägt weiterhin vor, dass die Erstellung eines nicht gruppierten Indexes zur Verbesserung der Leistung der Abfrage sehr hilfreich ist. Bedeutet dies, dass ein nicht gruppierter Index zur Ansicht hinzugefügt werden muss, bevor die gewünschte Leistungsverbesserung erzielt werden kann? Es gibt noch eine letzte Sache zu versuchen. Ändern Sie die Abfrage, um die Option "WITH NOEXPAND" zu verwenden:
Daraus ergibt sich der folgende Abfrageplan:
Dieser Ausführungsplan ähnelt dem, der mit dem in Max Vernons Antwort angegebenen nicht gruppierten Index erstellt wurde. Dies geschieht jedoch mit einem (nicht gruppierten) Index und einem Statistikobjekt weniger.
Es stellt sich heraus, dass die NOEXPAND-Option mit der Express- und der Standardversion von SQL Server verwendet werden muss, um eine indizierte Ansicht ordnungsgemäß zu verwenden. Paul White hat einen ausgezeichneten Artikel , in dem die Vorteile der NOEXPAND-Option erläutert werden. Er empfiehlt außerdem , diese Option in Verbindung mit der Enterprise Edition zu verwenden, um sicherzustellen, dass die von den Ansichtsindizes bereitgestellte Eindeutigkeitsgarantie vom Optimierer verwendet wird.
Die obige Analyse wurde mit der Express Edition von SQL Server 2014 durchgeführt. Ich habe sie auch mit der Developer Edition von SQL Server 2016 ausprobiert. Die NOEXPAND-Option scheint in der Development Edition nicht erforderlich zu sein, um die Leistungssteigerungen zu erzielen, wird jedoch weiterhin empfohlen .
Vor weniger als 5 Monaten hat Microsoft die Entwicklereditionen kostenlos zur Verfügung gestellt . Die Lizenz beschränkt die Verwendung nur auf die Entwicklung, was bedeutet, dass die Datenbank nicht in einer Produktionsumgebung verwendet werden kann. Wenn Sie also speicheroptimierte Tabellen, Verschlüsselung, R usw. testen möchten, gibt es keine lizenzfreie Ausrede mehr. Ich habe es vor ein paar Tagen zusammen mit SQL Server 2014 Express ohne Probleme erfolgreich auf meinem Computer installiert.
quelle