为什么在存在其他唯一字段时使用自动递增主键?

时间:2010-11-05 03:42:58

标签: sql database database-design data-modeling

我正在修读一门名为“数据库系统”的课程,对于我们的课程项目,我必须设计一个网站。

以下是我创建的表的示例:

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

教授告诉我“uid”(用户ID)完全无用且不必要,我应该使用用户名作为主键,因为没有两个用户可以拥有相同的用户名。

我告诉他我使用用户ID很方便,因为当我调用domain.com/viewuser?id=5之类的东西时,我只需检查参数:is_numeric($_GET['id']) ...不用说他是不相信。

由于我在大量教程中看到了user_id和其他类似的属性(thread_id,comment_id等),并且查看了流行软件的数据库模式(例如vbulletin),因此必须有很多其他(更强大的)原因。

所以我的问题是:你如何证明需要一个非空的自动递增id作为主键vs使用另一个属性如用户名?

12 个答案:

答案 0 :(得分:81)

自动递增主键有几个原因:

  • 它们允许重复的用户名,如Stack Overflow
  • 他们允许更改(轻松)用户名(或电子邮件地址,如果用于登录)
  • 选择,连接和插入比varchar主键更快,因为它维护数字索引要快得多
  • 如您所述,验证变得非常简单:if ((int)$id > 0) { ... }
  • 输入的卫生是微不足道的:$id = (int)$_GET['id']
  • 由于外键不必复制可能较大的字符串值,因此开销要小得多。

我想说当一个自动递增的数字键很容易获得时,尝试使用任何一个字符串信息作为记录的唯一标识符是一个坏主意。

具有唯一用户名的系统适用于极少数用户,但互联网已经彻底破坏了它们。当您考虑可能需要与网站进行交互的名为“john”的人数时,要求每个人使用唯一的显示名称是荒谬的。它导致我们经常看到的可怕系统,随机数字和字母装饰用户名。

但是,即使在您强制使用唯一用户名的系统中,它仍然是主键的不良选择。想象一下有500个帖子的用户:posts表中的外键将包含用户名,重复500次。即使在您考虑有人可能最终需要更改其用户名之前,开销也是令人望而却步的。

答案 1 :(得分:15)

如果用户名是主键并且用户更改了他/她的用户名,则需要更新所有对users表具有外键引用的表。

答案 2 :(得分:10)

如果您已向您的教授证明,为每个用户分配一个唯一的任意整数对您的应用程序有价值,那么当然他说“完全无用且没必要”是错误的。

然而,也许你错过了他的观点。如果他告诉你要求是“没有两个用户可以拥有相同的用户名”那么你就没有达到这个要求。

真诚地感谢发布您的SQL DDL,它非常有用,但大多数都不会在SO上打扰。

使用你的表,我可以这样做:

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上的自然键,你根本就没有任何数据完整性。

如果我是教授,我也会敦促你从你的设计中删除可以为空的列。

答案 3 :(得分:7)

这通常称为surrogate key,它有许多好处。其中之一是使数据库关系与应用程序数据隔离。更多细节和相应的缺点可以在上面提供的wiki链接中找到。

答案 4 :(得分:4)

因为有人可能想要更改其用户名(或任何名称)。

答案 5 :(得分:4)

你的教授正在做正确的事情,指出如果要求用户名应该是唯一的,那么你应该使用户名是唯一的而不是可空的。 uid也可能是一个关键,但除非你实际上在某个地方使用它,否则它是不需要的。设计中更重要的方面应该是实现自然键。所以我同意你教授的意见。

答案 6 :(得分:1)

我需要有更多数据库知识的人来支持我这个,但我相信你在外键查找时间内得到更快的响应。

此外,您可能稍后决定要更改用户名,或者用户名的要求可能会更改(可能是更长的字符串?)。使用ID可以防止必须更改所有外键。

让我们面对现实,大多数项目都不会扩展 ,但你真的想在未来12个月的时候冒风险,当你现在能够符合良好的编程标准吗?

答案 7 :(得分:0)

例如,整数搜索(?id = 5)比字符串搜索(?username = bob)更快,并且具有更高的基数。 另一个例子,uid是auto_increment,因此您不必显式插入它,但它会在每个插入查询中自动递增。

PS:你的教授对此错了:D

答案 8 :(得分:0)

我们使用ID来防止重复数据,并且它可以使一些过程变得不复杂(如果我们想要更新或删除数据),如果我们使用ID则更简单。

如果您不想使用ID,则可以使用其他字段。但别忘了让它们变得独一无二。它可以使您的数据成为重复数据的预防措施。

PRIMARY之外的另一种方式是UNIQUE。

答案 9 :(得分:0)

我带上面的所有答案。我想说ID很容易实现,而且当涉及到索引时,与varchar相比,Int总是更受欢迎。你的教授应该知道的更好,为什么他会拒绝Int id在我之上!

答案 10 :(得分:0)

因为用户标识应该是唯一的(不能复制)&amp;有时候是索引。

答案 11 :(得分:0)

您是否希望以明文形式存储您的用户名以供任何人窃取?我永远不会考虑使用我可能希望有一天加密的自然密钥(或者现在想要加密)。