Бих предпочел втория подход. Като използвате заместващи идентификационни номера, когато те не са логически необходими за идентификация, вие въвеждате повече задължителни присъединявания. Това изисква от вас да "преследвате идентификационни номера в цялата база данни", което е SQL еквивалент на "преследване на указатели в цялата база данни". Преследването на указатели беше характерно за IMS, една от архитектурите на базата данни, които релационният модел имаше за цел да замени. (IMS използва йерархична архитектура.) Няма смисъл да го преоткриваме днес. (Въпреки че много от хората правят точно това.)
Ако имате, например, пет нива на заместващи идентификационни номера и искате името на човек, трябва да направите четири обединявания, за да го получите. Използвайки втория подход, имате нужда само от едно присъединяване. Ако не искате да пишете свързвания с няколко колони, използвайте CREATE VIEW и го направете само веднъж.
Ефективността е лесна за тестване . Просто генерирайте няколко милиона произволни реда, използвайки любимия си скриптов език, и ги заредете в тестов сървър. Вие не само ще откриете къде се крият проблемите ви с производителността, ще намерите всички грешки във вашия код CREATE TABLE. (Вашият код няма да работи такъв, какъвто е.) Научете за ОБЯСНЯВАНЕ ако все още не знаете за това.
Колкото доиндексирането , можете да тествате това на произволните редове, които генерирате и зареждате. Индексът с няколко колони (first_name, last_name) ще работи най-добре, ако потребителите винаги предоставят собствено име. Но много потребители няма да направят това, предпочитайки да търсят по фамилно име. Индексът с няколко колони на (first_name, last_name) не е ефективен за потребители, които предпочитат да търсят по фамилно име. Можете да тествате това.
Само поради тази причина индексирането на собствени и фамилни имена е обикновено по-ефективен, ако има два отделни индекса, един за собственото име и един за фамилното име.
Какво означава преследването на идентификационни номера значи?
Неизказаният модел на дизайн, който стои в основата на този въпрос, е „Всеки ред трябва да има идентификационен номер и всички външни ключове трябва да се отнасят към идентификационния номер“. В SQL база данни това всъщност е анти-модел. Като правило, всеки модел, който ви позволява да проектирате таблици, без да мислите за ключове, трябва да се счита за виновен, докато не се докаже, че е невинен – трябва да се счита, че е антимодел, докато не се докаже, че не е така.
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)
);
Ако имате нужда от отчет за таблица "D", а отчетът се нуждае от
- колони D.d_1 и D.d_2 и
- колони A.a_1 и A.a_2,
имате нужда от 3 връзки, за да стигнете до него. (Опитайте.) Преследвате идентификационни номера. (Като преследване на указатели в IMS.) Следната структура е различна.
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)
);
С тази структура същият отчет се нуждае от едно присъединяване.
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;