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

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

вот пример таблицы, которую я создал:

CREATE TABLE users
(
  uid INT NOT NULL AUTO_INCREMENT,
  username VARCHAR(60),
  passhash VARCHAR(255),
  email VARCHAR(60),
  rdate DATE,
  PRIMARY KEY(uid)
);

профессор сказал мне, что" uid " (идентификатор пользователя) был совершенно бесполезным и ненужным, и я должен был использовать имя пользователя в качестве первичного ключа, так как никакие два пользователя не могут иметь одно и то же имя пользователя.

Я сказал ему, что мне удобно использовать идентификатор пользователя, потому что, когда я вызываю что-то вроде domain.com/viewuser?id=5 я просто проверяю параметр с помощью:is_numeric($_GET['id'])... излишне говорить, что его это не убедило.

Так как я видел user_id и другие подобные атрибуты (thread_id, comment_id, среди других) на множестве учебных пособий и глядя на схему базы данных популярного программного обеспечения (например. vbulletin) должно быть много других (более сильных) причин.

Итак, мой вопрос: как бы вы оправдали необходимость не нулевого автоматического увеличения id в качестве первичного ключа против использования другого атрибут, как имя пользователя?

12 ответов


автоматическое увеличение первичных ключей полезно по нескольким причинам:

  • они позволяют дублировать имена пользователей, как при переполнении стека
  • они позволяют изменить имя пользователя (или адрес электронной почты, если это используется для входа в систему) (легко)
  • выбирает, присоединяется и вставляет быстрее, чем первичные ключи varchar, так как его гораздо быстрее поддерживать числовой индекс
  • как вы упомянули, проверка становится очень простой:if ((int)$id > 0) { ... }
  • уборка входных тривиально: $id = (int)$_GET['id']
  • существует гораздо меньше накладных расходов, поскольку внешние ключи не должны дублировать потенциально большие строковые значения

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

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

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


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


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

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

искреннее спасибо за публикацию SQL DDL, это очень полезно, но большинство не надоело так.

используя вашу таблицу, я могу сделать это:

INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);
INSERT INTO users (username) VALUES (NULL);

что приводит к этому:

SELECT uid, username, passhash, email, rdate 
FROM users;

uid   username   passhash   email   rdate
1     <NULL>     <NULL>     <NULL>  <NULL>
2     <NULL>     <NULL>     <NULL>  <NULL>
3     <NULL>     <NULL>     <NULL>  <NULL>
4     <NULL>     <NULL>     <NULL>  <NULL>

Я думаю, что ваш профессор пытался сделать: не применяя естественный ключ на username у вас на самом деле нет целостности данных вообще.

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


Это обычно называется суррогатный ключ и оно имеет много преимуществ. Одним из которых является изоляция отношений базы данных от данных приложения. Более подробную информацию и соответствующие недостатки можно найти по ссылке на вики указано выше.


потому что кто-то может захотеть изменить свое имя пользователя (или любое имя, если на то пошло).


ваш профессор делает правильную вещь, указывая, что вы должны были сделать имя пользователя уникальным, а не аннулируемым, если это было требование, чтобы имена пользователей были уникальными. Uid также может быть ключом, но если вы действительно не используете его где-то, тогда он не нужен. Более важным аспектом дизайна должно быть внедрение естественного ключа. Поэтому я согласен с замечанием вашего профессора.


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

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

давайте посмотрим правде в глаза, большинство проектов не будут расширяться это много, но вы действительно хотите рисковать головная боль 12 месяцев по дороге, когда вы могли бы соответствовать хорошим стандартам программирования сейчас?


например, целочисленный поиск (?id=5) намного быстрее и имеет более высокую мощность, чем поиск строк (?username=bob). Другим примером uid является auto_increment, поэтому вам не нужно вставлять его явно, но он будет автоматически увеличиваться в каждом запросе вставки.

PS: ваш проф soooo неправильно об этом :D


мы используем ID для предотвращения дублирования данных, и это может сделать некоторые procces не сложным (если мы хотим обновить или удалить данные), это более просто, если мы используем ID.

Если вы не хотите использовать ID, вы можете использовать другие поля. но не забудьте сделать их уникальными. это может сделать ваши данные становятся превентивными от дублирования данных.

другой способ вне PRIMARY уникален.


Я иду со всеми ответами выше. Я бы сказал, что ID легко реализовать, и когда дело доходит до индексирования, Int всегда предпочтительнее по сравнению с varchar. Ваш профессор должен знать лучше, почему он сказал " Нет " Int id выше меня!


потому что userid должен быть уникальным (не может быть дублирован) и иногда является индексом.


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