Использовать адрес электронной почты в качестве первичного ключа?


234

Является ли адрес электронной почты плохим кандидатом на основной адрес по сравнению с автоматически увеличивающимися числами?

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

Это действительная причина не использовать электронную почту в качестве первичного ключа?

Мы используем PostgreSQL.


5
Что вы подразумеваете под «первичным»? Если адрес электронной почты должен быть уникальным, он является ключевым и требует уникального ограничения. Если вы решите «продвигать» его как «первичное», это произвольно, если только для этого нет практической причины, например, оптимизации плохо работающей системы.
понедельник,

7
Если вы хотите, чтобы в вашей базе данных использовался уникальный адрес электронной почты, создайте столбец с уникальным индексом, но не используйте его в качестве первичного ключа.
Джеймс Вестгейт

104
@robert Что если кто-то захочет изменить свой адрес электронной почты? Собираетесь ли вы также изменить все внешние ключи?
systempuntoout

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

3
@James Westgate: К вашему сведению, в PostgreSQL нет такой вещи, как автоматическая кластеризация. ПЕРВИЧНЫЙ КЛЮЧ реализован на диске точно так же, как и УНИКАЛЬНЫЙ ИНДЕКС, где все поля НЕ ПУСТО.
Мэтью Вуд

Ответы:


283

Сравнение строк медленнее, чем сравнение int. Однако это не имеет значения, если вы просто извлекаете пользователя из базы данных, используя адрес электронной почты. Имеет значение, если у вас есть сложные запросы с несколькими объединениями.

Если вы храните информацию о пользователях в нескольких таблицах, внешними ключами таблицы пользователей будет адрес электронной почты. Это означает, что вы сохраняете адрес электронной почты несколько раз.


11
@Sjoerd: Проблема не в том, что адрес электронной почты хранится несколько раз, хотя это определенно неэффективно, а в том, кому сегодня нужно место на жестком диске. Большинство компаний не имеют Google масштаба, где это будет иметь значение. Проблема в том, что адрес электронной почты не может быть изменен впоследствии, потому что это и первичный ключ, и ссылка на него как внешний ключ.
Стефан Штайгер

@StefanSteiger Кто сказал что-нибудь о пространстве на жестком диске? Все, что вы храните, будет занимать место в оперативной памяти.
Джонатан Аллен

В случае, если кому-то интересно, как я сделал, ключ GUID будет эквивалентен ключу электронной почты, я думаю.
Тофутим

178

Я также укажу, что электронная почта - плохой выбор для создания уникального поля, есть люди и даже малые предприятия, которые имеют адрес электронной почты. Как и номера телефонов, электронные письма могут быть использованы повторно.Jsmith@somecompany.com может легко принадлежать Джону Смиту один год и Джулии Смит два года спустя.

Другая проблема с электронными письмами заключается в том, что они часто меняются. Если вы присоединяетесь к другим таблицам с этим ключом, то вам придется обновить и другие таблицы, что может сильно ухудшить производительность, когда целая компания-клиент изменит свои электронные письма (что, как я видел, произошло).


47
+1 за упоминание о проблеме каскадного обновления. Вот почему друзья позволяют друзьям использовать только суррогатные ключи ;-).
Слёске

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

12
@onedaywhen и @jay, то, что вы думаете, что оно должно быть уникальным, не делает его уникальным. И да, муж и жена могут быть разными клиентами. Просто потому, что вы не сталкивались с этим раньше, не значит, что этого не произойдет. Я столкнулся с этим, и это случается, поэтому электронную почту никогда нельзя допускать, чтобы она считалась уникальной, независимо от того, считаете ли вы, что это так или нет. Это требование, которое вы выдвигаете, потому что оно по своей сути неверно.
HLGEM

15
@HLGEM: я не хочу вступать в бесконечный спор, но нельзя сказать, что предлагаемый ключ не является уникальным, основанным на гипотетических предположениях, без знания контекста. например, с точки зрения телефонной компании, телефонный номер однозначно идентифицирует клиента по определению. Да, вы можете сказать: «Но что, если есть два или три человека, которые могут ответить, когда вы позвоните по этому номеру?» Но это не имеет значения. С точки зрения телефонной компании, по определению, это один клиент. (продолжение ...)
Джей

14
(продолжение) Аналогичным образом, если вы создаете систему, которая в значительной степени связана с обменом сообщениями по электронной почте - возможно, системой рассылки сообщений или системой пересылки уведомлений - тогда вполне вероятно, что по определению адрес электронной почты однозначно идентифицирует пользователя. Если несколько человек используют один и тот же адрес электронной почты, это не имеет значения. Они являются одним пунктом назначения сообщений, поэтому они являются одним пользователем. «Пользователь» и «клиент» не обязательно должны быть синонимами слова «отдельный человек».
Джей

99

первичный ключ должен быть уникальным и постоянным

адреса электронной почты меняются в зависимости от сезона. Полезно в качестве вторичного ключа для поиска, но плохой выбор для первичного ключа.


17
Свойство хорошего ключа заключается в том, что оно должно быть стабильным, но НЕ обязательно неизменным.
понедельник,

5
@onedaywhen: Да! Иначе, почему SQL поддерживает каскадные обновления?
Билл Карвин

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

7
@ Vincent Malgrat: «каскадные обновления ... тормозит нормализацию базы данных» - мне кажется, вы неправильно поняли концепцию нормализации!
понедельник,

5
@ Винсент Малграт: спасибо за подтверждение, что вы действительно неправильно поняли концепцию нормализации. «вы не должны повторять одну и ту же информацию в нескольких строках» - вы действительно хотели сказать «информация» ?! Составной ключ обычно включает значения, повторяющиеся в нескольких строках. Для внешнего ключа значения ссылаются, а не «повторяются», большая разница. Домен из одного столбца с двумя значениями (например, «Да» и «Нет») будет иметь одинаковые значения для нескольких строк в ссылочной таблице, если в нем три или более строк. Это действительно простые вещи!
понедельник,

64

Недостатки использования адреса электронной почты в качестве первичного ключа:

  1. Медленнее, когда делает соединения.

  2. Любая другая запись с опубликованным внешним ключом теперь имеет большее значение и занимает больше места на диске. (Учитывая стоимость дискового пространства сегодня, это, вероятно, тривиальная проблема, за исключением того, что запись теперь занимает больше времени для чтения. См. № 1.)

  3. Адрес электронной почты может измениться, что приведет к обновлению всех записей, использующих его в качестве внешнего ключа. Поскольку адреса электронной почты меняются не так часто, проблема с производительностью, вероятно, незначительна. Большая проблема в том, что вы должны убедиться, что обеспечили это. Если вам нужно написать код, это больше работы и вводит возможность ошибок. Если ваша база данных поддерживает «каскад обновления», это незначительная проблема.

Преимущества использования адреса электронной почты в качестве первичного ключа:

  1. Вы можете быть в состоянии полностью устранить некоторые объединения. Если все, что вам нужно из «основной записи», это адрес электронной почты, то с абстрактным целочисленным ключом вам потребуется выполнить соединение, чтобы получить его. Если ключом является адрес электронной почты, значит, он у вас уже есть и присоединение не требуется. Поможет ли это вам, зависит от того, как часто возникает эта ситуация.

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

  3. В любом случае вам почти наверняка понадобится индекс по адресу электронной почты, поэтому, сделав его первичным ключом, вы исключите один индекс, что повысит производительность вставок, поскольку теперь у них есть только один индекс для обновления вместо двух.

По моему скромному мнению, это в любом случае не хлам. Я предпочитаю использовать естественные ключи, когда есть практические, потому что с ними просто работать, а недостатки в большинстве случаев не имеют большого значения.


@ Конрад: Хотя, он действительно указывает, что это не PITA, если у вас есть движок, который поддерживает ОБНОВЛЕНИЕ КАСКАДА. Это не проблема в этой точке кода; единственная реальная проблема заключается в том, насколько обширно обновление и насколько широка ключ. Адрес электронной почты может быть немного большим, но ОБНОВЛЕНИЕ CASCADE для PK с 2-символьным кодом страны не имеет большого значения.
Мэтью Вуд

5
@ Матфея ИМХО это все еще PITA. Например, предположим, что когда вы разрабатывали таблицу стран, на нее ссылались только две таблицы, ничего страшного, но со временем она превратилась в 20 таблиц с сотнями тысяч записей. Некоторые со ссылкой, некоторые без. Это приводит к тому, что одна логическая запись составляет десятки тысяч записей, и она не распространяется на все таблицы, потому что кто-то забыл ссылку при добавлении таблицы. Это именно то, что случилось со мной в таблице кодов стран с двумя символами, я не шучу.
Конрад Фрикс

@Wood & Conrad: худший случай, когда нет встроенной поддержки БД. Затем вы должны написать для него код для каждой таблицы с опубликованной ссылкой, и это просто боль и возможность ошибиться. С каскадами вам просто нужно не забыть добавить по одному предложению на каждую таблицу, а не такому. большое дело
Джей

2
Преимущество 1 и 3 - преждевременная оптимизация, преимущество 2 - очень незначительное преимущество, которое полностью преодолевается любым достойным инструментом запросов.
Эш

4
@Ash: Ты разница между "оптимизатином" и "преждевременной оптимизацией". Но, ладно, по той же причине все недостатки, о которых я упоминал, это преждевременная оптимизация. Так где же это тебя оставляет? Что касается # 2, я считаю, что ввод дополнительных объединений при попытке выполнить специальные запросы - это большая проблема. Записи часто имеют несколько внешних ключей, поэтому вам может потребоваться несколько объединений, чтобы получить понятные данные. Если под «достойным инструментом запроса» вы имеете в виду тот, который выясняет, какие данные вы хотите видеть без вашего ведома, и волшебным образом делает соединения для вас, я бы хотел посмотреть, как это работает.
Джей

12

Это довольно плохо. Предположим, какой-то провайдер электронной почты обанкротился. Затем пользователи захотят изменить свою электронную почту. Если вы использовали электронную почту в качестве первичного ключа, все внешние ключи для пользователей будут дублировать эту электронную почту, что затруднит их изменение ...

... и я даже не начал говорить о соображениях производительности.


Как изменение адресов электронной почты может привести к дублированию? Если только пользователь А не изменит свой адрес электронной почты, а затем пользователь Б не изменит свой адрес электронной почты так, чтобы он совпадал со старым значением пользователя А, и ваши обновления выполняются не по порядку. Я думаю, что это возможно удаленно.
Джей

2
Ссылка на внешний ключ по определению содержит значение первичного ключа строки, на которую она ссылается. Иными словами, он дублирует значение первичного ключа. (Таким образом, дублирование не вызвано изменением значения. Но изменение сложнее из-за этого дублирования и ограничения, обеспечивающего его).
меритон

5
+1 за строку «Предположим, какой-то провайдер электронной почты обанкротился».
Редди

Это не является проблемой. Для решения этой проблемы существует каскад внешних ключей. Если пользователь изменяет свою электронную почту, изменение будет каскадным для всех таблиц, использующих его в качестве внешнего ключа.
Рафа

1
@rafa, я вас уверяю, что если вы используете каскадные обновления и целый провайдер выходит из бизнеса или меняет свое имя (Yahoo.com становится HooYa.com), ваша база данных будет заблокирована для всех пользователей в течение нескольких часов, а может и дней, пока это происходит каскадно. через систему. Это очень актуальная проблема (и причина, по которой плохая идея использовать каскадные обновления, если у вас есть значительный объем данных и ключ может измениться.)
HLGEM

12

Я не знаю, может ли это быть проблемой в вашей установке, но в зависимости от вашей RDBMS значения столбцов могут быть чувствительными к регистру . Документы PostgreSQL говорят: «Если вы объявляете столбец как UNIQUE или PRIMARY KEY, неявно генерируемый индекс чувствителен к регистру». Другими словами, если вы принимаете пользовательский ввод для поиска в таблице с электронной почтой в качестве первичного ключа, и пользователь предоставляет «John@Doe.com», вы не найдете «john@doe.com».


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

Это более общая проблема с применением уникальности адресов электронной почты, а не необходимость их использования в качестве первичных ключей - такая же проблема существует в любом случае. +1, потому что это все еще очень полезный пункт

11

Кажется, никто не упомянул о возможной проблеме, заключающейся в том, что адреса электронной почты могут считаться частными. Если адрес электронной почты является первичным ключом, URL страницы профиля, скорее всего, будет выглядеть примерно так ..../Users/my@email.com. Что если вы не хотите показывать адрес электронной почты пользователя? Вам нужно найти какой-то другой способ идентификации пользователя, возможно, с помощью уникального целочисленного значения, чтобы сделать URL-адреса похожими ..../Users/1. Тогда вы получите уникальное целочисленное значение.


9

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

По этой причине дизайн может быть адаптирован. Естественный ключ становится альтернативным ключом (UNIQUE, NOT NULL), и вы используете суррогатный / искусственный / технический ключ в качестве первичного ключа, который может быть автоматическим приращением в вашем случае.

systemmpuntoout спросил,

Что если кто-то захочет изменить свой адрес электронной почты? Собираетесь ли вы также изменить все внешние ключи?

Вот что каскадно .

Еще одна причина использования числового суррогатного ключа в качестве первичного ключа связана с тем, как работает индексация на вашей платформе. Например, в MySQL InnoDB все индексы в таблице имеют первичный ключ, предварительно привязанный к ним, так что вы хотите, чтобы PK был как можно меньшим (для скорости и размера). Также с этим связано, что InnoDB быстрее, когда первичный ключ хранится в последовательности, и строка там не поможет.

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


5

Да, это плохой первичный ключ, потому что ваши пользователи захотят обновить свои адреса электронной почты.


1
Думаю, я бы указал, что теперь у нас есть каскад, это не проблема
Малхал

4

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

как это:

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

8
Почему это "лучше"? Какие-либо причины или источники?
Сьорд

20
Можете ли вы уточнить это?
Сьорд

3

Другая причина, по которой целочисленный первичный ключ лучше, - это когда вы ссылаетесь на адрес электронной почты в другой таблице. Если адрес сам по себе является первичным ключом, то в другой таблице вы должны использовать его в качестве ключа. Таким образом, вы храните адреса электронной почты несколько раз.


3

Я не слишком знаком с Postgres. Первичные ключи - это большая тема. Я видел несколько отличных вопросов и ответов на этом сайте (stackoverflow.com).

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

некоторые читают здесь и здесь.


3

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


2

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

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

Добавление поля как уникального обойдется вам в сравнение строк только при вставке в эту таблицу, а не при выполнении проверок объединений и ограничений внешнего ключа.

Конечно, вы должны отметить, что добавление любых ограничений в ваше приложение на уровне базы данных может привести к тому, что ваше приложение станет негибким. Всегда уделяйте должное внимание перед тем, как сделать любое поле «уникальным» или «не нулевым» только потому, что ваше приложение должно быть уникальным или непустым.


1
«Всегда внимательно относитесь к выполнению требования x только потому, что вашему приложению требуется требование x». - худший совет, который я прочитал за последнее время.
понедельник,

Меня не убеждает ваш «аргумент» - в реальной жизни часто бывают ситуации, когда некоторые важные данные (например, номер телефона) не будут доступны сразу. Если такое поле помечено как NOT NULL в базе данных, оно потребует от пользователей загрязнения данных фиктивными полями (например, 123) вместо того, чтобы оставлять их пустыми. Было бы более практично позволить приложению обрабатывать ограничения (и в этом случае приложение может пометить пустое поле как элемент действия).
Джаршат

5
Я согласен, что определение поля "не ноль" следует делать осторожно. Требования типа «нам всегда нужен номер телефона клиента» должны быть тщательно продуманы. Может быть, иногда нежелательно создавать запись о клиенте, даже если мы не знаем номер телефона прямо сейчас, а потом вернуться и получить его позже? Но «это поле должно быть уникальным» - это другая категория. Я не могу себе представить, что «два сотрудника могут иметь один и тот же номер социального страхования, мы выясним это позже». Как бы вы выправили данные?
Джей

1
Будь волком: однажды я знал женщину, у которой не было ее собственного номера телефона. Что вы делаете тогда?
Дэвид Торнли

@DavidThornley Похоже, вы должны больше работать, или, возможно, изменить дружеское поведение.
Филипп Шифф

2

Используйте GUID в качестве первичного ключа ... таким образом, вы можете сгенерировать его из своей программы, когда делаете INSERT, и вам не нужно получать ответ от сервера, чтобы узнать, что такое первичный ключ. Он также будет уникальным для таблиц и баз данных, и вам не нужно беспокоиться о том, что произойдет, если вы однажды урежете таблицу, и автоинкремент будет сброшен до 1.


2
Если вы не заботитесь о производительности, используйте GUID. Нет-нет № 1, если вы создаете систему, которая должна будет масштабироваться
Мика


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

2

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

Как отметил @HLGEM, «Jsmith@somecompany.com может легко принадлежать Джону Смиту через год и Джулии Смит два года спустя». в этом случае, если Джон Смит захочет воспользоваться вашим сервисом, вы должны либо отказаться от использования его адреса электронной почты, либо удалить все свои записи, относящиеся к Джулии Смит.

Если вам нужно удалить записи, которые связаны с финансовой историей бизнеса в зависимости от местного законодательства, вы можете оказаться в горячей воде.

Поэтому я бы никогда не использовал такие данные, как адреса электронной почты, номерные знаки и т. Д. В качестве первичных ключей, потому что, какими бы уникальными они ни казались, они находятся вне вашего контроля и могут предоставить некоторые интересные проблемы, с которыми у вас может не хватить времени для решения.


2

Возможно, вам придется рассмотреть любое применимое законодательство о регулировании данных. Электронная почта - это личная информация, и если ваши пользователи, например, являются гражданами ЕС, в рамках GDPR они могут поручить вам удалить их информацию из ваших записей (помните, что это применимо независимо от того, в какой стране вы находитесь).

Если вам необходимо сохранить саму запись в базе данных по ссылочной целостности или историческим причинам, таким как аудит, использование суррогатного ключа позволит вам просто ОБНОВИТЬ все поля личных данных. Это, очевидно, не так просто, если их личные данные являются первичным ключом


1

Вы можете повысить производительность, используя целочисленный первичный ключ.


1

Вы должны использовать целочисленный первичный ключ. если вам нужно, чтобы email-столбец был уникальным, почему бы вам просто не установить уникальный индекс для этого столбца?


1

Если в качестве первичного ключа вы используете не 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.