Sollte ich einen zusammengesetzten Index als eindeutig markieren, wenn er den Primärschlüssel enthält?

9

Bei einer Tabelle mit einem Primärschlüssel, z.

CREATE TABLE Customers (
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   Address nvarchar(200),
   Email nvarchar(260)
   --...
)

Wir haben einen eindeutigen Primärschlüssel an CustomerID.

Traditionell benötige ich dann möglicherweise einige zusätzliche Deckungsindizes. Zum Beispiel, um schnell einen Benutzer zu finden, indem Sie entweder CustomerIDoder Email:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)

Und das sind die Arten von Indizes, die ich seit Jahrzehnten erstellt habe.

Es muss nicht eindeutig sein, ist es aber tatsächlich

Der Index selbst ist vorhanden, um einen Tabellenscan zu vermeiden. Es handelt sich um einen Deckungsindex, um die Leistung zu verbessern (der Index dient nicht als Einschränkung für die Durchsetzung der Eindeutigkeit).

Heute habe ich mich an ein paar Informationen erinnert - SQL Server kann die Tatsache nutzen, dass:

  • Eine Spalte hat eine Fremdschlüsseleinschränkung
  • Eine Spalte hat einen eindeutigen Index
  • Eine Einschränkung ist vertrauenswürdig

um die Abfrageausführung zu optimieren. In der Tat aus dem SQL Server Index Design Guide :

Wenn die Daten eindeutig sind und die Eindeutigkeit erzwungen werden soll, bietet das Erstellen eines eindeutigen Index anstelle eines nicht eindeutigen Index für dieselbe Spaltenkombination zusätzliche Informationen für das Abfrageoptimierungsprogramm, mit denen effizientere Ausführungspläne erstellt werden können . In diesem Fall wird empfohlen, einen eindeutigen Index zu erstellen (vorzugsweise durch Erstellen einer EINZIGARTIGEN Einschränkung).

Da mein mehrspaltiger Index den Primärschlüssel enthält , ist dieser zusammengesetzte Index de facto eindeutig. Es ist keine Einschränkung, die SQL Server bei jeder Einfügung oder Aktualisierung besonders erzwingen muss. aber die Tatsache ist , dass dieser Nicht-Clustered - Index ist einzigartig.

Gibt es einen Vorteil, diesen de facto eindeutigen Index als tatsächlich eindeutig zu kennzeichnen?

CREATE UNIQUE INDEX IX_Customers_CustomerIDEmail ON Kunden
(
   Kundennummer,
   Email
)

Es scheint mir, dass SQL Server intelligent genug sein könnte , um zu erkennen, dass mein Index bereits eindeutig ist , da er den Primärschlüssel enthält.

  • Aber vielleicht weiß es das nicht und es gibt einen Vorteil für den Optimierer, wenn ich den Index trotzdem als eindeutig deklariere.
  • Außer vielleicht könnte dies jetzt zu Verlangsamungen bei Einfügungen und Aktualisierungen führen, bei denen Eindeutigkeitsprüfungen durchgeführt werden müssen - wo zuvor noch nie zuvor.
  • Es sei denn, es weiß, dass der Index garantiert bereits eindeutig ist, da er den Primärschlüssel enthält.

Ich kann keine Anleitung von Microsoft finden, was zu tun ist, wenn ein zusammengesetzter Index den Primärschlüssel enthält.

Zu den Vorteilen eindeutiger Indizes gehören:

  • Die Datenintegrität der definierten Spalten ist gewährleistet.
  • Zusätzliche Informationen, die für das Abfrageoptimierungsprogramm hilfreich sind, werden bereitgestellt.

Sollte ich einen zusammengesetzten Index als eindeutig markieren, wenn er bereits den Primärschlüssel enthält? Oder kann SQL Server dies selbst herausfinden?

Ian Boyd
quelle
4
Um mit CustomerID schnell einen Kunden zu finden, reicht die PK wahrscheinlich aus. Um einen Kunden per E-Mail zu finden, hätte ich lieber den zweiten Index nur per E-Mail (er deckt bereits den Clustering-Schlüssel ab). Wie auch immer, ich weiß, dass dies fiktiv ist, aber ja, ich würde es als eindeutig markieren, wenn Sie wissen, dass es eindeutig sein muss. Diese Einschränkung kann Einfügungen wahrscheinlich nicht genug verletzen, um die Fälle auszugleichen, in denen sie dem Optimierer helfen könnten. Aber das hängt alles von Ihrer Arbeitsbelastung ab, über die wir spekulieren müssten ...
Aaron Bertrand
1
Wir haben hier ausführlich darüber gesprochen. Und obwohl wir uns keine Möglichkeit vorstellen können, Daten zu finden, um dies auf die eine oder andere Weise zu beweisen, gehen wir davon aus, dass die SQL Server-Leute wahrscheinlich sehr schlau sind und der Optimierer diese Metaoptimierung wahrscheinlich bereits durchführen kann. Wir glauben auch, dass es wahrscheinlich am besten ist, wenn der Index die Absicht kommuniziert - was einfach ein Index ist und keine Eindeutigkeit als Geschäftsregel auferlegt, wenn es sonst nur getan würde, um zu versuchen, die Fähigkeiten von SQL Server zu überdenken.
Ian Boyd

Antworten:

11

Sollte ich einen zusammengesetzten Index als eindeutig markieren, wenn er bereits den Primärschlüssel enthält?

Wahrscheinlich nicht. Das Optimierungsprogramm kann im Allgemeinen ohnehin Informationen über die Eindeutigkeit der enthaltenen Schlüsselspalte verwenden, sodass es keinen wirklichen Vorteil gibt.

Es gibt auch eine wichtige Konsequenz , wenn ein Index in Aktualisierungsplänen, die die Schlüssel dieses Index ändern, eindeutig ist, um Folgendes zu berücksichtigen:

Installieren

CREATE TABLE dbo.Customers 
(
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   [Address] nvarchar(200),
   Email nvarchar(260)
);

CREATE NONCLUSTERED INDEX 
    IX_Customers_CustomerIDEmail 
ON dbo.Customers
(
   CustomerID,
   Email
);

-- Pretend we have some rows
UPDATE STATISTICS dbo.Customers 
WITH ROWCOUNT = 100000, PAGECOUNT = 20000;

Aktualisierungsplan pro Index (nicht eindeutiger Index)

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Ausführungsplan:

Teilen & Filtern

Der Optimierer trifft häufig eine kostenbasierte Entscheidung zwischen der Aktualisierung nicht gruppierter Indizes pro Zeile (ein "enger" Plan) oder pro Index (ein "breiter" Plan). Die Standardstrategie (mit Ausnahme von speicherinternen OLTP-Tabellen) ist ein umfassender Plan.

Enge Pläne (bei denen nicht gruppierte Indizes gleichzeitig mit dem Heap- / Clustered-Index verwaltet werden) sind eine Leistungsoptimierung für kleine Aktualisierungen. Diese Optimierung ist nicht in allen Fällen implementiert. Die Verwendung bestimmter Funktionen (z. B. indizierter Ansichten) bedeutet, dass die zugehörigen Indizes in einem umfassenden Plan verwaltet werden.

Weitere Informationen: Optimieren von T-SQL-Abfragen, die Daten ändern

In diesem Fall habe ich das undokumentierte Ablaufverfolgungsflag 8790 verwendet, um einen umfassenden Aktualisierungsplan zu erzwingen: Der Plan zeigt daher, dass die gruppierten und nicht gruppierten Indizes getrennt verwaltet werden.

Der Split verwandelt jedes Update in ein separates Lösch- und Einfügepaar. Der Filter filtert alle Zeilen heraus, die nicht zu einer Änderung des Index führen würden.

Weitere Informationen: ( Nicht aktualisierte Updates ) vom SQL Server QO-Team.

Aktualisierungsplan pro Index (eindeutiger Index)

-- Same index, but unique
CREATE UNIQUE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)
WITH (DROP_EXISTING = ON);

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Ausführungsplan:

Split-Sort-Collapse

Beachten Sie die zusätzlichen Sortier- und Reduzierungsoperatoren, wenn der Index als eindeutig markiert ist.

Dieses Split-Sort-Collapse-Muster ist erforderlich, wenn die Schlüssel eines eindeutigen Index aktualisiert werden, um Verstöße gegen eindeutige Schlüssel zwischenzeitlich zu verhindern.

Weitere Informationen: Pflege eindeutiger Indizes von Craig Freedman

Insbesondere die Sortierung kann ein Problem sein. Dies ist nicht nur ein unnötiger Mehraufwand, sondern kann auch auf die Festplatte übertragen werden, wenn die Schätzungen ungenau sind.

Über nicht gruppierte Schlüssel

Ein weiterer zu berücksichtigender Faktor ist, dass nicht gruppierte Indexstrukturen auf jeder Indexebene immer eindeutig sind, auch wenn sie UNIQUEnicht angegeben sind. Die Cluster-Schlüssel - und möglicherweise ein Eindeutiger, wenn der Cluster-Index nicht als eindeutig markiert ist - werden auf allen Ebenen einem nicht eindeutigen, nicht gruppierten Index hinzugefügt.

Infolgedessen die folgende Indexdefinition:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   Email
)
WITH (DROP_EXISTING = ON);

... enthält tatsächlich die Schlüssel (E-Mail, Kunden-ID) auf allen Ebenen. Es ist daher in beiden Spalten "suchbar":

SELECT * 
FROM dbo.Customers AS C WITH (INDEX(IX_Customers_CustomerIDEmail))
WHERE C.Email = N'Email'
AND C.CustomerID = 1;

Sucht

Weitere Informationen: Weitere Informationen zu nicht gruppierten Indexschlüsseln von Kalen Delaney

Paul White 9
quelle
8

SQL weiß, dass es bereits eindeutig ist (wenn es die PK enthält, kann es nicht eindeutiger werden), unabhängig davon, ob Sie es explizit angeben.

Der große Unterschied zwischen einem nicht eindeutigen Index und einem eindeutigen Index besteht darin, dass für nicht eindeutige Indizes der Clustered-Indexschlüssel (mit dem eindeutigen Wert, wenn der CIX nicht als eindeutig deklariert ist) auf den höheren Ebenen des Index erforderlich ist, nicht nur am Blatt Niveau.

In Ihrem Fall haben Sie den CIX bereits im Schlüssel, was bedeutet, dass er sich bereits auf jeder Ebene des Index befindet.

Sie können jedoch eine Tabelle erstellen, die eine separate PK (eindeutig) und CIX (egal) enthält. Erstellen Sie dann einen nicht eindeutigen Index, der die PK in ihrem Schlüssel enthält. Fügen Sie einige Zeilen in die Tabelle ein, einschließlich einiger leicht auffindbarer Varchar-Werte für Ihre CIX-Spalte. Fügen Sie genügend Zeilen ein, um mehrere Ebenen Ihrer Indizes zu erstellen. Dann können Sie DBCC IND verwenden, um die Seiten in Ihrem NCIX zu finden, und DBCC PAGE, um einige zu öffnen, um die Daten zu überprüfen und festzustellen, ob die CIX-Schlüsselwerte auf den höheren Ebenen liegen.

Rob Farley
quelle