如何避免主键错误

时间:2018-05-18 23:52:12

标签: mysql sql database-design primary-key surrogate-key

您好我是数据库的初学者,因此我想问您应该使用哪些属性作为主键来避免错误:

    CREATE TABLE customer(
    name
    first_lastname
    street
    ZIP_code
    mobile_phone
    telephone
    email
    gender
    birthdate
    nationality);

我可以选择将idcustomer添加为auto_increment,但我不确定这是个好主意。

5 个答案:

答案 0 :(得分:4)

  

我正在考虑将idcustomer添加为auto_increment,但我不确定这是一个好主意。

这确实是一个好主意。

您的其他列(属性)不一定具有唯一值。换句话说,它们不适合用作自然主键。什么样的价值可以作为一个自然的主键?可能是员工编号。 产品序列号可能有效。纳税人身份证号码(社会安全号码)不起作用:令人惊讶的是,有多少人误用了重复的号码。选择真实项目作为主键的唯一性标准是如此之高,以至于大多数数据库设计者甚至都没有尝试过。

因此,创建一个保证唯一的主键通常是很好的设计。这种密钥的术语是代理主键。大多数DBMS系统(包括MySQL)都为此提供自动递增数字。

您可以选择两种约定之一来命名id值。一个是称之为id。另一种是将其称为customer_id(添加了_id的表名)。当您开始在其他表中使用这些值来建立关系时,第二个将帮助您保持正确。

例如,您可能有一个销售表。该表可能包含以下列:

sales_id      autoincrementing pk
customer_id   the id of the customer to whom the sale was made. (foreign key)
item_sold     description of the item
list_price
discount
net_price

你明白了。阅读primary keysforeign keys。在“逻辑数据库设计”的术语中,您可以阅读实体(客户,销售)和关系。每个表都有自己的一系列自动递增值。

然后,您可以使用这样的查询来查找每个客户的销售情况。

 SELECT customer.name, customer.first_lastname,
        COUNT(sales.sales_id) number_of_sales,
        SUM(sales.net_price) revenue
   FROM customer
   JOIN sales ON customer.customer_id = sales.customer_id
  GROUP BY customer.customer_id, customer.name, customer.first_lastname

此处sales 实体customer 实体具有多对一的关系。这是通过在每个customer_id行中指向客户的sales属性来实现的。

将id作为每个表中的第一列也是一种惯例。

约定很好:它们可以帮助下一个人查看您的应用程序。它们也有助于你未来的自我。

注意:我的销售表只是一个示例,用于说明如何自动增加id值。我并不认为它是真实世界销售表的良好布局:它不是。

答案 1 :(得分:2)

PRIMARY KEY有几个理想的属性(其中一些很明显,但我们会枚举它们)

  • 非null - (每行保证所有PK列都具有非NULL值)
  • 唯一 - (没有两行永远具有相同的值集。永远
  • simple - (单列,本机数据类型)
  • short - (群集密钥将在每个二级索引和外键中重复)
  • immutable - (一旦分配,值将不会更改)
  • 匿名 - (不带任何有意义的信息)

我们可以持有意见,并讨论每个属性,含义和好处,以及没有这些属性的主键的缺点。但是很多人最终会对什么是最重要的,以及什么都不重要的事情发表意见。)

我有理由认为这些属性中的每一个都是理想的。我承认其他人不同意。

如果此列表有效,则代理主键可以适合所有这些。

在MySQL中,实现代理主键的一种可能方法是在表中添加一个额外的列:

p4 submit

请注意,使用AUTO_INCREMENT 是一项要求。这是许多有用且易于使用的功能。 (有一些关于AUTO_INCREMENT的细节使得它在PRIMARY KEY方面不是一个完美的功能。)

重要

断言使用代理主键是正确的方式,或唯一的方法。

代理主键是成功的数据库实施项目的要求。许多成功的项目都是使用自然键实现的。

但是我会注意到(在结束时)一些坚定的自然键信徒在事件发生时(在项目后期,新发现的要求)被严重烧伤,所选择的自然键变得不满足一个(或更多)我列出的“理想属性”。

答案 2 :(得分:1)

令人惊讶的是,到目前为止,没有一个答案询问您的业务需求。您是否了解您的业务流程,与客户进行的交互以及如何在业务领域中识别客户?标识属性 - 在电子商务应用程序中,它可能是一个登录名 - 例如 - 通常应该是您表中的一个键。除非您了解该密钥的用途,否则添加自动增量不是正确的做法。

答案 3 :(得分:0)

主键是唯一标识表中行的列或一组列。考虑到这一点,您可以将唯一标识customer行的列作为主键。您可以使用电话号码或名字,姓氏和电话号码的组合作为主键。但更容易接受的方法是添加一个额外的列,可能是您想象的idcustomercustomer_idid,这对于每个客户来说都是唯一的,并使其成为首要的关键;制作这个整数列auto_increment是一个好主意。

答案 4 :(得分:0)

最安全的方法是在每个表上创建一个名为id的PK列。不要成为英雄,只要去找一个没有签名的bigint。 PK溢出,但不太可能,不是你想要的问题。

您可以使用: id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY

或者使用SERIAL关键字替换中间位,这是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的别名

请记住,如果您使用基于语句的复制,AUTO_INCREMENT可能会导致问题。基于语句的复制是5.7.6之前的默认复制。

使用合成键将您正在建模的对象的特征与该对象的唯一标识符分离,如果您需要更改架构,这将非常方便。改变MySQL PK是很昂贵的。它还保证您将拥有一个唯一的非空列,以便使用外键进行引用。此外,一些ORM期望id PK列 - 如果您涉及到这类事情。

使用MySQL,您可以创建一个复合聚簇索引,它是一个具有多个列的主键。如果您确定该表永远不会变得巨大,并且您将定期访问具有指定该键中最左侧列的子集的复杂过滤器,那么这可能是一种优化。我不会使用这种方法。

InnoDB表需要主键。即使您没有显式创建数据库,数据库也会隐式选择它找到的第一个UNIQUE列。如果没有,它将创建一个名为GEN_CLUST_INDEX的隐藏列。