Використовувати електронну адресу як основний ключ?


234

Чи є адреса електронної пошти поганим кандидатом для первинних у порівнянні з автоматичним збільшенням номерів?

Нашій веб-програмі потрібна адреса електронної пошти, щоб вона була унікальною в системі. Отже, я подумав використовувати електронну адресу в якості основного ключа. Однак мій колега припускає, що порівняння рядків буде повільніше, ніж порівняння з цілими числами.

Чи поважна причина не використовувати електронну пошту в якості основного ключа?

Ми використовуємо PostgreSQL.


5
Що ви маєте на увазі під первинним? Якщо адреса електронної пошти повинна бути унікальною, то вона є ключовою і вимагає унікального обмеження. Незалежно від того, чи вирішите ви "сприяти", це бути "первинним" є довільним, якщо тільки для цього немає практичних причин, наприклад оптимізація недостатньо ефективної системи.
день, коли

7
Якщо ви хочете, щоб ваша база даних застосувала унікальну адресу електронної пошти, тоді створіть стовпчик з унікальним індексом, але не використовуйте його як основний ключ.
Джеймс Вестгейт

104
@robert Що робити, якщо хтось хоче змінити свою електронну адресу? Чи збираєтесь ви також змінити всі зовнішні ключі?
systempuntoout

3
@onedaywhen - навряд чи будь-яка різниця, але основний ключ буде кластеризований за замовчуванням, тоді як унікальний індекс не буде. Ви все одно хочете визначити первинний ключ, який буде ключем для пошуку одного запису за замовчуванням, унікальний індекс просто нав'язує унікальність стовпця над звичайним індексом
Джеймс Вестгейт,

3
@James Westgate: FYI, у PostgreSQL немає такого поняття, як автоматична кластеризація. PRIMARY KEY реалізований на диску точно так само, як UNIQUE INDEX, де всі поля НЕ НУЛЬНІ.
Меттью Вуд

Відповіді:


283

Порівняння рядків повільніше, ніж порівняння int. Однак це не має значення, якщо ви просто отримаєте користувача з бази даних за допомогою адреси електронної пошти. Не має значення, якщо у вас є складні запити з кількома приєднаннями.

Якщо ви зберігаєте інформацію про користувачів у кількох таблицях, іноземними ключами до таблиці користувачів буде адреса електронної пошти. Це означає, що ви зберігаєте електронну адресу кілька разів.


11
@Sjoerd: Проблема полягає не в тому, що адреса електронної пошти зберігається кілька разів, хоча це, безумовно, неефективно, але хто дбає про місце на жорсткому диску сьогодні. Більшість підприємств не мають google-масштабу, де це має значення. Проблема полягає в тому, що адресу електронної пошти після цього не можна змінювати, оскільки вона є первинним ключем і посилається на зовнішній ключ.
Стефан Штайгер

@StefanSteiger Хто сказав щось про місце на жорсткому диску? Все, що ви зберігаєте, займе місце в оперативній пам’яті.
Джонатан Аллен

У випадку, якщо хтось задається питанням, як я це робив, ключ GUID був би еквівалентний ключу електронної пошти, я думаю.
tofutim

178

Я також зазначу, що електронна пошта - це поганий вибір для створення унікального поля, є люди і навіть малий бізнес, які діляться адресою електронної пошти. Як і телефонні номери, електронні листи можна повторно використовувати. Jsmith@somecompany.com може легко належати Джону Сміту через рік і Джулії Сміт через два роки.

Ще одна проблема електронних листів полягає в тому, що вони часто змінюються. Якщо ви приєднуєтесь до інших таблиць, використовуючи це як ключ, тоді вам доведеться також оновити й інші таблиці, що може бути цілком сприятливим для продуктивності, коли ціла компанія-клієнт змінює свої електронні листи (що я бачив.)


47
+1 для згадування проблеми каскадного оновлення. Ось чому друзі дозволяють друзям використовувати лише сурогатні ключі ;-).
sleske

10
ах, мені зовсім не подобається приказка ... сурогатні ключі також можуть бути джерелом проблем; так, додаток буде більш надійним у зміні правил бізнесу та / або цілісності, однак інформація може загубитися трохи простіше, а особистість записів стає менш зрозумілою. тож я б не рекомендував тут великого правила ...
Нерозумно

12
@onedaywhen і @jay, тільки тому, що ти думаєш, що це повинно бути унікальним, це не робить його унікальним. І так, чоловік і дружина можуть бути різними клієнтами. Тільки тому, що ви раніше не стикалися з цим, не означає, що це не відбудеться. Я зіткнувся з цим, і це трапляється, тому електронну пошту ніколи не можна вважати унікальною, чи вважаєте ви це чи ні. Це така вимога, яку ви відштовхуєте, тому що вона сама по собі неправильна.
HLGEM

15
@HLGEM: Я не хочу вникати в нескінченний аргумент, але ви не можете сказати, що запропонований ключ не є унікальним на основі гіпотетики, не знаючи контексту. наприклад, з точки зору телефонної компанії, номер телефону однозначно ідентифікує клієнта за визначенням. Так, ви можете сказати: "Але що робити, якщо є два або три людини, які можуть відповісти, коли ви телефонуєте на цей номер?" Але це не має значення. З точки зору телефонної компанії, за визначенням це один замовник. (продовження ...)
Джей

14
(продовження) Так само, якщо ви будуєте систему, яка в значній мірі стосується електронної пошти - можливо, система диспетчеризації повідомлень чи система переадресації повідомлень - то, ймовірно, за визначенням адреса електронної пошти однозначно ідентифікує користувача. Якщо кілька людей діляться цією електронною адресою, це не має значення. Вони є єдиним призначенням повідомлення, тому вони є одним користувачем. "Користувач" і "замовник" не повинні бути синонімами "індивідуальної людини".
Джей

99

первинний ключ повинен бути унікальним і постійним

Адреси електронної пошти змінюються, як пори року. Корисний як вторинний ключ для пошуку, але поганий вибір для первинного ключа.


17
Властивість хорошого ключа полягає в тому, що він повинен бути стабільним, але НЕ обов'язково незмінним.
день, коли

5
@onedaywhen: Так! Інакше чому SQL підтримує каскадні оновлення?
Білл Карвін

18
якщо у вас є вибір, перейдіть до постійних / незмінних ключів; менше роботи для вас в дорозі; тільки те, що SQL підтримує каскадні оновлення, не означає, що це завжди гарна ідея!
Стівен А. Лоу

7
@Vincent Malgrat: "каскадні оновлення ... нормалізація гальмує" - міркування ви неправильно зрозуміли поняття нормалізації!
день, коли

5
@ Вінсент Малграт: дякую за підтвердження того, що ви дійсно неправильно зрозуміли концепцію нормалізації. "у вас не повинно повторюватися однакова інформація в декількох рядках" - ви справді мали намір сказати "інформацію" ?! Складний ключ, як правило, включає значення, повторювані в декількох рядках. Для іноземного ключа значення мають посилання, а не "повторювані", велика різниця. Один стовпецький домен з двома значеннями (наприклад, "Так" і "Ні") матиме однакові значення для кількох рядків у таблиці посилань, якщо він має три або більше рядків. Це дійсно базові речі!
onedaywhen

64

Недоліки використання електронної адреси в якості основного ключа:

  1. Повільніше, коли ви приєднуєтесь.

  2. Будь-яка інша запис із розміщеним іноземним ключем тепер має більше значення, займаючи більше місця на диску. (Враховуючи вартість дискового простору сьогодні, це, мабуть, тривіальна проблема, за винятком того, наскільки зараз запису потрібно більше часу для читання. Див. №1.)

  3. Електронна адреса може змінитися, що змушує оновлювати всі записи, що використовують це як зовнішній ключ. Оскільки адреса електронної пошти не змінюється все так часто, проблема ефективності, ймовірно, незначна. Більша проблема полягає в тому, що ви повинні переконатися в цьому. Якщо вам доведеться написати код, це більше роботи і вводить можливість помилок. Якщо двигун бази даних підтримує "на каскаді оновлень", це незначна проблема.

Переваги використання електронної адреси в якості основного ключа:

  1. Можливо, ви зможете повністю усунути деякі приєднання. Якщо все, що вам потрібно з "основного запису", - це адреса електронної пошти, то з абстрактним цілим ключем вам доведеться зробити об'єднання, щоб отримати його. Якщо ключем є адреса електронної пошти, то ви її вже маєте, і приєднання є непотрібним. Чи допоможе вам це чимось, залежить від того, як часто виникає така ситуація.

  2. Коли ви робите спеціальні запити, людині легко зрозуміти, на який основний запис йдеться. Це може бути великою підмогою при спробі виявити проблеми з даними.

  3. Ви майже напевно вам знадобиться індекс на адресу електронної пошти, так що, роблячи його основним ключем, виключає один індекс, тим самим покращуючи продуктивність вставок, оскільки тепер у них є лише один індекс для оновлення замість двох.

На мою скромну думку, це не так, як у суєтах. Я, як правило, вважаю за краще використовувати природні ключі, коли є доступний практичний, тому що з ними просто простіше працювати, а недоліки, як правило, не мають великого значення в більшості випадків.


@Conrad: Хоча, він все ж зазначає, що це не PITA, якщо у вас є двигун, який підтримує ПОНОВНУ КАСКАДУ. У цьому моменті це не проблема; Єдине справжнє питання - наскільки обширним є оновлення та наскільки широким є ключове. Адреса електронної пошти може бути небагато, але ОНОВЛЕННЯ КАСКАДУ для ПК 2-символьного коду країни не є великою справою.
Меттью Вуд

5
@Matthew IMHO все ще є PITA. Наприклад, припустимо, що коли ви розробляли таблицю своєї країни, було лише дві таблиці, на які вона посилалась, не великі, але з часом вона стала 20 таблиць, кожна із яких складала сотні тисяч записів. Деякі з посиланням, деякі без. Це змушує одного логічного запису закінчуватися десятками тисяч записів, і це не робить це для всіх таблиць, оскільки хтось забув посилання, коли додав таблицю. Це саме те, що трапилося зі мною за 2-х табличним кодовим кодом країни, я не тебе.
Конрад Фрікс

@Wood & Conrad: Найгірший випадок, коли немає вбудованої підтримки БД. Тоді ви повинні написати код для кожної таблиці з розміщеною посиланням, і це просто біль і двері для помилок, котрі просунуться. За допомогою каскадів вам просто потрібно пам’ятати, щоб додати по одній фразі на кожну таблицю, не таку велика справа.
Джей

2
Перевага 1 і 3 - це передчасна оптимізація, перевага 2 - дуже незначна перевага і повністю долається будь-яким гідним інструментом запитів.
Ясен

4
@Ash: різниця між "оптимізатином" та "передчасною оптимізацією". Але добре, тими ж міркуваннями всі недоліки, про які я бачив когось, - це передчасні оптимізації. То де це тебе залишає? Щодо №2, я вважаю, що введення додаткових приєднань, коли намагаються робити спеціальні запити, є великим болем. Записи часто мають кілька іноземних ключів, тому вам може знадобитися кілька приєднань, щоб отримати зрозумілі дані. Якщо під "гідним інструментом запиту" ви маєте на увазі той, який визначає, які дані ви хочете бачити, не повідомляючи про це, і магічно приєднується до вас, я хотів би побачити, як це працює.
Джей

12

Це досить погано. Припустимо, якийсь постачальник електронної пошти не працює. Потім користувачі захочуть змінити свою електронну пошту. Якщо ви використовували електронну пошту в якості основного ключа, всі закордонні ключі для користувачів дублюватимуть цю електронну пошту, зробивши її досить проклято важко змінити ...

... і я навіть не говорив про міркування щодо продуктивності.


Яким чином зміна електронних адрес може призвести до дублікатів? Якщо користувач A не змінить свою адресу електронної пошти, а потім користувач B змінить свою електронну пошту таким же, як і колишнє значення користувача A, і ваші оновлення не здійснюються послідовно. Можливо віддалено, я думаю.
Джей

2
Посилання на іноземний ключ за визначенням містить значення первинного ключа рядка, на який він посилається. Інакше кажучи, він дублює значення первинного ключа. (Отже, дублювання не спричинене зміною значення. Але зміна складніше через це дублювання та обмеження його примусового виконання).
Мерітон

5
+1 для рядка "Припустимо, якийсь постачальник електронної пошти не працює".
Редді

Це не проблема. Для вирішення цього питання існує каскадування іноземних ключів. Якщо користувач змінить свою електронну пошту, ця зміна стане каскадом до всіх таблиць, використовуючи її як зовнішній ключ.
Рафа

1
@rafa, я запевняю вас, що якщо ви використовуєте каскадні оновлення, і цілий провайдер припиняє свою діяльність або змінює своє ім'я (Yahoo.com стає HooYa.com), ваша база даних буде заблокована для всіх користувачів на години, а може й на дні, поки це каскадує через систему. Це дуже вагома проблема (і причина, чому погана ідея використовувати каскадні оновлення, якщо у вас є значна кількість даних, і ключ, ймовірно, зміниться.)
HLGEM,

12

Я не знаю, чи це може бути проблемою у вашій наладці, але залежно від RDBMS значення стовпців можуть залежати від регістру . Документи PostgreSQL кажуть: „Якщо ви оголошуєте стовпець як УНІКАЛЬНИЙ або ПЕРВИЧНИЙ КЛЮЧ, то імпліцитно генерований індекс відрізняється від регістру“. Іншими словами, якщо ви приймаєте введення користувача для пошуку в таблиці з електронною поштою в якості основного ключа, а користувач надає "John@Doe.com", ви не знайдете "john@doe.com".


7
Варто згадати у зв'язку з цим, що John@Doe.com та john@Doe.com можуть бути однаковими поштовими скриньками або можуть бути різними поштовими скриньками, і у вас немає способу сказати - у специфікації немає нічого, що б сказало, чи місцева частина є справжньою, чутливий.
телент

Це скоріше загальна проблема, пов’язана з унікальністю виконання електронних адрес, а не тим, чи слід використовувати їх як первинні ключі - та сама проблема є і в будь-якому випадку. +1, оскільки це все ще дуже корисний момент

11

Здається, ніхто не згадував про можливу проблему, що адреси електронної пошти можна вважати приватними. Якщо адреса електронної пошти є основним ключем, URL-адреса сторінки профілю, швидше за все, буде виглядати приблизно так ..../Users/my@email.com. Що робити, якщо ви не хочете виставляти електронну адресу користувача? Вам потрібно буде знайти інший спосіб ідентифікації користувача, можливо, за допомогою унікального цілого значення, щоб зробити подібні URL-адреси ..../Users/1. Тоді ви зрештою отримаєте унікальне ціле значення.


9

На логічному рівні електронний лист - це природний ключ. На фізичному рівні, якщо ви використовуєте реляційну базу даних, природний ключ не добре підходить як первинний ключ. Причиною є, головним чином, питання ефективності, згадані іншими.

З цієї причини дизайн може бути адаптований. Природний ключ стає альтернативним ключем (УНІКАЛЬНИЙ, НЕ НУЛЬНИЙ), і ви використовуєте сурогатний / штучний / технічний ключ як основний ключ, який може бути автоматичним збільшенням у вашому випадку.

запитав systempuntoout,

Що робити, якщо хтось хоче змінити свою електронну адресу? Чи збираєтесь ви також змінити всі зовнішні ключі?

Ось для чого це каскад .

Ще одна причина використання числового сурогатного ключа в якості основного ключа пов'язана з тим, як працює індексація на вашій платформі. Наприклад, у InnoDB MySQL, наприклад, у всіх індексах таблиці є попередній ключ до них, тому ви хочете, щоб ПК був якомога меншим (для скорочення та розміру). Також пов'язано з цим, InnoDB швидше, коли первинний ключ зберігається в послідовності, і рядок не допоможе там.

Інша річ, яку слід врахувати, використовуючи рядок як альтернативний ключ, - це те, що використання хешу фактичної рядки, яку ви хочете, може бути швидше, пропускаючи такі речі, як верхні та нижні регістри деяких літер. (Я фактично приземлився тут, шукаючи посилання, щоб підтвердити сказане щойно; все ще шукаю ...)


5

Так, це поганий первинний ключ, оскільки ваші користувачі захочуть оновити свої адреси електронної пошти.


1
Думав, я зазначу, що зараз у нас є каскад, це не проблема
зловмисник

4

так, краще, якщо ви замість цього використовуєте ціле число. ви також можете встановити свій стовпець електронної пошти як унікальне обмеження.

подобається це:

CREATE TABLE myTable(
    id integer primary key,
    email text UNIQUE
);

8
Чому це "краще"? Будь-які причини чи джерела?
Sjoerd

20
Чи можете ви детальніше розглянути це?
Sjoerd

3

Ще одна причина, чому цілий первинний ключ кращий - це посилання на адресу електронної пошти в іншій таблиці. Якщо адреса сама по собі є первинним ключем, то в іншій таблиці ви повинні використовувати її як ключ. Таким чином ви зберігаєте електронні адреси кілька разів.


3

Я не надто знайомий з постгресами. Первинні ключі - велика тема. Я бачив кілька чудових питань та відповідей на цьому сайті (stackoverflow.com).

Я думаю, що ви можете мати кращі показники роботи, маючи числовий первинний ключ та використовувати УНІКАЛЬНИЙ ІНДЕКС у стовпці електронної пошти. Електронні листи, як правило, різняться за довжиною і можуть не відповідати індексу первинного ключа.

дещо читаючи тут і тут.


3

Особисто я не використовую будь-яку інформацію для первинного ключа під час проектування бази даних, тому що дуже ймовірно, що мені може знадобитися змінити будь-яку інформацію пізніше. Єдиною причиною того, що я надаю первинний ключ, є зручність виконання більшості операцій SQL з боку клієнта, і мій вибір для цього завжди був цілочисельним типом автоматичного збільшення.


2

Ваш колега правий: використовуйте цілісне число для автоматичного збільшення для основного ключа.

Ви можете реалізувати унікальність електронної пошти або на рівні програми, або ви можете позначити стовпець своєї адреси електронної пошти як унікальний та додати індекс у цьому стовпці.

Додавання поля як унікального коштуватиме порівняння рядків лише при вставці в цю таблицю, а не при виконанні перевірок обмежень приєднання та зовнішніх ключів.

Звичайно, ви повинні зауважити, що додавання будь-яких обмежень до вашої програми на рівні бази даних може призвести до того, що ваш додаток стане негнучким. Завжди приділяйте належну увагу, перш ніж зробити будь-яке поле "унікальним" або "недійсним" лише тому, що вашій програмі потрібно, щоб воно було унікальним або непорожнім.


1
"Завжди приділяйте належну увагу, перш ніж впроваджувати вимогу x лише тому, що ваша програма потребує вимоги x." - найгірша порада, яку я прочитав за досить довгий час.
день, коли

Я не переконаний у вашому «аргументі» - в реальному житті часто трапляються ситуації, коли деякі важливі дані (наприклад, номер телефону) будуть одразу недоступними. Якщо таке поле в базі даних позначено як NOT NULL, воно вимагатиме від користувачів забруднення даних фіктивними полями (наприклад, 123), а не залишати їх порожніми. Більш практичним було б дозволити програмі обробляти обмеження (і в цьому випадку додаток може позначити порожнє поле як пункт дії).
jrharshath

5
Я погоджуюся, що визначати поле "недійсне" слід робити обережно. Вимоги на кшталт "нам завжди потрібен номер телефону замовника" слід враховувати. Можливо, не бажано часом створювати запис клієнта, навіть якщо ми не знаємо номер телефону зараз, і повернутися назад і отримати його пізніше? Але "це поле має бути унікальним" - це інша категорія. Я не можу собі уявити, щоб сказати: "Добре, щоб два працівники мали однаковий номер соціального страхування. Ми це зрозуміємо пізніше". Як би ви коли-небудь випрямили дані?
Джей

1
Будь Вовки: Я колись знав жінку, яка не мала власного телефону. Що ти робиш тоді?
Девід Торнлі

@DavidThornley Здається, що вам слід допрацювати більше, або, можливо, адаптувати дружнішу поведінку.
Філіп Шифф

2

Використовуйте GUID як первинний ключ ... таким чином ви можете генерувати його зі своєї програми, коли ви робите INSERT, і вам не потрібно отримувати відповідь від сервера, щоб дізнатися, що таке первинний ключ. Це також буде унікальним для всіх таблиць і баз даних, і вам не доведеться турбуватися про те, що станеться, якщо ви обріжете таблицю одного дня, і автоматичне збільшення збільшиться до 1.


2
Якщо ви майже нічого не піклуєтеся про продуктивність, тоді використовуйте GUID. Це ні-ні №1, якщо ви будуєте систему, яку потрібно масштабувати
Міхей,


3
Сказано справжнім способом пиття Microsoft-Kool-Aid!
Гері Чемберс

2

Я знаю, що це трохи пізній запис, але я хотів би додати, що люди відмовляються від облікових записів електронної пошти, а постачальники послуг відновлюють адресу, що дозволяє іншій людині використовувати її.

Як зазначає @HLGEM, "Jsmith@somecompany.com може легко належати Джону Сміту через рік і Джулії Сміт через два роки". у такому випадку, якщо Джон Сміт захоче вашої послуги, ви або повинні відмовитися від використання його електронної адреси або видалити всі ваші записи, що стосуються Джулії Сміт.

Якщо вам доведеться видалити записи, і вони стосуються фінансової історії бізнесу, залежно від місцевого законодавства, ви можете опинитися в гарячій воді.

Тому я ніколи не використовуватимуть такі дані, як адреси електронної пошти, номерні знаки тощо, як основні ключі, оскільки якими б унікальними вони не здавались, вони поза вашим контролем і можуть дати цікаві проблеми, з якими ви, можливо, не встигнете зіткнутися.


2

Можливо, вам доведеться розглянути будь-яке застосовне законодавство щодо регулювання даних. Електронна пошта - це особиста інформація, і якщо ваші користувачі є громадянами ЄС, наприклад, відповідно до GDPR, вони можуть доручити вам видалити їх інформацію зі своїх записів (пам'ятайте, що це стосується незалежно від того, в якій країні ви перебуваєте).

Якщо вам потрібно зберегти саму запис у базі даних для референтної цілісності або історичних причин, таких як аудит, використання сурогатного ключа дозволить вам просто НУЛЮВАТИ все поле персональних даних. Це очевидно не так просто, якщо їх особисті дані є основним ключем


1

ви можете підвищити продуктивність, використовуючи цілий первинний ключ.


1

ви повинні використовувати цілий первинний ключ. якщо вам потрібен унікальний стовпець електронної пошти, чому б вам просто не встановити унікальний індекс для цього стовпця?


1

Якщо у вас є первинне значення non-int, то для великих даних вставки та завантаження будуть дуже повільними.


1
Ні, вставляти це буде повільніше , тому що вам потрібні два унікальні індекси: один на створеному первинному ключі та інший на електронну адресу.
a_horse_with_no_name

1

первинний ключ повинен вибирати статичний атрибут. Оскільки адреси електронної пошти не є статичними і їх можна ділитися декількома кандидатами, тому не дуже корисно використовувати їх як основний ключ. Більше того, адреси електронної пошти - це рядки зазвичай певної довжини, які можуть бути більшими за унікальний ідентифікатор, який ми хотіли б використати [len (email_address)> len (unique_id)], тому це потребує більше місця і навіть гірше, що вони зберігаються кілька разів як зовнішній ключ . А отже, це призведе до погіршення продуктивності.


0

Це залежить від столу. Якщо рядки таблиці містять адреси електронної пошти, то найкращий ідентифікатор - це електронна пошта. Якщо ні, то електронний лист не є хорошим ідентифікатором.


0

Якщо ви просто вимагаєте, щоб повідомлення електронної пошти було унікальним, ви можете просто створити унікальний індекс за допомогою цього стовпця.


0

Електронна пошта є хорошим унікальним кандидатом, але не для первинного ключа, якщо це первинний ключ, ви не зможете, наприклад, змінити адресу електронної пошти контакту. Я думаю, що ваші запити на приєднання теж будуть повільнішими.


0

не використовуйте електронну адресу в якості основного ключа, зберігайте електронну пошту як унікальну, але не використовуйте її як основний ключ, використовуйте ідентифікатор користувача або ім'я користувача як основний ключ

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.