È necessaria una colonna ID univoco in una tabella moltiplicata (giunzione)?


22

Iniziare alcuni progetti con EF, ma ho avuto alcune domande su join tabelle e chiavi ecc. Diciamo che ho una tabella di applicazioni e una tabella di autorizzazioni. Le applicazioni hanno molte autorizzazioni e ogni autorizzazione può appartenere a molte applicazioni (molte-a-molte).

Ora, le tabelle Applicazione e Autorizzazione sono facili:

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

Ma qual è il modo MIGLIORE per fare il tavolo di join? Ho queste due opzioni:

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

O

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

Sei mai stato bruciato facendolo in un modo sopra l'altro? è strettamente preferenza? Mi è venuto in mente che molte delle "differenze" verranno sottratte dal mio modello di repository (ad esempio, non creerei quasi mai un intero oggetto di autorizzazione e lo aggiungerei a un'applicazione, ma lo faccio per ID o nome univoco o qualcosa), ma immagino che sto cercando storie horror, in un modo o nell'altro.

Risposte:


20

Credo che tu intenda la tabella "junction", non la tabella "join".

Non è necessario che una tabella di giunzione abbia il proprio campo ID. Non dovrai mai unirti o filtrare un simile ID. Ti uniresti o filtreresti solo sugli ID delle tabelle che stai mappando. Un ID su una tabella di giunzione è uno spreco di spazio su disco.

Quindi l'opzione "migliore" è quella di evitare l'ID. In genere una tabella di giunzione avrà 2 indici di copertura. Ogni indice di copertura utilizza uno degli ID mappati come campo di ordinamento principale.

Ma "il migliore" non è di gran lunga. È un problema molto piccolo avere un campo ID ridondante. Non avrai storie horror su una piccola quantità di disco sprecato. L'ID non "ruba" l'indice cluster perché non si desidera raggruppare comunque sulla combo mappata.

Se il tuo framework vuole che tutte le tabelle abbiano un ID, allora provaci. Se gli standard del database del tuo team impongono che tutte le tabelle debbano avere un ID, procedi. In caso contrario, evitarlo.


2
Bene, hai già affermato che l'aggiunta di un ID è una concessione minore, facilmente superabile dai potenziali vantaggi, quindi mi sembrerebbe che (dato che avere un ID univoco in ogni tabella è più o meno la migliore pratica nella maggior parte dei DBMS e degli ORM) si consiglia di avere un ID come opzione "migliore" o "predefinita", anziché non averne uno.
Robert Harvey,

4
"Non avresti mai bisogno di unirti o fare una query su un simile ID" - dire "mai" in una situazione tecnologica sta invitando proprio quello che succede. Detto questo, ci sono momenti in cui ti unirai a quella tabella di join (sì, l'ho sentita fare riferimento a una tabella "join" più di una tabella "junction") a una quarta tabella perché le entità unite sono in realtà un business object di loro proprietà.
Jesse C. Slicer,

4
@RobertHarvey. Un ID è una buona pratica per le entità. Ma una giunzione è più un dettaglio di implementazione per molte relazioni, non un'entità a sé stante. Ma come sottolinea il cursore Jesse C., ci sono casi in cui un incrocio potrebbe essere considerato un'entità aziendale.
mike30,

1
"spreco di spazio su disco". - Penso che alcuni motori (InnoDB?) Creino comunque una chiave primaria (interna) se non ne crei una tu stesso - quindi potresti non guadagnare spazio su disco senza averne una.
Alex

@Alex. Metti un PK composito sugli ID mappati.
mike30,

11

Nel corso degli anni ho preso l'abitudine di assegnare ad ogni tabella "TableName" una chiave primaria generata automaticamente "TableNameID", senza eccezioni, nemmeno per le tabelle di giunzione. Posso dire di non essermene mai pentito, perché semplifica molte cose quando si crea un codice generico che fa qualcosa per "tutte le tabelle" o "alcune tabelle" o per "molte righe di più tabelle diverse".

Ad esempio, se qualcuno ti chiede di memorizzare alcune righe di tabelle diverse (o riferimenti a quelle) in un file o in memoria, ad esempio per scopi di registrazione, è molto utile quando sai in anticipo che devi solo archiviare esattamente una nome della tabella e esattamente un ID intero e non devi occuparti di "casi speciali".

Un'altra cosa, quando inizi con i PK combinati, probabilmente qualche volta dopo incontrerai la necessità di chiavi esterne combinate (poiché potresti arrivare a un punto in cui vuoi aggiungere un riferimento FK al tuo ApplicationPermissionstavolo). Quindi il prossimo requisito potrebbe essere che questo FK sia univoco insieme ad altri attributi o chiavi esterne, il che comporterà una maggiore complessità complessiva. Niente che non sia possibile gestire per la maggior parte dei moderni sistemi DB, ovviamente, ma una soluzione uniforme rende la vita dei programmatori spesso molto più semplice.

E infine, un'affermazione come SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)funziona bene con una singola colonna come chiave primaria, ma finora non ho mai visto un dialetto SQL che ti consente di farlo con le chiavi combinate. Se sai in anticipo che non avrai mai bisogno di una query come questa, va bene, ma non stupirti se domani otterrai un requisito che sarà risolto più facilmente con questo tipo di SQL.

Naturalmente, quando ti aspetti che la tua ApplicationPermissionstabella contenga diverse centinaia di milioni di righe, dovresti considerare di evitare qualcosa come un ApplicationPermissionsID.


Anche se non ho finito per scegliere la tua risposta. Mi piacciono gli aspetti. Grazie per i tuoi pensieri (voto positivo).
solidau,

6

Mentre la risposta di Mike è buona, ecco i motivi per cui aggiungerei o meno un campo ID separato.

  1. Prendere in considerazione l'utilizzo di un campo ID separato per la tabella junction / join se contiene campi diversi dall'ID . Questo tende a notare che si tratta di un'entità di prima classe.

  2. Prendi in considerazione l'utilizzo di un campo ID separato se le API o qualsiasi logica esistente tendono a utilizzare singoli campi per il recupero / modifica di entità. Ciò può aiutare altre persone a seguire il tuo codice nel contesto di un progetto più ampio.

  3. Non utilizzarlo se non vi è alcun vantaggio specifico (KISS). EF sa come gestire questo tipo di tabella e talvolta può mancare un vincolo univoco composito quando altre persone stanno cercando di capire questo tipo di relazione. Inoltre, durante la normalizzazione cerco di utilizzare la chiave più piccola possibile che definisce in modo univoco la tupla . Nel tuo secondo esempio, hai effettivamente 2 chiavi primarie candidate separate.


-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

Ricorda di creare un indice e una chiave esterna su entrambi PersonIde AddressId.

Indipendentemente da ciò che gli altri pensano "meglio" o "dovresti", questo è il modo più semplice e più semplice per consentire al database di funzionare correttamente.


1
Penso che un problema con questo approccio sia lo schema che consente due PersonAddressrighe con valori PersonIde AddressIdvalori identici .
Sam
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.