Всяка велика история започва с криза на идентичността. Люк, великият майстор джедай, започва да не е сигурен - „Кой съм аз?“ - и как мога да бъда някой важен? Необходим е Йода, този със Силата, за да го научи как да използва силите си.
Днес, позволете ми да бъда вашият Йода.
Ще започнем с това как да изберем първичен ключ, да се борим с кризата на идентичността и след това да завършим с примерни кодове за създаване на първичен ключ в база данни.
Как да изберем първичен ключ
Може да си мислите, че Люк е единственият с криза на идентичността, но това не е вярно. При създаването на база данни всичко е в криза на идентичността. И точно затова имаме нужда от първични ключове:те решават кризата. Те ни казват как да намерим всички.
Представете си, че сте правителството и искате да идентифицирате всеки един от вашите граждани цифрово. И така, вие създавате тази база данни с всичко за тях:
First Name
Last Name
Passport Number
Избирате номера на паспорта като първичен ключ - самоличността за всеки. Мислите, че това е всичко, от което се нуждаете, тъй като в паспорта има адрес и всичко останало. Знаете, че номерата на паспортите са уникални, така че се чувствате добре и прилагайте тази система.
След това, няколко години по-късно, разбирате една грозна истина:цялата страна е изправена пред криза на идентичността.
Когато нечий паспорт изтича, той получава нов. Идентичността им се променя. Други системи продължават да използват старите номера на паспортите, така че вече сочат към хора-призраци.
Уникалността не е достатъчна. Стойността не трябва да се променя през целия живот на реда.
И тогава откривате, че има хора, които дори нямат паспорти. Не можете да ги въведете във вашата система, тъй като първичните ключове не могат да бъдат NULL
. Как можете да идентифицирате някого с NULL
ключ?
Всеки ред трябва да има идентификатор. NULL не са разрешени.
Следващата итерация означава намиране на идентификатор, който не се променя с течение на времето и който всеки има. В Индия това се оказва картата Adhaar. В САЩ социалноосигурителният номер.
Ако създавате база данни, направете ги вашите първични ключове.
Понякога нямате такъв ключ. Помислете за държава, която все още няма социалноосигурителен номер и те искат да създадат цифров запис на всеки гражданин. Те биха могли да създадат нов SSN или просто да използват силата на базите данни и да използват сурогатен ключ.
Сурогатният ключ няма еквивалент в реалния свят. Това е просто число в база данни. И така, имате тази таблица в новата държава:
userID
First Name
Last Name
Passport Number
Паспортните номера са уникални. Винаги, когато искате да получите идентификатора за потребител, можете да го получите чрез номера на паспорта.
UserID никога не се променя. Номерът на паспорта може да се променя - но той винаги е уникален, така че винаги получавате правилния потребител. UserID е сурогат за несъществуващ социалноосигурителен номер в тази държава.
Забавен факт:Номерът на паспорта тук също е ключ за кандидат. Можеше да е първичният ключ, ако никога не се променяше. Това е разграничение на бизнес логиката.
Основният извод е следният:Всеки път, когато избирате първичен ключ, помислете за криза на идентичността . Възможно ли е някой да промени идентификатора си в бъдеще? Можем ли да влезем в състояние с множество хора с един и същ идентификатор?
Използвам хората като пример, защото това прави идентичността по-ясна – знаем, че всеки човек трябва да има идентичност. Прехвърлете това мислене във вашите бази данни. Всичко има идентичност, точно затова имате нужда от първични ключове.
Забележка:Понякога е възможно и желателно да използвате няколко колони заедно като първичен ключ. Това е композитен ключ.
Сега нека опитаме да дефинираме първични ключове с реални примери за код. Тук трябва да направите две неща:първо, ще идентифицирате първичния ключ. След това ще научите синтаксиса за дефинирането му в база данни.
Пример от реалния свят
Да кажем, че стартирате стартиране на доставка, подобно на Flexport. Имате пакети, които трябва да стигнат от едно място на друго, и кораби, които ги транспортират. Освен това имате клиенти, които поръчват тези пакети.
Смятате, че ще ви трябва една таблица за клиентите, една за пакетите и една за транспортиране, показвайки кой пакет къде се намира в момента.
Помислете какви колони ще ви трябват и какъв трябва да бъде първичният ключ. Ако бяхте инженер във Flexport, това е действителен въпрос, който ще трябва да разберете. Нищо не е дадено, всичко се открива в реалния свят.
Като се има предвид тази информация, бих проектирал тези таблици така:
Customers: first_name, last_name, email, address (for deliveries to their location)
Packages: weight, content
Transportation: <package_primary_key>, Port, time
Липсват ни първичните ключове. Помислете за тях, преди да прочетете повече.
За пакета ще избера сурогат PackageID. Можех да се опитам да изброя всички атрибути на опаковката:тегло, обем, плътност, възраст. Те биха идентифицирали уникално пакета, но това е много трудно да се направи на практика. Хората не се интересуват от това, те просто се интересуват от това, че пакетът ще стигне от едно място на друго.
Така че има смисъл да създадете произволно число и да го използвате като идентификатор. Точно затова виждате, че FedEx, UPS и всяка служба за доставка използват баркодове и идентификационни номера. Това са сурогатни ключове, генерирани за проследяване на пакети.
За клиента ще избера сурогат Клиентски номер. Тук отново имах възможност да избера, да речем, социалноосигурителния номер на моите клиенти. Но клиентите не искат да споделят това с мен, само за да мога да им изпратя нещо. По този начин ние генерираме ключ вътрешно, не казваме на нашите клиенти за този ключ и продължаваме да ги наричаме CustomerNo. 345681.
Забавна история:Познавам няколко компании, в които разкриха този CustomerNo, и клиентите настояваха да получат номер 1. Беше доста забавно – инженерите всъщност трябваше да променят своя преден код на:if (cust == 345681) print(1);
За транспорт ще избера композит PackageID+Port+time. Това е малко по-интересно. Можех да създам сурогат и тук и ще работи също толкова добре.
Но тук се крие магията на индексирането. Първичните ключове получават индекс автоматично, което означава, че търсенето е много по-ефективно спрямо първичните ключове.
Когато търсите в тази база данни, повечето заявки ще бъдат от формата "къде е този пакет?". С други думи, като се има предвид този PackageID, кажете ми пристанището и времето, в което е в момента. Ще ми трябва допълнителен индекс върху PackageID, ако го нямам като част от моя първичен ключ.
Това добре ли звучи? Последна стъпка, нека дефинираме тези 3 таблици в SQL. Синтаксисът варира леко в зависимост от базата данни, която използвате.
Дефиниране на първични ключове в MySQL
CREATE TABLE customers
( customerID INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
last_name VARCHAR(30) NOT NULL,
first_name VARCHAR(25) NOT NULL,
email VARCHAR(50) NOT NULL,
address VARCHAR(300)
);
CREATE TABLE packages
( packageID INT(15) NOT NULL AUTO_INCREMENT,
weight DECIMAL (10, 2) NOT NULL,
content VARCHAR(50),
CONSTRAINT packages_pk PRIMARY KEY (packageID) # An alternative way to above,
# when you want to name the constraint as well.
);
CREATE TABLE transportation
( package INT(15) NOT NULL,
port INT(15) NOT NULL,
time DATE NOT NULL,
PRIMARY KEY (package, port, time),
FOREIGN KEY package
REFERENCES packages(packageID)
ON DELETE RESTRICT # It's good practice to define what should happen on deletion. In this case, I don't want things to get deleted.
);
Дефиниране на първични ключове в PostgreSQL
CREATE TABLE customers
( customerID SERIAL NOT NULL PRIMARY KEY, # In PostgreSQL SERIAL is same as AUTO_INCREMENT - it adds 1 to every new row.
last_name VARCHAR(30) NOT NULL,
first_name VARCHAR(25) NOT NULL,
address TEXT,
email VARCHAR(50) NOT NULL
);
CREATE TABLE packages
( packageID SERIAL NOT NULL,
weight NUMERIC NOT NULL,
content TEXT,
CONSTRAINT packages_pk PRIMARY KEY (packageID) # In PostgreSQL, this alternative way works too.
);
CREATE TABLE transportation
( package INTEGER NOT NULL,
port INT(15) NOT NULL,
time DATE NOT NULL,
PRIMARY KEY (package, port, time),
FOREIGN KEY package
REFERENCES packages(packageID)
ON DELETE RESTRICT # It's good practice to define what should happen on deletion. In this case, I don't want things to get deleted.
);
Не е много различно, нали? След като разберете основите, можете да го приложите към почти всяка база данни само с бърз поглед към документацията. Ключът е да знаете какво да търсите!
Успех, млад падаван.
Наслаждавахте се на това? Може също да харесате Неща, които научих от старши софтуерен инженер