Ik zou de voorkeur geven aan de tweede benadering. Door surrogaat-ID-nummers te gebruiken wanneer ze niet logisch nodig zijn voor identificatie, introduceert u meer verplichte joins. Dit vereist dat u "ID-nummers door de hele database achtervolgt", wat het SQL-equivalent is van "aanwijzers overal in de database achtervolgen". Het achtervolgen van pointers was kenmerkend voor IMS, een van de database-architecturen die het relationele model moest vervangen. (IMS gebruikt een hiërarchische architectuur.) Het heeft geen zin om het vandaag opnieuw uit te vinden. (Hoewel een veel van de mensen doet precies dat.)
Als je bijvoorbeeld vijf niveaus van surrogaat-ID-nummers hebt en je wilt de naam van een persoon, dan moet je vier keer meedoen om het te krijgen. Als u de tweede benadering gebruikt, hebt u slechts één join nodig. Als je geen joins met meerdere kolommen wilt schrijven, gebruik dan CREATE VIEW en doe het maar één keer.
Prestaties zijn eenvoudig te testen . Genereer gewoon een paar miljoen willekeurige rijen met uw favoriete scripttaal en laad ze in een testserver. U zult niet alleen ontdekken waar uw prestatieproblemen zich verbergen, u vindt alle fouten in uw CREATE TABLE-code. (Je code werkt niet zoals hij is.) Meer informatie over UITLEG als je het nog niet weet.
Wat betreft indexeren , kunt u dat testen op de willekeurige rijen die u genereert en laadt. Een index met meerdere kolommen op (first_name, last_name) werkt het beste als gebruikers altijd een voornaam opgeven. Maar veel gebruikers zullen dat niet doen en zoeken liever op achternaam. Een index met meerdere kolommen op (voornaam, achternaam) is niet effectief voor gebruikers die liever op achternaam zoeken. Dat kun je testen.
Alleen al om die reden is het indexeren van voor- en achternaam meestal effectiever als er twee aparte indexen zijn, een voor de voornaam en een voor de achternaam.
Wat doet het najagen van ID-nummers bedoel?
Het onuitgesproken ontwerppatroon dat aan deze vraag ten grondslag ligt, is "Elke rij moet een id-nummer hebben en alle buitenlandse sleutels moeten naar het id-nummer verwijzen." In een SQL-database is het eigenlijk een antipatroon. Als vuistregel geldt dat elk patroon waarmee u tabellen kunt ontwerpen zonder na te denken over sleutels, als schuldig moet worden beschouwd totdat het tegendeel is bewezen - het moet worden verondersteld een antipatroon te zijn totdat is bewezen dat het niet zo is.
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)
);
Als u een rapport over tabel "D" nodig hebt, en het rapport heeft
- kolommen D.d_1 en D.d_2 en
- kolommen A.a_1 en A.a_2,
je hebt 3 joins nodig om er te komen. (Probeer het.) Je jaagt op ID-nummers. (Zoals het najagen van pointers in IMS.) De volgende structuur is anders.
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)
);
Met deze structuur heeft hetzelfde rapport een enkele join nodig.
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;