MySQL - 什么是正确的主键方法

时间:2010-03-27 14:48:20

标签: mysql primary-key

我开始使用MySQL开发应用程序,尽管我在使用数据库之前已经开发了应用程序,但我通常会使用递增id方法。有一天,我正在某个地方阅读一个帖子,看到有人因为没有正确地“正常化数据库”而被分开。我不是一个大数据库人,但我想确保我做对了。

任何想法,帮助/指导?

4 个答案:

答案 0 :(得分:5)

选择primary key有两种主要方法:

  • 从现有natural candidate keys中选择主键。
  • 创建surrogate key,并将其设置为主键。与自然键不同,代理键不是从应用程序数据派生的。这是您使用自动递增方法的密钥类型。

这两种方法都有一般优点和缺点,您可能希望在某些情况下选择自然键,在其他情况下选择代理键。

我希望这只是一个简短的介绍,以便您可以进一步研究如何选择合适的主键。

答案 1 :(得分:2)

COMPOSITE PK方法

drop table if exists users;
create table users(
 user_id int unsigned not null auto_increment primary key, -- clustered auto_inc PK
 username varbinary(32) not null,
 unique key users_username_idx(username)
)engine=innodb;

insert into users (username) values ('f00'),('bar'),('bish'),('bash'),('bosh'),('F00');

drop table if exists user_friends;
create table user_friends(
 user_id int unsigned not null,
 friend_user_id int unsigned not null,
 primary key (user_id, friend_user_id) -- clustered composite PK
)engine=innodb;

insert into user_friends values
(1,2),(1,3),  (2,1),(2,5),  (3,5),  (4,1),(4,2),(4,3),(4,5),(4,6),  (5,4),(5,1);

大部分时间我都在查询想要列出给定用户的所有朋友的user_friends 所以我的查询正在利用聚集主键(user_id,friend_user_id)

select * from user_friends where user_id = 4; -- uses PK index

如果我想删除朋友,我有一个复合PK,所以我需要指定user_id和 我要删除的friend_user_id - 需要满足密钥的两个部分。这个 习惯让你的应用程序逻辑变得更复杂。

delete from user_friends where user_id = 4 and user_friend_id = 5; -- uses PK index

AUTO INC PK APPROACH (用户表保持不变)

drop table if exists user_friends;
create table user_friends(
 friend_id int unsigned not null auto_increment primary key, -- clustered auto_inc PK
 user_id int unsigned not null,
 friend_user_id int unsigned not null,
 unique key user_friends_idx (user_id, friend_user_id) -- non clustered secondary index
)engine=innodb;

大部分时间我都在查询想要列出给定用户的所有朋友的user_friends 在这种情况下,我无法利用主键,我需要创建一个辅助 index on(user_id,friend_user_id)。现在我在这个表上有2个索引PK索引 强制实体完整性和辅助索引,有助于优化我的查询。

添加二级索引会产生相关的成本。插入/删除现在必须 更新2个索引与仅一个复合键索引,它占用更多的磁盘空间。

select * from user_friends where user_id = 4; -- uses secondary index not PK

然而,如果我想删除一个朋友,我可以使用friend_id PK,这简化了我的 应用程序逻辑,因为我可以使用PK轻松删除1行。

delete from user_friends where friend_id = 10; -- uses PK index

这可能不是这两种方法的一个很好的例子,但它应该给你一些想法,为什么有时使用聚簇复合索引:)

答案 2 :(得分:1)

增加id与规范化无关。规范化与删除传递和减少依赖关系有关。无论您选择使用自动递增ID还是其他形式的主键,都是完全不同的事情。

答案 3 :(得分:0)

自动增量ID和规范化无关(即,您可以在非规范化数据库中使用自动增量ID,或者使用不使用自动增量ID的规范化数据库)。