2010-02-03 43 views
92

Questa domanda viene in su dopo aver letto un commento in questo domanda:SQL - molti-a-molti tabella primaria chiave

Database Design

Quando si crea una relazione molti-a-molti tavolo, si dovrebbe creare un composito chiave primaria sulle due colonne chiave esterna o creare una chiave primaria "ID" sostitutiva di auto-incremento e inserire solo indici sulle due colonne FK (e forse un vincolo univoco)? Quali sono le implicazioni sulla performance per l'inserimento di nuovi record/reindicizzazione in ciascun caso?

Fondamentalmente, questo:

PartDevice 
---------- 
PartID (PK/FK) 
DeviceID (PK/FK) 

vs. questo:

PartDevice 
---------- 
ID (PK/auto-increment) 
PartID (FK) 
DeviceID (FK) 

Il commentatore dice:

rendendo i due ID PK significa che la tabella di è fisicamente ordinato in base il disco in questo ordine. Quindi se inseriamo (Parte1/Dispositivo1), (Parte1/Dispositivo2), (Parte2/Dispositivo3), quindi (Parte 1/Dispositivo3) il database dovrà rompere il tavolo e inserire l'ultimo tra le voci 2 e 3. Per molti record , questo diventa molto problematico poiché consiste nel mescolare centinaia, migliaia o milioni di record ogni volta che ne viene aggiunto uno. Al contrario, un PK autoincrementante consente ai nuovi record di virare fino alla fine.

Il motivo che mi sto chiedendo è perché sono sempre stato incline a fare la chiave primaria composta senza colonna a incremento automatico surrogata, ma non sono sicuro se la chiave surrogata è in realtà più performante.

+0

ottima domanda, in attesa di alcune risposte da sql guru :) – sbczk

+0

Ecco una domanda silimar pubblicata su SO: http://stackoverflow.com/questions/344068/sql-server-clustered-index-order-of-index- domanda – Tony

+0

(tentativo di aggiungere questo al mio commento precedente ma non è possibile) A seconda del numero di inserti è anche possibile ricostruire periodicamente l'indice per assicurarsi che restituisca risultati rapidamente. In SQL Server è anche possibile modificare il FILLFACTOR dell'indice per fornire spazio sufficiente per gli inserti prima di spostare i dati. – Tony

risposta

60

Con un semplice due colonne molti-a-molti mappatura, non vedo alcun reale vantaggio di avere una chiave surrogata. Avere una chiave primaria su (col1,col2) è univoco garantito (supponendo che i valori col1 e col2 nelle tabelle di riferimento siano univoci) e un indice separato su (col2,col1) catturerà quei casi in cui l'ordine opposto verrebbe eseguito più rapidamente. Il surrogato è uno spreco di spazio.

Non avrete bisogno di indici sulle singole colonne poiché la tabella dovrebbe sempre essere utilizzata per unire le due tabelle di riferimento insieme.

Il commento a cui fai riferimento nella domanda non vale gli elettroni che usa, secondo me. Sembra che l'autore pensi che la tabella sia archiviata in una matrice piuttosto che in una struttura ad albero multidirezionale bilanciata ad altissime prestazioni.

Per iniziare, non è mai necessario archiviare o ottenere tabella ordinati, solo l'indice. E l'indice non sarà memorizzato in sequenza, verrà memorizzato in modo efficiente per poter essere recuperato rapidamente.

Inoltre, la maggior parte delle tabelle di database viene letta lontano più spesso di quanto scritto. Questo rende tutto ciò che fai sul lato selezionato molto più rilevante di qualsiasi cosa sul lato insert.

+0

L'ultimo punto non è una buona generalizzazione: "la maggior parte delle tabelle del database viene letta molto più spesso di quanto scritto". Trovo molti esempi di tabelle associative che devono essere scritti molto spesso, ad es. una tabella che collega il cliente all'ordine. – Medorator

+4

@buffer, risponderò a quel commento (tecnicamente, è una generalizzazione solo se dico "tutte le tabelle", "vasta maggioranza" si basa sull'esperienza).Pensiamo anche al tuo esempio, un ordine viene creato una volta (potrebbe essere aggiornato occasionalmente ma è improbabile che cambi le informazioni su chiave/indice, altro per colpire cose come lo stato degli ordini.) Tuttavia, quegli aggiornamenti e le selezioni che devi fare per stampare fatture o generare rapporti di gestione superano l'inserto originale – paxdiablo

+0

Pensa Amazon - Migliaia di ordini creati ogni ora – Medorator

12

Nessuna chiave surrogata è necessaria per le tabelle di collegamento.

One PK su (col1, col2) e un altro indice univoco (col2, col1) è tutto ciò che serve

A meno che non si utilizza un ORM che non può far fronte e detta il vostro disegno DB per voi ...

Edit: ho risposto lo stesso qui: SQL: Do you need an auto-incremental primary key for Many-Many tables?

+0

Grazie per il link ... interessante –

+3

Potrebbe essere OK con un indice di dups su col2 invece di un indice univoco su (col2, col1). Il vantaggio dell'indice a due colonne è che consente scansioni solo indice su col2 da solo o su col1 e col2 (anche se l'altro indice, su (col1, col2) gestisce anche il caso 'both'). Lo svantaggio è lo spazio di archiviazione aggiuntivo necessario per la colonna in più. Questo di solito non è significativo, quindi il consiglio è tutt'altro che orribile. Tuttavia, se col1 e col2 sono grandi o di dimensioni molto diverse, puoi risparmiare spazio senza danneggiare le prestazioni scegliendo di avere il secondo indice solo sulla colonna più corta. –

+0

@gbn: il secondo indice su (col2, col1) non deve necessariamente essere univoco, giusto? – Medorator

4

Il modo più breve e diretto per rispondere alla domanda è dire che ci sarà un impatto sulle prestazioni se le due tabelle che si stanno collegando non hanno le chiavi primarie sequenziali. Come dichiarato/quotato, l'indice per la tabella di collegamento diventerà frammentato, oppure il DBMS lavorerà più duramente per inserire i record se la tabella dei collegamenti non ha la propria chiave primaria sequenziale. Questo è il motivo per cui la maggior parte delle persone inserisce una chiave primaria ad incremento sequenziale nelle tabelle dei collegamenti.

8

Una chiave primaria incrementale potrebbe essere necessaria se si fa riferimento alla tabella. Potrebbero esserci dettagli nella tabella many-to-many che doveva essere tirata su da un'altra tabella usando la chiave primaria incrementale.

ad esempio

PartDevice 
---------- 
ID (PK/auto-increment) 
PartID (FK) 
DeviceID (FK) 
Other Details 

E 'facile tirare la 'Altri dati' utilizzando PartDevice.ID come l'FK. Quindi è necessario l'uso della chiave primaria incrementale.

Problemi correlati