VARCHAR-Primärschlüssel - MySQL

8

Derzeit habe ich eine categoriesTabelle mit 2 Spalten - category VARCHAR(50) NOT NULL PRIMARY KEYund parent VARCHAR(50). Die parentSpalte ist ein Fremdschlüssel (FK) für die categorySpalte.

Dies scheint der naheliegendste Ansatz zu sein. In meinem Kopf läuten jedoch Alarmglocken, weil ich eine VARCHARSpalte für einen Primärschlüssel verwende, was den Vorgang beim Abfragen der Tabelle verlangsamen kann.

Ich könnte eine dritte Spalte namens cat_id INT AUTO_INCREMENTPK einführen und diese als PK festlegen, aber es würde eine neue Spalte einführen, die keine Bedeutung hat.

Welche anderen Überlegungen sollten außer dem, was schneller wäre, berücksichtigt werden?

NB Ich gehe davon aus, dass es höchstens 1000 Kategorien geben wird, daher ist die Anzahl der Zeilen nicht sehr hoch. Die categoriesPK-Spalte ist jedoch eine Referenzspalte für viele Fremdschlüssel in anderen Tabellen.

Sollte ich auch (eindeutige) Benutzernamen als PKs verwenden?

Dayuloli
quelle

Antworten:

8

VARCHAR Spalte als Primärschlüssel ist keine gute Wahl, da wir normalerweise einen Clusterindex für dieselbe Spalte erstellen.

Der Clusterindex für VARCHAR-Spalten ist aufgrund der erwarteten hohen Fragmentierungsrate eine schlechte Wahl. Jeder neu eingefügte Schlüsselwert versucht, seinen Platz irgendwo zwischen vorhandenen Schlüsseln zu finden und verursacht normalerweise einen Seitenteilung und eine Fragmentierung mit hohem Index. Infolgedessen schlechte Leistung und zusätzliche Index-Wiederherstellungs- / Reorganisationskosten.

Zweitens benötigt die Verwendung der varcharSchlüsselspalte als Fremdschlüssel im Vergleich zur Pseudoschlüsselspalte zusätzlichen Platz auto-incremented.

ABER

Ein Clustered-Index für eine automatisch inkrementierte Spalte kann einen "Hot Spot" erzeugen. Lesen Sie dies sorgfältig durch. Ist "Vermeiden Sie das Erstellen eines Clustered-Index basierend auf einem inkrementierenden Schlüssel" ein Mythos aus SQL Server 2000 Tagen?

Obwohl Hotspot ein Problem sein könnte, wenn zu viele Benutzer versuchen, Werte einzufügen, aber dennoch in Ihrem Fall möchte ich eine automatisch inkrementierte Spalte im Vergleich zu varchar wählen.

aasim.abdullah
quelle
7

Ja, ich würde einen Ersatz-4-Byte-Ganzzahlschlüssel hinzufügen. Ihre aktuellen zwei Spalten sind 100 Byte, dies könnte dann durch Hinzufügen der neuen Identitätsspalte auf 58 Byte reduziert werden. Sie können den Ersatzschlüssel sogar zu einem 2-Byte-Smallint machen, wenn Sie sicher sind, dass Sie 65.535 Kategorien nie überschreiten werden (möglicherweise ist es immer noch eine gute Idee, für alle Fälle als INT zu bleiben).

Die Platzersparnis ist für eine Tabelle mit 1.000 Zeilen nicht groß, aber hier, wo cat_id zu anderen Tabellen hinzugefügt wird, können Sie erheblichen Platz sparen (4 Bytes anstelle von 50 in jedem FK). Möglicherweise möchten Sie diese Fremdschlüssel auch indizieren, sodass die Speicherplatzersparnis auch in all Ihren nicht gruppierten Indizes noch größer ist.

Außerdem ist Ihr Clustered-Index jetzt sequentiell, um eine Fragmentierung (Seitenteilung) beim Hinzufügen neuer Kategorien zu vermeiden

Tabellenstruktur: -

create table dbo.Cateogory (
    CateogoryID int not null identity(1,1) constraint pkCateogory primary key clustered,
    Cateogory varchar(50) not null constraint ukCateogory unique nonclustered,
    ParentCateogoryID int null constraint fkCateogory references dbo.Cateogory(CateogoryID)
    )

Abhängig von Ihren Anforderungen können Sie auch Indexoptionen in der Produktion hinzufügen (Füllfaktor usw.).

Andy Jones
quelle