Eine zu berücksichtigende Sache ist, dass ein Primärschlüssel und ein Clustered-Index nicht dasselbe sind. Ein Primärschlüssel ist eine Einschränkung und behandelt die Regeln, nach denen die Daten leben (dh Datenintegrität). es hat nichts mit Effizienz / Leistung zu tun. Für einen Primärschlüssel müssen die Schlüsselspalten eindeutig (in Kombination) und NICHT NULL (einzeln) sein. Eine PK wird über einen eindeutigen Index erzwungen, kann jedoch entweder gruppiert oder nicht gruppiert sein.
Ein Clustered Index ist ein Mittel zum physischen (dh auf der Festplatte) Ordnen der Daten in der Tabelle und befasst sich mit der Leistung. Es hat nichts mit Datenintegrität zu tun. Ein Clustered Index kann müssen die Schlüsselspalten eindeutig sein (in Kombination), dies ist jedoch nicht erforderlich. Da der Clustered Index jedoch die physische Reihenfolge der Daten ist, muss jede Zeile unabhängig davon eindeutig identifiziert werden. Wenn Sie also nicht festlegen, dass Eindeutigkeit erforderlich ist, wird über eine versteckte 4-Byte-Spalte "Eindeutigkeit" eine eigene Eindeutigkeit erstellt. Diese Spalte befindet sich immer in nicht eindeutigen Clustered-Indizes, nimmt jedoch keinen Platz ein, wenn die Schlüsselfelder eindeutig sind (in Kombination). Um aus erster Hand zu sehen, wie diese "Eindeutigkeit" -Spalte funktioniert (sowohl im Clustered-Index als auch die Auswirkung auf nicht-Clustered-Indizes), T-SQL-Skript veröffentlicht habe, um die Uniquifier-Größe zu testen .
Daher die Hauptfrage von:
Wäre es effizienter, ein Auto-Inkrement- id
Feld hinzuzufügen und dieses in Verbindung mit company_id
als Primärschlüssel zu verwenden, oder würde es unnötigen Overhead hinzufügen
verschmilzt diese beiden Konzepte, so dass sie getrennt behandelt werden müssen, obwohl es definitiv einige Überschneidungen gibt.
Sollte eine IDENTITY
Spalte hinzugefügt werden oder wäre dies unnötig?
Wenn Sie eine INT IDENTITY
Spalte hinzufügen und damit eine PK erstellen, wird davon ausgegangen, dass es sich um eine Cluster-PK handelt, die jeder Zeile 4 Byte hinzufügt. Diese Spalte ist sichtbar und kann in Abfragen verwendet werden. Es könnte als Fremdschlüssel zu anderen Tabellen hinzugefügt werden, obwohl dies in diesem speziellen Fall nicht der Fall ist.
Wenn Sie die INT IDENTITY
Spalte nicht hinzufügen , können Sie für diese Tabelle keine PK erstellen. Sie können jedoch weiterhin einen Clustered-Index für die Tabelle erstellen, solange Sie die UNIQUE
Option nicht verwenden . In diesem Fall fügt SQL Server eine ausgeblendete Spalte mit dem Namen "Uniquifier" hinzu, die sich wie oben beschrieben verhält. Da die Spalte ausgeblendet ist, kann sie nicht in Abfragen oder als Referenz für Fremdschlüssel verwendet werden.
In Bezug auf die Effizienz sind diese Optionen ungefähr gleich. Ja, der nicht eindeutige Clustered-Index belegt etwas weniger Speicherplatz, da einige Zeilen (mit den anfänglichen eindeutigen Schlüsselwerten) 0 Byte belegen, während alle Zeilen in der IDENTITY
/ PK die 4 Byte belegen. Es wird jedoch nicht genug von den 0-Byte-Zeilen geben (insbesondere bei der geringen erwarteten Anzahl von Zeilen), um jemals einen Unterschied zu bemerken, geschweige denn die Bequemlichkeit abzuwägen, die ID
Spalte in Abfragen verwenden zu können.
INT IDENTITY-Spalte oder Hash einer persistierten berechneten org_path
Spalte?
Da Sie keine Zeilen basierend auf org_path
Werten suchen , ist es nicht sinnvoll, den Overhead der persistierten berechneten Spalte hinzuzufügen und diesen Hash in Abfragen zu berechnen, um mit der berechneten Spalte übereinzustimmen (dies war meine ursprünglicher Vorschlag, der im Revisionsverlauf hier verfügbar ist und auf dem ursprünglichen Wortlaut / den Einzelheiten der Frage basiert). In diesem speziellen Fall ist die INT IDENTITY
Spalte "ID" wahrscheinlich am besten.
Reihenfolge der Schlüsselsäulen
Da die ID
Spalte selten, wenn überhaupt, in Abfragen verwendet wird und die beiden Hauptanwendungsfälle darin bestehen, entweder "alle Zeilen" oder "alle Zeilen für eine bestimmte company_id
" zu erhalten, würde ich die PK auf erstellen company_id, id
. Und da dies bedeutet, dass Zeilen nicht nacheinander eingefügt werden, würde ich eine FILLFACTOR
von 90 angeben . Sie müssen auch sicherstellen, dass eine regelmäßige Indexpflege durchgeführt wird, um die Fragmentierung zu verringern.
Zweite Frage
Hat die Tatsache, dass company_id der Primärschlüssel in einer anderen Tabelle ist, hier einen Einfluss?
Nein.
Auslösen
Da org_path
Werte innerhalb von a company_id
eindeutig sind, sollten Sie dennoch einen Trigger erstellen INSERT, UPDATE
, um dies zu erzwingen. Führen Sie im Trigger eine IF EXISTS
mit einer Abfrage aus, die wahrscheinlich ein COUNT(*)
und ausführt GROUP BY company_id, org_path
. Wenn etwas gefunden wird, geben Sie ein aus ROLLBACK
, um den DML-Vorgang abzubrechen, und dann ein RAISERROR
Sprichwort, dass Duplikate vorhanden sind.
Kollation
In meiner ersten Antwort (basierend auf dem ursprünglichen Wortlaut / den spärlichen Details der Frage und verfügbar im Revisionsverlauf hier ) hatte ich vorgeschlagen, möglicherweise eine binäre (dh _BIN2
) Kollatierung zu verwenden. Nachdem wir nun wissen, was genau org_path
ist, würde ich die Verwendung einer binären Sortierung nicht empfehlen. Da es diakritische Zeichen sein, Sie tun wollen Verwendung von sprachlichen Äquivalenzen machen.