Gibt es einen REALEN Leistungsunterschied zwischen INT- und VARCHAR-Primärschlüsseln?

174

Gibt es einen messbaren Leistungsunterschied zwischen der Verwendung von INT und VARCHAR als Primärschlüssel in MySQL? Ich möchte VARCHAR als Primärschlüssel für Referenzlisten verwenden (denken Sie an US-Bundesstaaten, Ländercodes), und ein Mitarbeiter wird sich nicht an INT AUTO_INCREMENT als Primärschlüssel für alle Tabellen rühren.

Wie hier ausgeführt , ist mein Argument, dass der Leistungsunterschied zwischen INT und VARCHAR vernachlässigbar ist, da für jede INT-Fremdschlüsselreferenz ein JOIN erforderlich ist, um die Referenz zu verstehen, und ein VARCHAR-Schlüssel die Informationen direkt darstellt.

Hat jemand Erfahrung mit diesem speziellen Anwendungsfall und den damit verbundenen Leistungsproblemen?

Jake McGraw
quelle
3
Ich habe einen Beitrag mit der Antwort "Nein" mit einigen Details der von mir durchgeführten Tests verfasst ... aber das war SQL Server, nicht MySQL. Also habe ich meine Antwort gelöscht.
Timothy Khouri
17
@ Timothy - du hättest es nicht löschen sollen. Ich war gerade dabei, darüber abzustimmen. Die meisten SQL-Datenbankserver haben ähnliche Abfrageplaner und ähnliche Leistungsengpässe.
Paul Tomblin
9
@ Timothy Bitte veröffentlichen Sie Ihre Ergebnisse erneut.
Jake McGraw
2
Bei so vielen Kommentaren und Antworten wird davon ausgegangen, dass Schlüssel für Verknüpfungen verwendet werden können. Sie sind nicht. Schlüssel dienen der Datenkonsistenz, um doppelte Zeilen zu vermeiden (mehr als eine Zeile, die dieselbe Entität darstellt). Jede Spalte (oder jeder Satz von Spalten) kann in einem Join verwendet werden. Um sicherzustellen, dass der Join eins zu null ist oder viele, müssen die Spalten einfach eindeutig sein. Jeder eindeutige Index garantiert dies und muss nicht aussagekräftig sein.
Charles Bretana

Antworten:

78

Sie machen einen guten Punkt, dass Sie eine bestimmte Anzahl von verknüpften Abfragen vermeiden können, indem Sie einen sogenannten natürlichen Schlüssel anstelle eines Ersatzschlüssels verwenden . Nur Sie können beurteilen, ob der Nutzen davon in Ihrer Anwendung von Bedeutung ist.

Das heißt, Sie können die Abfragen in Ihrer Anwendung messen, die für die Schnelligkeit am wichtigsten sind, da sie mit großen Datenmengen arbeiten oder sehr häufig ausgeführt werden. Wenn diese Abfragen von der Beseitigung eines Joins profitieren und nicht unter der Verwendung eines varchar-Primärschlüssels leiden, tun Sie dies.

Verwenden Sie keine der beiden Strategien für alle Tabellen in Ihrer Datenbank. In einigen Fällen ist ein natürlicher Schlüssel wahrscheinlich besser, in anderen Fällen ist ein Ersatzschlüssel besser.

Andere Leute weisen darauf hin, dass es in der Praxis selten vorkommt, dass sich ein natürlicher Schlüssel niemals ändert oder Duplikate aufweist. Daher lohnen sich Ersatzschlüssel normalerweise.

Bill Karwin
quelle
3
Und manchmal (imho, oft) ist beides besser, der Ersatz für FK-Referenzen in anderen Tabellen und für Joins und der natürliche Schlüssel zur Gewährleistung der Datenkonsistenz
Charles Bretana
@ CharlesBretana Das ist interessant. Ist die Verwendung eines natürlichen Schlüssels für die Datenkonsistenz neben der FK eine gängige Praxis? Mein erster Gedanke war, dass sich der zusätzliche Speicherplatz, der für große Tische benötigt wird, möglicherweise nicht lohnt. Jede Information wird geschätzt. Zu Ihrer Information - Ich habe einen anständigen Programmierhintergrund, aber meine SQL-Erfahrung beschränkt sich hauptsächlich auf SELECT-Abfragen
Rob
2
@CharlesBretana Wenn ich "beide speichern" lese, denke ich "Redundanz" und "nicht normalisiert", was gleich "Dieses Zeug könnte vermasselt werden" und "Ich muss sicherstellen, dass beide geändert werden, wenn eines jemals geändert wird" bedeutet. Wenn Sie Redundanz haben, sollte es einen sehr guten Grund geben (wie eine völlig inakzeptable Leistung), da Redundanz immer dazu führen kann, dass Ihre Daten inkonsistent werden.
jpmc26
3
@ jpmc26, Es gibt absolut KEINE Probleme mit Redundanz oder Normalisierung. Ein Ersatzschlüssel hat keine sinnvolle Verbindung zu den Werten in einem natürlichen Schlüssel, daher sollte er niemals geändert werden müssen. Über welche Normalisierungsprobleme sprechen Sie in Bezug auf die Normalisierung? Normalisierung gilt für sinnvolle Attribute einer Beziehung; Der numerische Wert eines Ersatzschlüssels (in der Tat das Konzept eines Ersatzschlüssels selbst) liegt völlig außerhalb des Kontextes einer Normalisierung.
Charles Bretana
1
Und um Ihre andere Frage zu beantworten, insbesondere zu einer Tabelle mit Staaten, wenn Sie einen Ersatzschlüssel in dieser Tabelle mit Werten von beispielsweise 1 bis 50 hatten, aber KEINEN anderen eindeutigen Index oder Schlüssel in die Postleitzahl des Staates eingefügt haben, (und meiner Meinung nach auch zum Staatsnamen), was hindert dann jemanden daran, zwei Zeilen mit unterschiedlichen Ersatzschlüsselwerten, aber mit derselben Postleitzahl und / oder demselben Staatsnamen einzugeben? Wie würde die Client-App damit umgehen, wenn es zwei Zeilen mit 'NJ', 'New Jersey' gäbe? Natürliche Schlüssel sorgen für Datenkonsistenz!
Charles Bretana
81

Es geht nicht um Leistung. Es geht darum, was einen guten Primärschlüssel ausmacht. Einzigartig und unveränderlich im Laufe der Zeit. Sie denken vielleicht, dass sich eine Entität wie ein Ländercode im Laufe der Zeit nie ändert und ein guter Kandidat für einen Primärschlüssel wäre. Aber bittere Erfahrung ist, dass das selten so ist.

INT AUTO_INCREMENT erfüllt die Bedingung "eindeutig und über die Zeit unverändert". Daher die Präferenz.

Steve McLeod
quelle
25
Wahr. Eine meiner größten Datenbanken enthält Einträge für Jugoslawien und die Sowjetunion. Ich bin froh, dass sie keine Primärschlüssel sind.
Paul Tomblin
8
@Steve, warum unterstützt ANSI SQL dann die Syntax für ON UPDATE CASCADE?
Bill Karwin
5
Unveränderlichkeit ist keine Voraussetzung für einen Schlüssel. In jedem Fall ändern sich manchmal auch Ersatzschlüssel. Es ist nichts Falsches daran, die Schlüssel zu ändern, wenn Sie müssen.
Nvogel
9
Paul, also haben Sie die Sowjetunion in Ihrer Datenbank in Russland geändert? Und so tun, als ob SU niemals existiert? Und alle Verweise auf SU deuten jetzt auf Russland hin?
Dainius
6
@alga Ich wurde in SU geboren, also weiß ich was es ist.
Dainius
52

Ich war ein bisschen verärgert über das Fehlen von Benchmarks für dieses Online, also habe ich selbst einen Test durchgeführt.

Beachten Sie jedoch, dass ich dies nicht regelmäßig mache. Überprüfen Sie daher mein Setup und meine Schritte auf Faktoren, die die Ergebnisse unbeabsichtigt beeinflusst haben könnten, und veröffentlichen Sie Ihre Bedenken in Kommentaren.

Das Setup war wie folgt:

  • Intel® Core ™ i7-7500U CPU bei 2,70 GHz × 4
  • 15,6 GiB RAM, von denen ich sicherstellte, dass ungefähr 8 GB während des Tests frei waren.
  • 148,6 GB SSD-Laufwerk mit viel freiem Speicherplatz.
  • Ubuntu 16.04 64-Bit
  • MySQL Ver 14.14 Distrib 5.7.20 für Linux (x86_64)

Die Tische:

create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;

Dann füllte ich 10 Millionen Zeilen in jeder Tabelle mit einem PHP-Skript, dessen Wesen wie folgt ist:

$pdo = get_pdo();

$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];

for ($k = 0; $k < 10; $k++) {
    for ($j = 0; $j < 1000; $j++) {
        $val = '';
        for ($i = 0; $i < 1000; $i++) {
            $val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
        }
        $val = rtrim($val, ',');
        $pdo->query('INSERT INTO jan_char VALUES ' . $val);
    }
    echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}

Für intTabellen wurde das Bit ($keys[rand(0, 9)])durch just ersetzt rand(0, 9), und für varcharTabellen habe ich vollständige US-Statusnamen verwendet, ohne sie auf 6 Zeichen zu schneiden oder zu erweitern.generate_random_string()generiert eine 10-stellige Zufallszeichenfolge.

Dann lief ich in MySQL:

  • SET SESSION query_cache_type=0;
  • Für jan_intTabelle:
    • SELECT count(*) FROM jan_int WHERE myindex = 5;
    • SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
  • Für andere Tabellen wie oben, mit myindex = 'califo'für charTabellen und myindex = 'california'für varcharTabellen.

Zeiten der BENCHMARKAbfrage für jede Tabelle:

  • jan_int: 21.30 sek
  • jan_int_index: 18,79 Sek
  • jan_char: 21,70 Sek
  • jan_char_index: 18,85 Sek
  • jan_varchar: 21,76 Sek
  • jan_varchar_index: 18,86 Sek

In Bezug auf Tabellen- und Indexgrößen ist hier die Ausgabe von show table status from janperformancetest;(mit einigen nicht gezeigten Spalten):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name              | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation              |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int           | InnoDB |      10 | Dynamic    | 9739094 |             43 |   422510592 |               0 |            0 |   4194304 |           NULL | utf8mb4_unicode_520_ci |  
| jan_int_index     | InnoDB |      10 | Dynamic    | 9740329 |             43 |   420413440 |               0 |    132857856 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_char          | InnoDB |      10 | Dynamic    | 9726613 |             51 |   500170752 |               0 |            0 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_char_index    | InnoDB |      10 | Dynamic    | 9719059 |             52 |   513802240 |               0 |    202342400 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_varchar       | InnoDB |      10 | Dynamic    | 9722049 |             53 |   521142272 |               0 |            0 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_varchar_index | InnoDB |      10 | Dynamic    | 9738381 |             49 |   486539264 |               0 |    202375168 |   7340032 |           NULL | utf8mb4_unicode_520_ci | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

Mein Fazit ist, dass es für diesen speziellen Anwendungsfall keinen Leistungsunterschied gibt.

Jan Żankowski
quelle
Ich weiß, dass es jetzt spät ist, aber ich wäre gespannt auf die Ergebnisse gewesen, wenn Sie eine weniger ideale Saite für die Where-Bedingung ausgewählt hätten. "califo [rnia]" war ideal, da es Fehlpaarungen nach dem Vergleich des ersten Zeichens verwerfen konnte und nur die tatsächlichen Übereinstimmungen weiter überprüfen musste; so etwas wie "newham" hätte interessantere Ergebnisse geliefert, da es neu wäre, mehr Charakter zu vergleichen, um alle Fehlpaarungen zu beseitigen. Wenn Sie Ihre Ganzzahlen auf diese Weise einschränken, stapeln Sie auch die Chancen gegen sie. Ich hätte ihnen mindestens 26 Werte gegeben.
Uueerdo
15
Erstaunlich, dass dies bei einer 10 Jahre alten Frage nur eine von zwei Antworten ist, die nicht nur Spekulationen sind und sich auf tatsächliche Benchmarks stützen.
Adrian Baker
1
Ihre Tabellen haben jedoch keinen Primärschlüssel, der in InnoDB tatsächlich eine sortierte Datenstruktur ist. Die Geschwindigkeit zwischen Ganzzahlsortierung und Zeichenfolgensortierung sollte unterschiedlich sein.
Melkor
1
@ Melkor Fair Punkt, den ich INDEXanstelle von PRIMARY KEY. Ich erinnere mich nicht an meine Argumentation - ich habe wahrscheinlich angenommen, dass PRIMARY KEYes sich nur um eine INDEXEinschränkung der Eindeutigkeit handelt. Wenn ich jedoch den Abschnitt darüber lese , wie Dinge in InnoDB unter federico-razzoli.com/primary-key-in-innodb gespeichert werden , denke ich, dass meine Ergebnisse immer noch für Primärschlüssel gelten, und beantworte die Frage zum Leistungsunterschied bei der Wertesuche . Auch Ihr Kommentar schlägt vor , bei der Ausführung der Suche Sortieralgorithmen, die gelten nicht für die Verwendung Fall , den ich untersuchen, welche aufzublicken Werte in einem Satz.
Jan Żankowski
1
Die Suchoperation erfordert auch Vergleiche im Primärschlüsselfeld (wie bei einer binären Suche), wobei int etwas schneller als varchar sein sollte. Aber wie Ihre Experimente gezeigt haben, ist dies nicht so offensichtlich (oder vielleicht, weil Sie keinen Primärschlüssel hatten und die Abfragen alle langsamer waren). Ich denke, es ist dasselbe beim Einfügen und Nachschlagen.
Melkor
38

Hängt von der Länge ab. Wenn der Varchar 20 Zeichen und der Int 4 ist, hat Ihr Index bei Verwendung eines Int FÜNF Mal so viele Knoten pro Seite Indexspeicherplatz auf der Festplatte ... Das bedeutet, dass das Durchlaufen erfolgt Der Index erfordert ein Fünftel so viele physische und / oder logische Lesevorgänge.

Wenn die Leistung ein Problem darstellt, verwenden Sie bei Gelegenheit immer einen integralen, nicht aussagekräftigen Schlüssel (als Ersatzschlüssel bezeichnet) für Ihre Tabellen und für Fremdschlüssel, die auf die Zeilen in diesen Tabellen verweisen ...

Um die Datenkonsistenz zu gewährleisten, sollte jede Tabelle, auf die es ankommt, auch einen aussagekräftigen nicht numerischen Alternativschlüssel (oder einen eindeutigen Index) haben, um sicherzustellen, dass keine doppelten Zeilen eingefügt werden können (doppelte basierend auf aussagekräftigen Tabellenattributen).

Für die spezifische Verwendung, über die Sie sprechen (wie Status-Lookups), spielt es keine Rolle, da die Größe der Tabelle so klein ist. Im Allgemeinen hat dies keinen Einfluss auf die Leistung von Indizes für Tabellen mit weniger als einigen tausend Zeilen. ..

Charles Bretana
quelle
Sicher? Sind die meisten Datenformate nicht zeilenbasiert? Neben den Schlüsseln gibt es noch andere Daten. Ist Faktor 5 nicht utopisch?
ManuelSchneid3r
1
@ manuelSchneid3r, was? utopisch? Nein, der Faktor 5 ist nicht "utopisch". Es ist nur 20 geteilt durch 4. Und was bedeutet "zeilenbasiert im Datenformat"? Indizes sind nicht "zeilenbasiert", sondern ausgeglichene Baumstrukturen.
Charles Bretana
36

Absolut nicht.

Ich habe mehrere ... mehrere ... Leistungsprüfungen zwischen INT, VARCHAR und CHAR durchgeführt.

10 Millionen Datensatztabellen mit einem PRIMARY KEY (eindeutig und gruppiert) hatten genau die gleiche Geschwindigkeit und Leistung (und Teilbaumkosten), unabhängig davon, welche der drei von mir verwendet wurde.

Davon abgesehen ... verwenden Sie das, was für Ihre Anwendung am besten ist. Mach dir keine Sorgen über die Leistung.

Timothy Khouri
quelle
42
bedeutungslos, ohne zu wissen, wie lange die Varchars waren ... Wenn sie 100 Bytes breit wären, würden Sie garantiert nicht die gleiche Leistung wie ein 4-Byte-Int erhalten
Charles Bretana
6
Es ist auch hilfreich zu wissen, welche Datenbank Sie verwenden und welche Version der Datenbank. Die Leistungsoptimierung wird fast immer von Version zu Version bearbeitet und verbessert.
Dave Black
VARCHAR ist definitiv wichtig für die Indexgröße. Und der Index bestimmt, wie viel in den Speicher passen kann. Und Indizes im Speicher sind viel, viel schneller als solche, die es nicht sind. Es könnte sein, dass für Ihre 10-m-Zeilen 250 MB Speicher für diesen Index verfügbar waren und dies in Ordnung war. Aber wenn Sie 100 m Zeilen haben, werden Sie in diesem Speicher weniger gut sein.
Paul Draper
9

Bei Funktionscodes gibt es wahrscheinlich keinen Unterschied. Dies gilt insbesondere, da die Tabelle mit diesen Codes wahrscheinlich sehr klein ist (höchstens ein paar tausend Zeilen) und sich nicht oft ändert (wann haben wir das letzte Mal einen neuen US-Bundesstaat hinzugefügt).

Bei größeren Tabellen mit einer größeren Variation zwischen den Schlüsseln kann dies gefährlich sein. Denken Sie beispielsweise an die Verwendung der E-Mail-Adresse / des Benutzernamens aus einer Benutzertabelle. Was passiert, wenn Sie einige Millionen Benutzer haben und einige dieser Benutzer lange Namen oder E-Mail-Adressen haben? Jedes Mal, wenn Sie diese Tabelle mit diesem Schlüssel verbinden müssen, wird sie viel teurer.

Joel Coehoorn
quelle
2
Wissen Sie sicher, dass dies teuer wäre? Oder raten Sie nur?
Steve McLeod
Natürlich hängt es von der rdbms-Implementierung ab, aber soweit ich weiß, behalten die meisten Server den Hash des tatsächlichen Werts für Indizierungszwecke bei. Trotzdem und selbst wenn es sich um einen relativ kurzen Hash handelt (z. B. 10 Byte), ist es immer noch mehr Arbeit, 2 10-Byte-Hashes als 2 4-Byte-Ints zu vergleichen.
Joel Coehoorn
Verwenden Sie NIEMALS einen langen (breiten) Schlüssel für Verknüpfungen ... Wenn dies jedoch die beste Darstellung dessen ist, was für die Zeilen in der Tabelle eindeutig ist, sollten Sie einen eindeutigen Schlüssel (oder Index - das ist dasselbe) auf dem Tabelle mit diesen natürlichen Werten. Schlüssel sind nicht für Joins da, Sie können sich an allem beteiligen, was Ihr Herz begehrt. Schlüssel dienen dazu, die Datenkonsistenz sicherzustellen.
Charles Bretana
6

Was den Primärschlüssel betrifft, sollte als Primärschlüssel festgelegt werden, was eine Zeile physisch eindeutig macht.

Für eine Referenz als Fremdschlüssel ist die Verwendung einer automatisch inkrementierenden Ganzzahl als Ersatz aus zwei Hauptgründen eine gute Idee.
- Erstens fällt beim Join normalerweise weniger Overhead an.
- Zweitens, wenn Sie die Tabelle aktualisieren müssen, die das eindeutige varchar enthält, muss das Update auf alle untergeordneten Tabellen herunterkaskadiert und alle sowie die Indizes aktualisiert werden, während beim int-Ersatz nur das aktualisiert werden muss Mastertabelle und ihre Indizes.

Der Nachteil bei der Verwendung des Ersatzes besteht darin, dass Sie möglicherweise eine Änderung der Bedeutung des Ersatzes zulassen können:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

Es hängt alles davon ab, worüber Sie sich in Ihrer Struktur wirklich Sorgen machen müssen und was am meisten bedeutet.

LeppyR64
quelle
3

Häufige Fälle, in denen ein Ersatz AUTO_INCREMENTweh tut:

Ein allgemeines Schemamuster ist eine Viele-zu-Viele-Zuordnung :

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

Die Leistung dieses Musters ist viel besser, insbesondere bei Verwendung von InnoDB:

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

Warum?

  • InnoDB-Sekundärschlüssel benötigen eine zusätzliche Suche. durch Verschieben des Paares in die PK wird dies für eine Richtung vermieden.
  • Der Sekundärindex ist "abdeckend", daher ist keine zusätzliche Suche erforderlich.
  • Diese Tabelle ist kleiner, weil idein Index entfernt wurde.

Ein anderer Fall ( Land ):

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

Allzu oft normalisiert der Anfänger den Ländercode in ein 4-Byte INT anstatt eine 'natürliche' 2-Byte-Zeichenfolge zu verwenden, die sich fast nicht . Schneller, kleiner, weniger JOINs, besser lesbar.

Rick James
quelle
2

Bei HauteLook haben wir viele unserer Tabellen geändert, um natürliche Schlüssel zu verwenden. Wir haben eine echte Leistungssteigerung erlebt. Wie Sie bereits erwähnt haben, verwenden viele unserer Abfragen jetzt weniger Verknüpfungen, wodurch die Abfragen leistungsfähiger werden. Wir werden sogar einen zusammengesetzten Primärschlüssel verwenden, wenn dies sinnvoll ist. Abgesehen davon sind einige Tabellen einfacher zu bearbeiten, wenn sie einen Ersatzschlüssel haben.

Wenn Sie zulassen, dass Benutzer Schnittstellen in Ihre Datenbank schreiben, kann ein Ersatzschlüssel hilfreich sein. Der Dritte kann sich darauf verlassen, dass sich der Ersatzschlüssel nur in sehr seltenen Fällen ändert.

Herman J. Radtke III
quelle
2

Ich stand vor dem gleichen Dilemma. Ich habe ein DW (Konstellationsschema) mit 3 Faktentabellen erstellt: Verkehrsunfälle, Fahrzeuge bei Unfällen und Unfallopfer. Die Daten umfassen alle von 1979 bis 2012 in Großbritannien erfassten Unfälle sowie 60 Dimensionstabellen. Insgesamt rund 20 Millionen Datensätze.

Faktentabellen Beziehungen:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

RDMS: MySQL 5.6

Der Unfallindex ist ein Varchar (Zahlen und Buchstaben) mit 15 Ziffern. Ich habe versucht, keine Ersatzschlüssel zu haben, sobald sich die Unfallindizes nie ändern würden. In einem i7-Computer (8 Kerne) wurde der DW zu langsam, um nach 12 Millionen Lastdatensätzen abhängig von den Abmessungen abzufragen. Nach vielen Überarbeitungen und dem Hinzufügen von Bigint-Ersatzschlüsseln erhielt ich eine durchschnittliche Geschwindigkeitssteigerung von 20%. Noch zu geringem Leistungsgewinn, aber gültiger Versuch. Ich arbeite in MySQL Tuning und Clustering.

Diego Duarte
quelle
1
Klingt so, als müssten Sie sich um die Partitionierung kümmern.
Jcoffland
2

Die Frage bezieht sich auf MySQL, daher gibt es einen signifikanten Unterschied. Wenn es um Oracle ging (das Zahlen als Zeichenfolge speichert - ja, ich konnte es zuerst nicht glauben), dann kein großer Unterschied.

Die Speicherung in der Tabelle ist nicht das Problem, aber das Aktualisieren und Verweisen auf den Index ist. Abfragen, bei denen ein Datensatz anhand seines Primärschlüssels nachgeschlagen wird, sind häufig. Sie möchten, dass sie so schnell wie möglich ausgeführt werden, da sie so häufig auftreten.

Die Sache ist, dass eine CPU natürlich mit 4-Byte- und 8-Byte-Ganzzahlen in Silizium umgeht . Es ist WIRKLICH schnell, zwei ganze Zahlen zu vergleichen - es geschieht in ein oder zwei Taktzyklen.

Schauen Sie sich jetzt eine Zeichenfolge an - sie besteht aus vielen Zeichen (heutzutage mehr als ein Byte pro Zeichen). Das Vergleichen von zwei Zeichenfolgen auf Vorrang kann nicht in einem oder zwei Zyklen durchgeführt werden. Stattdessen müssen die Zeichen der Zeichenfolgen iteriert werden, bis ein Unterschied festgestellt wird. Ich bin mir sicher, dass es Tricks gibt, um es in einigen Datenbanken schneller zu machen, aber das ist hier irrelevant, da ein int-Vergleich auf natürliche Weise und blitzschnell von der CPU in Silizium durchgeführt wird.

Meine allgemeine Regel - jeder Primärschlüssel sollte ein automatisch inkrementierendes INT sein, insbesondere in OO-Apps, die ein ORM (Hibernate, Datanucleus, was auch immer) verwenden, in dem es viele Beziehungen zwischen Objekten gibt - sie werden normalerweise immer als einfaches FK und die Fähigkeit für das implementiert DB, um diese Probleme schnell zu lösen, ist wichtig für die Reaktionsfähigkeit Ihrer App.

Volksman
quelle
0

Sie sind sich nicht sicher über die Auswirkungen auf die Leistung, aber es scheint ein möglicher Kompromiss zu sein, zumindest während der Entwicklung, sowohl den automatisch inkrementierten, ganzzahligen "Ersatz" -Schlüssel als auch Ihren beabsichtigten, eindeutigen "natürlichen" Schlüssel einzuschließen. Dies gibt Ihnen die Möglichkeit, die Leistung sowie andere mögliche Probleme zu bewerten, einschließlich der Änderbarkeit natürlicher Schlüssel.

Sauerstoff
quelle
0

Wie üblich gibt es keine pauschalen Antworten. 'Es hängt davon ab, ob!' und ich bin nicht scherzhaft. Mein Verständnis der ursprünglichen Frage war, dass Schlüssel in kleinen Tabellen - wie Country (Ganzzahl-ID oder char / varchar-Code) - ein Fremdschlüssel für eine potenziell große Tabelle wie Adresse / Kontakttabelle sind.

Hier gibt es zwei Szenarien, in denen Sie Daten aus der Datenbank zurückerhalten möchten. Das erste ist eine Listen- / Suchabfrage, bei der Sie alle Kontakte mit Staats- und Ländercodes oder -namen auflisten möchten (IDs helfen nicht und benötigen daher eine Suche). Das andere ist ein Get-Szenario für den Primärschlüssel, in dem ein einzelner Kontaktdatensatz angezeigt wird, in dem der Name des Staates und des Landes angezeigt werden muss.

Für letztere ist es wahrscheinlich egal, worauf die FK basiert, da wir Tabellen für einen einzelnen Datensatz oder einige Datensätze und für Schlüssellesevorgänge zusammenführen. Das erstere Szenario (Suche oder Liste) kann durch unsere Wahl beeinflusst werden. Da das Land angezeigt werden muss (zumindest ein erkennbarer Code und möglicherweise sogar die Suche selbst einen Ländercode enthält), kann es möglicherweise möglich sein, nicht über einen Ersatzschlüssel einer anderen Tabelle beizutreten (ich bin hier nur vorsichtig, weil ich nicht tatsächlich getestet habe) dies, scheint aber sehr wahrscheinlich) die Leistung zu verbessern; ungeachtet der Tatsache, dass es sicherlich bei der Suche hilft.

Da die Codes klein sind - normalerweise nicht mehr als 3 Zeichen für Land und Bundesland - kann es in diesem Szenario in Ordnung sein, die natürlichen Schlüssel als Fremdschlüssel zu verwenden.

Das andere Szenario, in dem Schlüssel von längeren Varchar-Werten und möglicherweise von größeren Tabellen abhängen. Der Ersatzschlüssel hat wahrscheinlich den Vorteil.

Vinod
quelle
0

Gestatten Sie mir, zu sagen, dass es unter Berücksichtigung des Leistungsumfangs definitiv einen Unterschied gibt (Standarddefinition):

1- Die Verwendung von Surrogate Int ist in der Anwendung schneller, da Sie ToUpper (), ToLower (), ToUpperInvarient () oder ToLowerInvarient () nicht in Ihrem Code oder in Ihrer Abfrage verwenden müssen und diese 4 Funktionen unterschiedliche Leistungsbenchmarks haben. Siehe hierzu die Microsoft-Leistungsregeln. (Leistung der Anwendung)

2- Die Verwendung von Surrogate Int garantiert, dass der Schlüssel im Laufe der Zeit nicht geändert wird. Sogar Ländercodes können sich ändern, siehe Wikipedia, wie sich ISO-Codes im Laufe der Zeit geändert haben. Das würde viel Zeit in Anspruch nehmen, um den Primärschlüssel für Teilbäume zu ändern. (Durchführung der Datenpflege)

3- Es scheint Probleme mit ORM-Lösungen zu geben, z. B. NHibernate, wenn PK / FK nicht int ist. (Entwicklerleistung)

Shadi Namrouti
quelle