0

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

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

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

4

5 回答 5

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

你明白了。阅读有关主键外键的信息。在“逻辑数据库设计”的行话中,您可以阅读有关实体(客户、销售)和关系的信息。每个表都有自己的一系列自动递增值。

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

 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_idsales

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

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

注意:我的销售表只是一个示例,展示了自动递增 id 值如何有用。我并没有声称它对于现实世界的销售表来说是一个很好的布局:它不是。

于 2018-05-18T23:58:02.993 回答
2

PRIMARY KEY 有几个理想的属性(其中一些非常明显,但我们将列举它们)

  • 非空 - (保证每一行的所有 PK 列都有一个非空值)
  • 唯一的 - (没有两行将具有相同一组值。永远
  • 简单 - (单列,本机数据类型)
  • 短 - (集群键将在每个二级索引中重复,外键)
  • 不可变 - (一旦分配,值不会改变)
  • 匿名 - (不携带任何有意义的信息)

我们可以就这些属性中的每一个、含义和好处以及不具有这些属性的主键的缺点提出意见并进行讨论。但是很多最终都是关于什么是最重要的,什么是不重要的。)

我有理由认为这些属性中的每一个都是可取的。我承认其他人不持有相同的观点。

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

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

 CREATE TABLE mytable 
 ( id                INT NOT NULL AUTO_INCREMENT PRIMARY KEY  COMMENT 'PK'
 , cust_email        VARCHAR(255) NOT NULL                    COMMENT 'UX1'
 , cust_name_title
 , cust_name_first
 , cust_name_last
 , cust_name_suffix
 , cust_addr_street
 , cust_addr_line2
 , cust_addr_city
 , cust_addr_state
 , cust_addr_postal_code
 , UNIQUE KEY customer_UX1 (cust_email) 
 )

请注意,使用 AUTO_INCREMENT不是必需的。这是许多人认为有用且易于使用的功能。(有一些关于 AUTO_INCREMENT 的细节使其在 PRIMARY KEY 方面不够完美。)


重要的

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

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

但我要指出(最后),当事实证明(在项目后期,新发现的要求)选择的自然键结果不满足一个(或多个) 我列出的“理想属性”。

于 2018-05-19T00:00:06.837 回答
1

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

于 2018-05-19T14:31:50.563 回答
0

主键是唯一标识表中行的一列或一组列。考虑到这一点,您可以将任何列customer唯一地标识行作为主键。您可以使用电话号码或名字、姓氏和电话号码的组合作为主键。但是更被接受的方法是添加一个额外的列,也许idcustomer像你想象的那样命名 orcustomer_id或者只是id,这对于每个客户来说都是唯一的,并使其成为主键;制作这个整数列auto_increment是个好主意。

于 2018-05-19T00:02:31.320 回答
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 需要一个idPK 列——如果你喜欢那种东西的话。

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

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

于 2018-05-19T01:47:20.530 回答