Preferirei il secondo approccio. Utilizzando numeri ID surrogati quando non sono logicamente necessari per l'identificazione, introduci join più obbligatori. Ciò richiede di "inseguire numeri ID in tutto il database", che è l'equivalente SQL di "inseguire puntatori in tutto il database". Inseguire i puntatori era caratteristico di IMS, una delle architetture di database che il modello relazionale intendeva sostituire. (IMS utilizza un'architettura gerarchica.) Non ha senso reinventarla oggi. (Anche se un molto delle persone fanno proprio questo.)
Se hai, ad esempio, cinque livelli di numeri ID surrogati e vuoi il nome di una persona, devi fare quattro join per ottenerlo. Usando il secondo approccio, hai solo bisogno di un join. Se non vuoi scrivere join multicolonna, usa CREATE VIEW e fallo solo una volta.
Le prestazioni sono semplici da testare . Basta generare alcuni milioni di righe casuali utilizzando il tuo linguaggio di scripting preferito e caricarle in un server di prova. Non solo troverai dove si nascondono i tuoi problemi di prestazioni, ma troverai tutti gli errori nel tuo codice CREATE TABLE. (Il tuo codice non funzionerà così com'è.) Ulteriori informazioni su EXPLAIN se non lo sai già.
Per quanto riguarda l'indicizzazione , puoi testarlo sulle righe casuali che generi e carichi. Un indice a più colonne su (nome, cognome) funzionerà meglio se gli utenti forniscono sempre un nome. Ma molti utenti non lo faranno, preferendo invece cercare per cognome. Un indice a più colonne su (nome, cognome) non è efficace per gli utenti che preferiscono eseguire la ricerca per cognome. Puoi testarlo.
Solo per questo motivo, l'indicizzazione di nomi e cognomi è solitamente più efficace se sono presenti due indici separati, uno per il nome e uno per il cognome.
Che cosa significa inseguire i numeri ID intendi?
Il modello di progettazione non detto alla base di questa domanda è "Ogni riga deve avere un numero ID e tutte le chiavi esterne devono fare riferimento al numero ID". In un database SQL, è in realtà un anti-pattern. Come regola generale, qualsiasi schema che ti consente di progettare tavoli senza pensare alle chiavi dovrebbe essere ritenuto colpevole fino a prova contraria:dovrebbe essere considerato un anti-modello fino a quando non viene dimostrato che non lo è.
create table A (
a_id integer primary key,
a_1 varchar(15) not null unique,
a_2 varchar(15) not null
);
create table B (
b_id integer primary key
a_id integer not null references A (a_id),
b_1 varchar(10) not null,
unique (a_id, b_1),
);
create table C (
c_id integer primary key,
b_id integer not null references B (b_id),
c_1 char(3) not null,
c_2 varchar(20) not null,
unique (b_id, c_1)
);
create table D (
d_id integer primary key,
c_id integer not null references C (c_id),
d_1 integer not null,
d_2 varchar(15),
unique (c_id, d_1)
);
Se hai bisogno di un rapporto sulla tabella "D", e il rapporto ha bisogno di
- colonne D.d_1 e D.d_2 e
- colonne A.a_1 e A.a_2,
hai bisogno di 3 join per arrivarci. (Prova.) Stai cercando numeri ID. (Come inseguire i puntatori in IMS.) La struttura seguente è diversa.
create table A (
a_1 varchar(15) primary key,
a_2 varchar(15) not null
);
create table B (
a_1 varchar(15) not null references A (a_1),
b_1 varchar(10) not null,
primary key (a_1, b_1),
);
create table C (
a_1 varchar(15) not null,
b_1 varchar(10) not null,
c_1 char(3) not null,
c_2 varchar(20) not null,
primary key (a_1, b_1, c_1),
foreign key (a_1, b_1) references B (a_1, b_1)
);
create table D (
a_1 varchar(15) not null,
b_1 varchar(10) not null,
c_1 char(3) not null,
d_1 integer not null,
d_2 varchar(15),
primary key (a_1, b_1, c_1, d_1),
foreign key (a_1, b_1, c_1) references C (a_1, b_1, c_1)
);
Con questa struttura, lo stesso report necessita di un unico join.
select D.d_1, D.d_2, A.a_1, A.a_2
from D
inner join A on D.a_1 = A.a_1;