2016-04-29 9 views
3

Hier ist, was ich habe:Composite-Schlüssel VS Primärschlüssel + nicht eindeutigen Index

table content : cat_id product_id data1 data2 etc.
die Kategorien offensichtlich nicht eindeutig sind. Die Produkt-IDs sind einzigartig.

2 queries : 1 -- SELECT * WHERE cat_id = :cat - must be as quick as possible 2 -- SELECT * WHERE product_id = :prodId In second select, I can add : AND cat_id = :cat

Was ist effizienter?

  • 1 - index (nicht eindeutig) auf cat_id (gut für select 1)
  • 2 - Primärschlüssel auf product_id (unique -> sehr gut für ausgewählten 2)
  • 3 - Index (nicht unique) auf cat_id + PK auf product_id (gut für 1 & 2 getrennt)
  • 4 - eindeutige Einschränkung mit composite [cat_id + product_id] (gut für 1 & 2 zusammen)
  • 5 - das gleiche wie 4, b ut Definition der Verbund als PK
  • 6 - Kunstoff (4 oder 5) + Einzelindex/PK

Informationen, werde ich rund 20 Produkte in jeder Kategorie und viele Kategorien (etwa 3000) haben - Und (wie es einzigartig in der Tabelle ist) EIN Produkt gehört nur zu einer Kategorie - In der Tat, das ist nicht wirklich Katzen und Produkte, das ist für die Einfachheit der Erklärung;)

danke!

+0

Nur ein Kopf in Option 4: Wenn ich mich richtig erinnere, kann MySQL die ersten Teile eines zusammengesetzten Schlüssels verwenden. Das heißt, wenn Sie Ihre Schlüssel wie in Option 4 definieren und dann eine Abfrage mit "WHERE cat_id = ..." erstellen, kann MySQL den Index verwenden (nicht so bei "WHERE product_id = ..."). http://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html – Sebastianb

+0

@Sebastianb - Danke, das ist die Art von Dingen, die ich nicht weiß: wie erstellt und später verwendet werden - zusammengesetzte Schlüssel vom Motor. Also, sagen wir in phpMyAdmin, die ORDER, in der wir die Zeilen setzen, wenn wir einen zusammengesetzten Index definieren, ist wichtig? [cat_id + produkt_id]! = [produkt_id + cat_id]? Ich habe die fünfte Option hinzugefügt. Hinzufügen der Zusammensetzung als PK ist immer besser, nicht? –

+0

Solange Sie nicht NULL Katzen und Produkte haben, können Sie nur den zusammengesetzten Schlüssel PK und ich denke, es wäre in Ordnung (überprüfen Sie hier für Unterschiede zwischen eindeutigen Indizes und PK's: http://StackOverflow.com/Questions/487314/primary -key-or-unique-index). Wenn Sie jedoch eine product_id finden möchten, werden Sie den zusammengesetzten Index nicht verwenden, also denke ich, dass es besser wäre, product_id als PK und cat_id als Index zu deklarieren. – Sebastianb

Antwort

5

Eine Datenbank ohne Primärschlüssel ist nur zur Hälfte verkleidet und Ihrer Meinung nach ist product_id ein idealer Kandidat für einen Primärschlüssel, also wählen Sie das aus. Der Primärschlüssel wird in

SELECT * WHERE product_id = :prodId 

verwendet werden Es spielt keine Rolle, ob and cat_id = :cat_id ein Teil der Abfrage wird oder nicht, es sei denn Sie haben Tausende von cat_ids mit jedem product_id verbunden.

Wählen Sie dann einen Index für cat_id. Dies wird verwendet werden

SELECT * WHERE cat_id = :cat 

Dies wird sehr schnell sein, wenn die Kardinalität der Daten gut ist. Das bedeutet, dass es eine breite Verteilung von cat_id s in der Tabelle gibt. Der Index cat_id wird nicht in der ersten Abfrage verwendet. So haben Sie zwei verschiedene Indizes und beide Abfragen können sehr schnell erwartet werden.

Seit [cat_id+product_id] != [product_id+cat_id] wenn es um Indexierung geht, wenn Sie nur einen zusammengesetzten Index haben, wird der eine oder andere langsam sein.

Angenommen, wir hätten einen zusammengesetzten Index für (cat_id, product_id) jetzt die folgende Abfrage kann diesen Index nicht verwenden.

SELECT * FROM tablename WHERE product_id = :prodId 

Aber beide diese Abfragen verwenden können, die (cat_id, product_id) Index

SELECT * FROM tablename WHERE cat_id = :cat_id and product_id = :prodId 
SELECT * FROM tablename WHERE cat_id = :catId 

Also zusammenfassend. Wähle 1 und 2.Aber wenn die Anzahl der cat_id s sind klein oder es gibt viele cat_ids mit jedem product_id verbunden wählen Sie 4, aber stellen Sie sicher, dass der Primärschlüssel auch vorhanden ist.

+0

Danke! Ich versuche gerade, alles zu verstehen :) Zur Information, ich werde ungefähr 20 Produkte in jeder Kategorie und vielen Kategorien haben (sagen wir 3000) - Und ein Produkt gehört nur zu EINER Kategorie - Eigentlich ist das nicht wirklich * Katzen und Produkte, das war für die Einfachheit der Erklärung;) –

+0

Also mit anderen Worten nur etwa 600.000 Zeilen pro Tabelle höchstens? Wahrscheinlich benötigen Sie für diese Datenmenge den zusammengesetzten Index überhaupt nicht. – e4c5

+1

Um Ihnen eine Idee zu geben, werden 600.000 Zeilen mit beiden Spalten nur 480k groß sein. mysql könnte hier überhaupt keinen Index verwenden, weil diese Datenmenge sofort gelesen werden kann – e4c5

1

Wenn diese Ihre nur zwei Anfragen:

SELECT * FROM tablename WHERE cat_id = :cat_id and product_id = :prodId 
SELECT * FROM tablename WHERE cat_id = :cat_id 

und Sie haben eine andere Art und Weise, um sicherzustellen, dass product_id ist UNIQUE, dann müssen Sie nur:

PRIMARY KEY(cat_id, product_id) 

Es ist optimal für beideSELECTs.

Es ist besser als INDEX(cat_id), weil (1) sekundäre Schlüssel ihre Arbeit mit einem PK-Lookup beenden müssen, und (2) alle Cat-Zeilen sind benachbart, dadurch effizienter.

Wenn product_id ist eigentlich ein AUTO_INCREMENT, fügen Sie dann

INDEX(product_id) 

Nein, Sie müssen UNIQUE nicht sagen (es sei denn, Sie sind anfällig absichtlich doppelte product_ids einfügen zu versuchen). Die einzige Sache, die AI erfordert, ist, dass die ID in einige Index zuerst ist, so dass es das Äquivalent von SELECT max(id) tun kann, wenn mysqld neu gestartet wird.

Meine Empfehlungen gelten unabhängig von der Größe der Tabelle.

Die Reihenfolge der Klauseln in WHERE tut nicht Angelegenheit.

JOINs nicht erfordert etwas besonderes. Es ist etwas effizienter zu JOIN auf einem PRIMARY KEY als auf einem sekundären Schlüssel, der viel effizienter ist (aber immer noch möglich) als auf einer nicht indizierten Spalte (n).

+0

Meine zweite Abfrage (in meiner ursprünglichen Frage) kann cat_id in der WHERE-Klausel verwenden. Daher ist es möglich, "WHERE cat_id =: cat_id UND product_id =: prodId" zu verwenden. Wie Sie sagten, scheint die 5. Option alle Erwartungen zu erfüllen (sogar für JOINs). Aber nur um sicher zu sein "neben" und AutoIncrement: mein Tisch kann wie aussehen (cat/prod): 2/27, 4/34, 1/37, 2/12, 5/17, 2/68 ... - -> Katzen sind keine Nachbarn und Produkte sind NICHT AI ... empfehlen Sie immer noch OPTION 5? –

+0

Mit 'ENGINE = InnoDB' werden die Zeilen in dieser Reihenfolge gespeichert: 1/37, 2/17, 2/27, 2/68, 4/34, 5/17. Und da es effizient ist, einen Teil der Tabelle linear abzutasten, profitieren Sie von "Clustering"/"Adjazenz". Wenn Sie auch ein Auto_Increment haben, vermasselt das Dinge. Sie haben einen guten eindeutigen Schlüssel, es muss auch kein auto_increment vorhanden sein. –

+0

Das _data_ (in InnoDB) wird in PK-Reihenfolge gespeichert. Jedes neue 'INSERT' wird den richtigen (auf PK basierenden) Platz in den Daten finden, um die neue Zeile zu speichern. Das heißt, Sie bezahlen während "INSERT" etwas und gewinnen während "SELECT" einen Vorteil. –

Verwandte Themen