Ich habe mit verschiedenen Entwicklern in meinem Büro eine ständige Debatte über die Kosten eines Index geführt und darüber, ob die Eindeutigkeit vorteilhaft oder kostspielig ist (wahrscheinlich beides). Der Kern des Problems sind unsere konkurrierenden Ressourcen.
Hintergrund
Ich habe zuvor in einer Diskussion gelesen, dass ein Unique
Index keine zusätzlichen Kosten verursacht, da eine Insert
Operation implizit prüft, wo er in den B-Baum passt, und einen Eindeutiger anhängt, wenn ein Duplikat in einem nicht eindeutigen Index gefunden wird das Ende des Schlüssels, fügt aber sonst direkt ein. In dieser Abfolge von Ereignissen entstehen für einen Unique
Index keine zusätzlichen Kosten.
Mein Kollege bekämpft diese Aussage, indem er sagt, dass dies Unique
als zweite Operation nach der Suche nach der neuen Position im B-Baum erzwungen wird und daher in der Pflege teurer ist als ein nicht eindeutiger Index.
Im schlimmsten Fall habe ich Tabellen mit einer Identitätsspalte (von Natur aus eindeutig) gesehen, die der Clustering-Schlüssel der Tabelle ist, aber ausdrücklich als nicht eindeutig angegeben wird. Auf der anderen Seite ist meine Besessenheit von der Eindeutigkeit am schlimmsten, und alle Indizes werden als eindeutig erstellt. Wenn es nicht möglich ist, eine explizit eindeutige Beziehung zu einem Index zu definieren, hänge ich die PK der Tabelle an das Ende des Index an, um sicherzustellen, dass der Index eindeutig ist Einzigartigkeit ist garantiert.
Ich bin häufig an Codeüberprüfungen für das Entwicklerteam beteiligt, und ich muss in der Lage sein, allgemeine Richtlinien zu geben, denen sie folgen können. Ja, jeder Index sollte ausgewertet werden. Wenn Sie jedoch fünf Server mit jeweils Tausenden von Tabellen und bis zu zwanzig Indizes in einer Tabelle haben, müssen Sie in der Lage sein, einige einfache Regeln anzuwenden, um ein bestimmtes Qualitätsniveau sicherzustellen.
Frage
Hat die Einzigartigkeit zusätzliche Kosten im Insert
Vergleich zu den Kosten für die Aufrechterhaltung eines nicht eindeutigen Index? Was ist zweitens falsch daran, den Primärschlüssel einer Tabelle an das Ende eines Indexes anzuhängen, um die Eindeutigkeit sicherzustellen?
Beispiel Tabellendefinition
create table #test_index
(
id int not null identity(1, 1),
dt datetime not null default(current_timestamp),
val varchar(100) not null,
is_deleted bit not null default(0),
primary key nonclustered(id desc),
unique clustered(dt desc, id desc)
);
create index
[nonunique_nonclustered_example]
on #test_index
(is_deleted)
include
(val);
create unique index
[unique_nonclustered_example]
on #test_index
(is_deleted, dt desc, id desc)
include
(val);
Beispiel
Ein Beispiel , warum ich das hinzufügen würde Unique
Schlüssel zum Ende eines Index ist in einem unsere Faktentabellen. Es gibt ein Primary Key
, auf dem eine Identity
Spalte. Das Clustered Index
ist jedoch stattdessen die Partitionierungsschema-Spalte, gefolgt von drei Fremdschlüsseldimensionen ohne Eindeutigkeit. Die Leistung bei der Auswahl dieser Tabelle ist miserabel, und ich erhalte häufig bessere Suchzeiten, wenn ich die Primary Key
mit einer Schlüsselsuche verwende, anstatt die zu nutzen Clustered Index
. Andere Tabellen, die ein ähnliches Design aufweisen, jedoch Primary Key
am Ende angehängt sind, weisen eine erheblich bessere Leistung auf.
-- date_int is equivalent to convert(int, convert(varchar, current_timestamp, 112))
if not exists(select * from sys.partition_functions where [name] = N'pf_date_int')
create partition function
pf_date_int (int)
as range right for values
(19000101, 20180101, 20180401, 20180701, 20181001, 20190101, 20190401, 20190701);
go
if not exists(select * from sys.partition_schemes where [name] = N'ps_date_int')
create partition scheme
ps_date_int
as partition
pf_date_int all
to
([PRIMARY]);
go
if not exists(select * from sys.objects where [object_id] = OBJECT_ID(N'dbo.bad_fact_table'))
create table dbo.bad_fact_table
(
id int not null, -- Identity implemented elsewhere, and CDC populates
date_int int not null,
dt date not null,
group_id int not null,
group_entity_id int not null, -- member of group
fk_id int not null,
-- tons of other columns
primary key nonclustered(id, date_int),
index [ci_bad_fact_table] clustered (date_int, group_id, group_entity_id, fk_id)
)
on ps_date_int(date_int);
go
if not exists(select * from sys.objects where [object_id] = OBJECT_ID(N'dbo.better_fact_table'))
create table dbo.better_fact_table
(
id int not null, -- Identity implemented elsewhere, and CDC populates
date_int int not null,
dt date not null,
group_id int not null,
group_entity_id int not null, -- member of group
-- tons of other columns
primary key nonclustered(id, date_int),
index [ci_better_fact_table] clustered(date_int, group_id, group_entity_id, id)
)
on ps_date_int(date_int);
go
Case
und Weise und dieIf
Strukturen auf 10 Ebenen begrenzt sind, ist es sinnvoll, dass auch die Auflösung nicht eindeutiger Entitäten begrenzt ist. Ihrer Aussage nach scheint dies nur in Fällen zuzutreffen, in denen der Clustering-Schlüssel nicht eindeutig ist. Ist dies ein Problem für einenNonclustered Index
oder liegt der Clustering-Schlüssel vor,Unique
gibt es kein Problem fürNonclustered
Indizes?Ich werde mich nicht mit der Frage auseinandersetzen, ob ein Index eindeutig sein sollte oder nicht und ob dieser oder jener Ansatz mehr Aufwand mit sich bringt. Aber ein paar Dinge haben mich an Ihrem allgemeinen Design gestört
WHERE is_deleted = 0
), und verwenden Sie einen gefilterten Index. Ich würde sogar in Betracht ziehen, 2 gefilterte Indizes zu verwenden, einen fürwhere is_deleted = 0
und einen fürwhere is_deleted = 1
Grundsätzlich sieht dies eher nach einer Codierungsübung aus, mit der eine Hypothese getestet werden soll, als nach einem echten Problem / einer echten Lösung, aber diese beiden Muster sind definitiv etwas, nach dem ich in Codeüberprüfungen Ausschau halte.
quelle
Nonclustered
Index wird der Clustering-Schlüssel an das Ende der Datenzeile angehängt, damit Schlüssel intern gesucht werden können. Als solches sind die beiden Indizes physisch gleich, was der Punkt meiner Frage war.Es sieht so aus, als würden Sie einfach PK verwenden, um einen alternativen, kleineren Index zu erstellen. Daher ist die Leistung schneller.
Sie sehen dies bei Unternehmen mit massiven Datentabellen (z. B. Stammdatentabellen). Jemand entscheidet sich für einen massiven Clustered-Index, der die Anforderungen verschiedener Berichtsgruppen erfüllen soll.
Eine Gruppe benötigt jedoch möglicherweise nur wenige Teile dieses Index, während eine andere Gruppe andere Teile benötigt. Daher hilft es nicht wirklich, wenn der Index in jede Spalte unter der Sonne geschlagen wird, um die Leistung zu optimieren.
In der Zwischenzeit wird das Problem häufig dadurch gelöst, dass mehrere kleinere Zielindizes erstellt werden.
Und das scheint das zu sein, was du tust. Sie haben diesen massiven Clustered-Index mit schrecklicher Leistung, dann verwenden Sie PK, um einen weiteren Index mit weniger Spalten zu erstellen, der (keine Überraschung) eine bessere Leistung aufweist.
Führen Sie einfach eine Analyse durch und finden Sie heraus, ob Sie den einzelnen Clustered-Index in kleinere, zielgerichtete Indizes aufteilen können, die für bestimmte Jobs erforderlich sind.
Sie müssten dann die Leistung von einem Standpunkt aus analysieren, bei dem es um einen "Einzelindex vs. Mehrfachindex" geht, da das Erstellen und Aktualisieren von Indizes einen Mehraufwand bedeutet. Sie müssen dies jedoch aus einer Gesamtperspektive analysieren.
EG: Es ist möglicherweise weniger ressourcenintensiv für einen massiven Clustered-Index, und es ist ressourcenintensiver, wenn mehrere kleinere Zielindizes vorhanden sind. Wenn Sie jedoch gezielte Abfragen im Back-End schneller ausführen können und dabei Zeit (und Geld) sparen, lohnt es sich möglicherweise.
Sie müssten also eine End-to-End-Analyse durchführen. Sehen Sie sich nicht nur an, wie sich dies auf Ihre eigene Welt auswirkt, sondern auch, wie sich dies auf Endbenutzer auswirkt.
Ich habe nur das Gefühl, dass Sie die PK-Kennung falsch verwenden. Möglicherweise verwenden Sie jedoch ein Datenbanksystem, das nur einen Index (?) Zulässt. Sie können jedoch einen anderen einschleichen, wenn Sie PK verwenden (in diesen Tagen scheint jedes relationale Datenbanksystem die PK automatisch zu indizieren). Die meisten modernen RDBMS sollten jedoch die Erstellung mehrerer Indizes ermöglichen. Die Anzahl der Indizes, die Sie erstellen können, sollte unbegrenzt sein (im Gegensatz zu einem Limit von 1 PK).
Wenn Sie also eine PK erstellen, die sich wie ein Alt-Index verhält, verbrauchen Sie Ihre PK. Dies kann erforderlich sein, wenn die Tabelle später in ihrer Rolle erweitert wird.
Das heißt nicht, dass Ihre Tabelle keine PK benötigt. SOP DBs 101 sagen, dass "jede Tabelle eine PK haben sollte". Aber in einer Data-Warehousing-Situation oder einer ähnlichen Situation kann es sein, dass eine PK auf einem Tisch zusätzlichen Aufwand verursacht, den Sie nicht benötigen. Oder es könnte von Gott gesandt werden, um sicherzustellen, dass Sie keine doppelten Dupe-Einträge hinzufügen. Es ist wirklich eine Frage dessen, was Sie tun und warum Sie es tun.
Massive Tabellen profitieren jedoch definitiv von Indizes. Angenommen, ein einzelner massiver Clustered-Index ist der beste, ist aber möglicherweise der beste. Ich würde jedoch empfehlen, einen Test durchzuführen, bei dem der Index in mehrere kleinere Indizes aufgeteilt wird, die auf bestimmte Anwendungsszenarien abzielen.
quelle