Jeg foretrækker den anden tilgang. Ved at bruge surrogat-id-numre, når de ikke er logisk nødvendige for identifikation, introducerer du flere obligatoriske joinforbindelser. Dette kræver, at du "jager id-numre over hele databasen", hvilket svarer til SQL, der svarer til "at jage pointere over hele databasen". At jage pointere var karakteristisk for IMS, en af de databasearkitekturer, som den relationelle model havde til hensigt at erstatte. (IMS bruger en hierarkisk arkitektur.) Det nytter ikke at genopfinde det i dag. (Selvom en masse af mennesker gør netop det.)
Hvis du for eksempel har fem niveauer af surrogat-id-numre, og du vil have en persons navn, skal du lave fire joins for at få det. Ved at bruge den anden tilgang, skal du blot have én joinforbindelse. Hvis du ikke vil skrive sammenkædninger med flere kolonner, skal du bruge CREATE VIEW og gøre det én gang.
Ydeevnen er enkel at teste . Bare generer et par millioner tilfældige rækker ved hjælp af dit foretrukne scriptsprog, og indlæs dem på en testserver. Du finder ikke kun, hvor dine præstationsproblemer gemmer sig, du finder alle fejlene i din CREATE TABLE-kode. (Din kode fungerer ikke som den er.) Lær om EXPLAIN hvis du ikke allerede kender til det.
Hvad angår indeksering , kan du teste det på de tilfældige rækker, du genererer og indlæser. Et indeks med flere kolonner på (fornavn, efternavn) vil fungere bedst, hvis brugere altid angiver et fornavn. Men mange brugere vil ikke gøre det, de foretrækker at søge på efternavn i stedet for. Et indeks med flere kolonner på (fornavn, efternavn) er ikke effektivt for brugere, der foretrækker at søge efter efternavn. Du kan teste det.
Alene af den grund er indeksering af fornavne og efternavne normalt mere effektivt, hvis der er to separate indekser, et for fornavnet og et for efternavnet.
Hvad betyder chasing-id-numre mener?
Det uudtalte designmønster, der ligger til grund for dette spørgsmål, er "Hver række skal have et id-nummer, og alle fremmednøgler skal referere til id-nummeret." I en SQL-database er det faktisk et anti-mønster. Som en tommelfingerregel bør ethvert mønster, der giver dig mulighed for at designe borde uden at tænke på nøgler, formodes skyldig, indtil det er bevist, at det er uskyldigt - det bør antages at være et anti-mønster, indtil det er bevist ikke at være det.
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)
);
Hvis du har brug for en rapport på tabel "D", og rapporten skal bruge
- kolonne D.d_1 og D.d_2, og
- kolonne A.a_1 og A.a_2,
du skal bruge 3 joins for at komme til det. (Prøv det.) Du jagter id-numre. (Som at jage pointere i IMS.) Følgende struktur er anderledes.
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)
);
Med denne struktur skal den samme rapport have en enkelt joinforbindelse.
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;