使用电子邮件地址为主键?

与自动递增的数字相比,电子邮件地址是一个糟糕的初选候选人吗?

我们的web应用程序需要电子邮件地址在系统中是唯一的。所以,我想到使用电子邮件地址为主键。然而,我的同事认为字符串比较将比整数比较慢。

这是一个有效的理由不使用电子邮件为主键吗?

我们正在使用PostgreSQL

51857 次浏览

您可以通过使用整数主键来提高性能。

是的,如果您使用整数来代替会更好。您还可以将电子邮件列设置为唯一约束。

是这样的:

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

您应该使用整数主键。如果你需要电子邮件列是唯一的,为什么不简单地在该列上设置一个唯一索引呢?

字符串比较比int比较慢。但是,如果您只是使用电子邮件地址从数据库检索用户,那么这并不重要。如果您有多个连接的复杂查询,那么这很重要。

如果在多个表中存储有关用户的信息,则用户表的外键将是电子邮件地址。这意味着您将多次存储电子邮件地址。

整数主键更好的另一个原因是当您在不同的表中引用电子邮件地址时。如果address本身是一个主键,那么在另一个表中你必须使用它作为一个键。所以你可以多次存储电子邮件地址。

你的同事是对的:使用一个自动递增的整数作为你的主键。

您可以在应用程序级别实现电子邮件唯一性,或者您可以将电子邮件地址列标记为惟一,并在该列上添加索引。

将字段添加为唯一字段只会在插入到该表时花费字符串比较的成本,而不会在执行连接和外键约束检查时花费字符串比较成本。

当然,您必须注意,在数据库级别向应用程序添加任何约束都可能导致应用程序变得不灵活。在仅仅因为应用程序需要某个字段是唯一的或非空的,就将它设置为“唯一的”或“非空的”之前,一定要充分考虑。

我对postgres不太熟悉。主键是一个很大的主题。我在这个网站(stackoverflow.com)上看到了一些很好的问题和答案。

我认为使用数字主键并在电子邮件列上使用UNIQUE INDEX可以获得更好的性能。电子邮件往往在长度上有所不同,可能不适合主键索引。

一些读取在这里在这里。

我还要指出,电子邮件是一个糟糕的选择,使一个独特的领域,有些人,甚至是小企业共享一个电子邮件地址。就像电话号码一样,电子邮件可以被重复使用。 Jsmith@somecompany.com很容易在一年后属于John Smith,两年后属于Julia Smith。

电子邮件的另一个问题是它们经常变化。如果你用这个键连接到其他表,那么你也必须更新其他表,当整个客户公司更改他们的电子邮件时,这可能会对性能造成相当大的影响(我曾经见过这种情况)。

这很糟糕。假设某个电子邮件提供商倒闭了。用户会想要更改他们的电子邮件。如果你使用e-mail作为主键,用户的所有外键都将复制该电子邮件,这使得更改它非常困难……

... 我甚至还没有开始谈论性能考虑因素。

主键应该是独特的< < em >常数/ em >

电子邮件地址随着季节的变化而变化。作为查找的辅助键很有用,但作为主键不太合适。

如果你有一个非int值作为主键,那么在大数据上插入和检索将会非常慢。

使用电子邮件地址作为主键的缺点:

  1. 做连接时更慢。

  2. 任何其他带有外键的记录现在都具有更大的值,占用更多的磁盘空间。(考虑到当前磁盘空间的成本,这可能是一个微不足道的问题,只是现在读取记录需要更长的时间。看到# 1)。

  3. 电子邮件地址可能会更改,这将强制更新所有使用此外键的记录。由于电子邮件地址不会经常更改,所以性能问题可能很小。更大的问题是,你必须确保为此做好准备。如果您必须编写代码,这是更多的工作,并引入了错误的可能性。如果您的数据库引擎支持“on update cascade”,这是一个小问题。

使用电邮地址作主键的优点:

  1. 您可以完全消除一些连接。如果从“主记录”中需要的只是电子邮件地址,那么对于一个抽象整数键,您将不得不执行连接来检索它。如果键是电子邮件地址,那么您已经拥有了它,联接是不必要的。这对你是否有帮助取决于这种情况出现的频率。

  2. 当您进行特别查询时,人们很容易看到引用的是什么主记录。在试图追踪数据问题时,这可能是一个很大的帮助。

  3. 无论如何,您几乎肯定需要在电子邮件地址上建立索引,因此将其作为主键可以消除一个索引,从而提高插入的性能,因为它们现在只需更新一个索引而不是两个。

在我看来,这两种情况都不是十拿九稳的。当有实用的键时,我倾向于使用自然键,因为它们更容易使用,而且在大多数情况下,缺点并不太重要。

这取决于桌子。如果表中的行表示电子邮件地址,那么电子邮件是最好的ID。如果不是,那么电子邮件不是一个好的ID。

使用GUID作为主键…这样,当你执行INSERT操作时,你就可以从程序中生成它,而不需要从服务器获取响应来找出主键是什么。它在所有表和数据库中都是唯一的,如果有一天你截断了表,自动增量被重置为1,你不必担心会发生什么。

如果只是要求电子邮件是唯一的,那么你可以用该列创建一个唯一的索引。

就我个人而言,我在设计数据库时不使用任何信息作为主键,因为我很可能在以后需要更改任何信息。我提供主键的唯一原因是,它方便从客户端执行大多数SQL操作,我的选择一直是自动增加整数类型。

我不知道这在你的设置中是否可能是一个问题,但根据你的RDBMS,列的值可能是区分大小写的。PostgreSQL文档说:“如果你声明一个列为UNIQUE或PRIMARY KEY,隐式生成的索引是区分大小写的”。换句话说,如果您在一个以email为主键的表中接受用户输入进行搜索,并且用户提供“John@Doe.com”,那么您将找不到“john@doe.com”。

是的,这是一个糟糕的主键,因为你的用户会想要更新他们的电子邮件地址。

似乎没有人提到一个可能的问题,即电子邮件地址可能被视为隐私。如果电子邮件地址是主键,个人资料页面URL很可能看起来像..../Users/my@email.com。如果不想暴露用户的电子邮件地址怎么办?你必须找到一些其他的方法来识别用户,可能是通过一个唯一的整数值来创建像..../Users/1这样的url。那么你最终会得到一个唯一的整数值。

Email是一个很好的唯一索引候选,但不是主键,如果它是一个主键,例如,你将无法更改联系人的电子邮件地址。 我认为你的连接查询也会变慢
< em >逻辑< / em >水平中,电子邮件是自然的密钥。 在物理级别,如果你使用的是关系数据库,自然键不适合作为主键。原因主要是别人提到的性能问题。

出于这个原因,设计可以进行调整。自然键变成替换关键字 (UNIQUE, NOT NULL),你使用代理/人工/技术关键作为主键,在你的情况下,它可以是一个自动递增。

systempuntoout问道:

如果有人想更改他的电子邮件地址怎么办?你是否也要更改所有外键?

这就是级联的作用。

使用数字代理键作为主键的另一个原因与索引在平台中的工作方式有关。例如,在MySQL的InnoDB中,表中的所有索引都预先挂起了主键,所以你希望PK尽可能小(为了速度和大小)。同样与此相关的是,当主键按顺序存储时,InnoDB会更快,而字符串在那里没有帮助。

使用字符串作为替代键时要考虑的另一件事是,使用您想要的实际字符串的哈希值可能更快,跳过一些字母的大写和小写。(实际上,我降落在这里是为了寻找证据来证实我刚才说的话;还看……)

我知道这有点晚了,但我想补充的是,人们放弃电子邮件帐户和服务提供商恢复地址,允许其他人使用它。

正如@HLGEM指出的那样,“Jsmith@somecompany.com很容易在一年后属于约翰·史密斯,两年后属于朱莉娅·史密斯。”在这种情况下,如果约翰·史密斯想要你的服务,你要么拒绝使用他的电子邮件地址,要么删除所有与朱莉娅·史密斯有关的记录。

如果你必须根据当地法律删除与企业财务历史有关的记录,你可能会发现自己陷入困境。

所以我永远不会使用电子邮件地址、车牌等数据作为主键,因为无论它们看起来多么独特,它们都不受你的控制,并且可能会提供一些你可能没有时间处理的有趣挑战。

主键应该选择一个静态属性。由于电子邮件地址不是静态的,可以被多个候选人共享,因此使用它们作为主键并不是一个好主意。此外,电子邮件地址通常是一定长度的字符串,可能大于唯一id,我们想使用[len(email_address)>len(unique_id)],所以它将需要更多的空间,甚至最糟糕的是,它们被多次存储为外键。因此会导致性能下降。

不要使用电子邮件地址为主键,保持电子邮件的唯一性,但不要使用它为主键,使用用户id或用户名为主键

您可能需要考虑任何适用的数据法规。电子邮件是个人信息,例如,如果你的用户是欧盟公民,那么根据GDPR,他们可以指示你从你的记录中删除他们的信息(记住,无论你在哪个国家,这都适用)。

如果出于参考完整性或审计等历史原因,需要将记录本身保存在数据库中,则使用代理键将允许您将所有个人数据字段设置为NULL。如果他们的个人数据是主键,这显然不那么容易