7

我正在尝试在 MySQL 中设计一个电子商务 Web 应用程序,但在为用户表选择正确的主键时遇到问题。给出的示例只是用于说明的示例。

在此处输入图像描述

用户表有以下定义

CREATE  TABLE IF NOT EXISTS `mydb`.`user` (
  `id` INT NOT NULL ,
  `username` VARCHAR(25) NOT NULL ,
  `email` VARCHAR(25) NOT NULL ,
  `external_customer_id` INT NOT NULL ,
  `subscription_end_date` DATETIME NULL ,
  `column_1` VARCHAR(45) NULL ,
  `column_2` VARCHAR(45) NULL ,
  `colum_3` VARCHAR(45) NULL ,
  PRIMARY KEY (`id`) ,
  UNIQUE INDEX `username_UNIQUE` (`username` ASC) ,
  UNIQUE INDEX `email_UNIQUE` (`email` ASC) ,
  UNIQUE INDEX `customer_id_UNIQUE` (`external_customer_id` ASC) )
ENGINE = InnoDB

我在主键候选列方面面临以下问题:

标识列

优点

  • 无业务意义(稳定主键)
  • 更快的表连接
  • 紧缩指数

缺点

  • 不是“自然”键
  • 所有属性表必须与“主”用户表连接,因此无法进行非连接直接查询
  • 导致较少“自然”的 SQL 查询
  • 泄漏信息:如果起始值为 0,则用户可以计算出注册用户的数量(更改起始值对此进行排序)ii)用户在 time_X 将配置文件注册为 user_A,稍后在 time_Y 注册为 user_B 将很容易计算一段时间内的注册用户数((用户 B 的 ID)-(用户 A 的 ID)/(时间_Y-时间_X))

电子邮件栏

优点

  • 没有任何

缺点

  • 用户应该能够更改电子邮件地址。不适合主键

用户名列

优点

  • “自然”主键
  • 更少的表连接
  • 更简单、更“自然”的查询

缺点

  • 连接表时 varchar 列速度较慢
  • varchar 列上的索引不如 int 列索引紧凑
  • 很难更改用户名,因为外键取决于值。解决方案:“同步”应用程序上的所有外键不允许用户更改用户名,例如,用户应删除配置文件并注册新的

external_customer 列

优点

  • 可以用作客户的外部参考并且不包含任何信息(也许可以使用不可编辑的用户名?)

    缺点

  • 如果它是自动增量的(如果可能),可能会泄漏信息

  • 如果自动增量代理 id 已在使用中,则生成 unqiue 值是有问题的,因为 MySQL innodb 引擎在同一个表中没有多个 auto_increment 列

为可扩展的电子商务 Web 应用程序选择用户表主键时的常见做法是什么?所有反馈表示赞赏

4

3 回答 3

12

关于你的一些分析,我无话可说。如果我削减了你的一些优点或缺点,那只意味着我认为我没有任何有用的东西可以补充。

标识列

优点

  • 无业务意义(稳定主键)
  • 更快的表连接
  • 紧缩指数

首先,声明为 NOT NULL UNIQUE 的任何列或列集都具有主键的所有属性。您可以将它们中的任何一个用作外键引用的目标,这就是这一切的真正意义所在。

在您的情况下,您的结构允许 4 列作为外键引用的目标:id、用户名、电子邮件和 external_customer_id。您不必一直使用同一个。对 90% 的 FK 引用使用 id 并为其中的 10% 使用 email 可能是有意义的。

稳定性与列是否具有商业意义无关。稳定性与价值可能改变的频率和情况有关。除非您正在运行 Oracle,否则“稳定”并不意味着“不可变”。(Oracle 不能执行 ON UPDATE CASCADE。)

根据您的表结构和索引,自然键可能执行得更快。自然键使一些连接变得不必要。我在构建生产数据库之前进行了测试。我们可能需要几十年的时间才能达到基于 ID 号的联接将优于更少的联接和自然键的程度。我已经在 SO 或 DBA 上写过这些测试。

您还有其他三个唯一索引。(这对你有好处。我认为至少 90% 的构建数据库的人没有做到这一点。)所以不仅仅是 ID 号上的索引比这三个中的任何一个都更紧凑。它也是一个附加索引。(在此表中。)

电子邮件栏

优点

  • 没有任何

电子邮件地址可以被认为是稳定且唯一的。您无法阻止人们共享电子邮件地址,无论它是否是外键引用的目标。

但是电子邮件地址可能会“丢失”。在美国,大多数大学生在毕业一年左右就会丢失他们的 *.edu 电子邮件地址。如果您的电子邮件地址来自您正在支付的域,并且您停止付款,则该电子邮件地址将消失。我想有可能将这样的电子邮件地址提供给新用户。这是否会造成难以承受的负担取决于应用程序。

缺点

  • 用户应该能够更改电子邮件地址。不适合主键

SQL 数据库中的所有值都可以更改。仅当您的环境不让您的 dbms 及时遵守 ON UPDATE CASCADE 声明时,它才不合适。我的环境可以。(但我在体面的非共享硬件上运行 PostgreSQL。)YMMV。

用户名列

优点

  • “自然”主键
  • 更少的表连接
  • 更简单、更“自然”的查询

更少的连接是很重要的一点。我一直在参加咨询演出,在那里我看到无意识地使用 ID 号码使人们编写带有 40 多个连接的查询。明智地使用自然键可消除多达 75% 的自然键。

始终使用代理键作为外键的目标(Oracle 除外)或始终使用自然键作为目标并不重要。思考很重要。

缺点

  • 连接表时 varchar 列速度较慢
  • varchar 列上的索引不如 int 列索引紧凑

如果不限定该声明,您不能真的说加入 varchar() 会更慢。事实是,尽管 varchar() 上的大多数连接都比id 号上的连接慢,但它们不一定慢到您无法使用它们。如果一个查询需要 4 毫秒的 id​​ 编号,而 6 毫秒的 varchar(),我认为这不是取消 varchar() 资格的好理由。此外,使用自然键将消除大量连接,因此整体系统响应可能会更快。(在其他条件相同的情况下,40 个 4 毫秒的连接将不如 10 个 6 毫秒的连接。)

我不记得在我的数据库职业生涯(25 年以上)中,索引的宽度是选择外键目标的决定因素。

external_customer 列

优点

  • 可以用作客户的外部参考并且不包含任何信息(也许可以使用不可编辑的用户名?)

实际上很少有系统可以让我更改我的用户名。大多数人会让我更改我的真实姓名(我认为),但不会更改我的用户名。我认为不可编辑的用户名是完全合理的。

于 2012-04-01T22:09:10.600 回答
4

一般来说,Web 应用程序会尽量让他们的数据库模式远离客户——包括主键。我认为您将架构设计与身份验证方法混为一谈 - 即使您的数据库设计使用整数来唯一标识他们,也没有什么能阻止您允许用户使用他们的电子邮件地址登录。

每当我设计这样的系统时,我都会使用一个 ID 列 - 主键为整数或 GUID。它速度很快,不会因讨厌的现实生活情况而改变,并且是开发人员熟悉的习语。

然后,我为手头的应用程序制定了最佳身份验证方案 - 现在大多数人都希望使用他们的电子邮件地址登录,所以我会坚持下去。当然,您也可以让他们使用他们的 Facebook、Twitter 或 Google 帐户登录。与我的主键无关,虽然......

于 2012-04-01T22:21:39.690 回答
0

我认为使用用户名列你也有这个缺点:

  • 用户应该能够更改用户名。不适合主键。

因此,出于同样的原因,您不会使用电子邮件,我不会使用用户名。对我来说,内部用户整数 id 是最好的方法。

于 2012-04-01T18:41:40.520 回答