ITPub博客

首页 > > > 主键,聚集索引,不是一个东西!

主键,聚集索引,不是一个东西!

作者:58沈剑 时间:2020-01-02 13:37:38 0 删除 编辑
《主键,五个小习题》昨天挖的坑,今天填一下。

练习一:建表时,可不可以不声明主键?

(1) create table user(

         name varchar(10)

)engine=innodb;

(2) insert into user values('shenjian');

(3) insert into user values('shenjian');

画外音:建表时,不声明主键,插入两个相同的元素。
 
提问,连续执行上面的语句,执行结果是:

A 建表语句(1)报错

B 插入语句(2)报错

C 插入语句(3)报错

D 均不报错

 

实操如上,所以答案是【D 均不报错】
 
InnoDB必须要有聚集索引,行记录按照聚集索引物理上排序。必须要有聚集索引,并不代表一定要有主键。
(1)如果定义了主键,主键就是聚集索引;
(2)如果没有定义主键,第一个非空(not null)且唯一(unique)列是聚集索引;
(3)如果没有符合条件的列,会自动创建一个隐藏的row-id作为聚集索引;
画外音:本例就属于第三种情况。
 
练习二:建表时,可不可以不声明主键非空?

(1) create table user(

         id int,

         name varchar(10),

         primary key(id)

)engine=innodb;

(2) insert into user(name) values('shenjian');

(3) insert into user(name) values('shenjian');

画外音:建表时,不声明非空,插入两个相同的元素。
 
提问,连续执行上面的语句,执行结果是:

A 建表语句(1)报错

B 插入语句(2)报错

C 插入语句(3)报错

D 均不报错


实操如上,所以答案是:【C 插入语句(3)报错】
 
建表语句可以不主动设置主键非空(上例中的id),InnoDB会自动添加非空(not null)且唯一(unique)的限制。

使用show create table查看,会发现主键列要求非空,且默认值是0,因此:
insert into user(name) values('shenjian');
id默认为0,第一次插入成功,第二次插入主键冲突。
画外音:这一题很多人答错。
 
练习三:建表时,可不可以选择多个字段做主键?

(1) create table user(

         id int not null,

         name varchar(10) not null,

         primary key(id, name)

)engine=innodb;

(2) insert into user values(1, 'shenjian');

(3) insert into user values(1, 'zhangsan');

(4) insert into user values(2, 'shenjian');

画外音:建表时,声明联合主键(a,b),插入若干元素,有些a重复,有些b重复。
 
提问,连续执行上面的语句,执行结果是:

A 建表语句(1)报错

B 插入语句(2)报错

C 插入语句(3)报错

D 插入语句(3)报错

E 均不报错


实操如上,所以答案是:【E 均不报错】
 
这就是所谓的联合主键,不要求每个列唯一,而要求联合主键各个列的“组合唯一”。
画外音:联合索引,联合主键,类似的。
 
练习四:可不可以主动插入自增主键?

(1) create table user(

         id int auto_increment,

         name varchar(10) not null,

         primary key(id)

)engine=innodb;

(2) insert into user(name) values('shenjian');

(3) insert into user(id, name) values(10,'shenjian');

(4) insert into user(name) values('shenjian');

画外音:建表时,自增ID为主键,插入若干元素,有些包含自增ID,有些不包含。
 
提问,连续执行上面的语句,执行结果是:

A 建表语句(1)报错

B 插入语句(2)报错

C 插入语句(3)报错

D 插入语句(3)报错

E 均不报错


实操如上,所以答案是:【E 均不报错】
 
自增ID经常被用来作为主键,插入行记录时,不指定值,InnoDB自动增加。同时,也可以手动指定值:
(1)手动指定的值与已有值重复,则主键冲突;
(2)与已有值不冲突,则插入成功;
(3)未来不指定值插入,会从手动插入值往后继续递增;
 

如上例,手动插入10后,未来插入的行会从11开始,自增ID中间出现空洞。
 
练习五:建表时,可不可以使用联合自增主键?

(1) create table user(

         id int auto_increment,

         name varchar(10) not null,

         primary key(name, id)

)engine=innodb;

(2) insert into user(name) values('shenjian');

(3) insert into user(id, name) values(10,'shenjian');

(4) insert into user(name) values('shenjian');

画外音:建表时,声明联合主键(a,b),并且有一个是自增ID,插入若干元素,包含自增ID,有些不包含。
 
提问,连续执行上面的语句,执行结果是:

A 建表语句(1)报错

B 插入语句(2)报错

C 插入语句(3)报错

D 插入语句(3)报错

E 均不报错


实操如上,所以答案是:【A 建表语句(1)报错】
 
这里不是指自增ID不能作为联合主键,而是如果作为联合主键,必须放在第一列。

primary key(name, id)
改为
primary key(id, name)
就可以执行成功了。
画外音:这一题很多人答错。
 
总结
一:InnoDB建表时,可不可以不声明主键?
可以不声明主键,但必须要有聚集索引:
(1)有主键,主键是聚集索引;
(2)没有主键,首个非空唯一列是聚集索引;
(3)没有符合条件的列,row-id是聚集索引;
主键和聚集索引不是一个东西,不要混淆。
 
二:InnoDB建表时,可不可以不声明主键非空?
可以不声明主键非空,会自动加上非空限制。
 
三:InnoDB建表时,可不可以选择多个字段做主键?
可以使用联合主键,组合列唯一即可。
 
四:InnoDB插入时,可不可以主动插入自增主键?
可以指定自增列的值,但可能导致空洞。
 
五:InnoDB建表时,可不可以使用联合自增主键?
可以,但自增ID必须在联合主键的第一列。

希望大家对主键有更系统性的认识。

架构师之路-分享技术思路


相关文章:

《缓冲池(buffer pool),彻底懂了!》
《写缓冲(change buffer),彻底懂了!》


【DCEEA】,你答对了吗?

画外音:原文是《主键,五个小习题》,评论里好多同学都答错了,帮转一下吧。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31556838/viewspace-3139169/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
58速运CTO,互联网架构技术专家,“架构师之路”公众号作者。曾任百度高级工程师,58同城技术委员会主席,高级架构师,58到家技术委员会主席,高级技术总监,目前主要负责58速运技术部。

注册时间:2018-09-30

  • 博文量
    420
  • 访问量
    82603