【MySQL】复合主键每个主键字段都能使用索引吗?可重复插入吗?

本文探讨了MySQL中复合主键的使用,解释了复合主键的每个字段是否都能使用索引以及是否允许重复插入。实验表明,复合主键的第一个字段在查询时使用索引,其他字段则不使用。复合主键确保多个字段的唯一组合,不允许完全相同的记录存在。

【MySQL】复合主键每个主键字段都能使用索引吗?可重复插入吗?


一、主键

  primary key用来唯一约束该字段里面的数据。其主要特征有:

  ● 不能重复,不能为空

  ● 一张表中最多只有一个primary key

  ● primary key 所在列通常是整数类型


1.1 创建主键

  create table [表名] ([字段1] [字段类型1] primary key,[字段2] [字段类型2], …);

  create table [表名] ([字段1] [字段类型1],[字段2] [字段类型2], … ,primary key(字段));

  alter table [表名] add primary key(字段);


1.2 删除主键

  alter table [表名] drop primary key;


二、复合主键

  在创建表的时候,在所有字段之后,使用primary key(字段)来创建主键,如果有多个字段作为主键,可以使用符合主键。

MariaDB [class_info]> create table test(
		id int unsigned,course char(10) comment '课程代码',
		score int unsigned default 60 comment '成绩',
		primary key(id,course));
Query OK, 0 rows affected (0.01 sec)

MariaDB [class_info]> show create table test\G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL DEFAULT '0',
  `course` char(10) NOT NULL DEFAULT '' COMMENT '课程代码',
  `score` int(10) unsigned DEFAULT '60' COMMENT '成绩',
  PRIMARY KEY (`id`,`course`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

MariaDB [class_info]> desc test;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | NO   | PRI | 0       |       |
| course | char(10)         | NO   | PRI |         |       |
| score  | int(10) unsigned | YES  |     | 60      |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

2.1 Question

  那么问题来了,在主键中说过“ 一张表中最多只有一个primary key”,那么复合主键,每个主键字段都能使用索引吗?

  防止以后在应用环境中不当的使用索引,使得mysql性能下降,今天来验证一下这个问题。


2.2 实验环境

  • MySQL 5.5
  • InnoDB引擎

2.3 实验验证

  (1) 创建test1表和test2表

MariaDB [class_info]> CREATE TABLE `test1` (
       `id` INT(11) NOT NULL,
       `name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin',
       `age` INT(11) NOT NULL,
       `gender` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin',
       PRIMARY KEY (`id`, `age`)
       )
       COLLATE='utf8_bin'
       ENGINE=InnoDB;
Query OK, 0 rows affected (0.03 sec)

MariaDB [class_info]> desc test1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(50) | YES  |     | NULL    |       |
| age    | int(11)     | NO   | PRI | NULL    |       |
| gender | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
MariaDB [class_info]> CREATE TABLE `test2` (
       `id` INT(11) NOT NULL,
       `name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin',
       `age` INT(11) NOT NULL,
       `gender` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin',
       PRIMARY KEY (`age`, `id`)
       )
       COLLATE='utf8_bin'
       ENGINE=InnoDB;
Query OK, 0 rows affected (0.02 sec)

MariaDB [class_info]> desc test2;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(50) | YES  |     | NULL    |       |
| age    | int(11)     | NO   | PRI | NULL    |       |
| gender | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

  可以看出 test1 和 test2 两个表的字段顺序是一样的,都是用了 id 和 age 的复合主键,不同的是 test1 使用的复合主键的顺序是 (id,age),test2 使用的复合主键的顺序是 (age,id)。

(2) 使用索引

image-20210422105017049

image-20210422104930920
  推荐文章:【MySQL】explain 用法详解

  观察上面两张图,可知:对于test1表,使用id字段查询时使用到了主键索引,而使用age字段查询时未使用索引。对于test2表,使用age字段查询时使用到了主键索引,而使用id字段查询时未使用索引。


2.4 实验结论

  由此证明,在MySQL中创建主键索引时字段的先后顺序是非常重要的。复合索引的第一位字段在查询时才可以用到索引,后面的字段在查询时都用不到索引。如果要频繁查询时,则应另外创建索引。

  那么对于上面的Question嘛,也就迎刃而解,这里的联合主键就是用多个字段一起作为一张表的主键,所以才说一张表中最多只有一个primary key。


三、复合主键的唯一性

  (1) 虽然复合主键只有第一个字段在查询时才可以用到索引,但是这多个字段组成了唯一的组合,不能同时重复,不然在插入时就会报错。

MariaDB [class_info]> select * from test1; 
+----+--------+-----+--------+
| id | name   | age | gender |
+----+--------+-----+--------+
|  1 | 李明   |  18 ||
|  2 | 刘梅   |  17 ||
+----+--------+-----+--------+
2 rows in set (0.00 sec)

MariaDB [class_info]> insert into test1 values(2,'路遥',19,'女');
Query OK, 1 row affected (0.01 sec)

MariaDB [class_info]> select * from test1;
+----+--------+-----+--------+
| id | name   | age | gender |
+----+--------+-----+--------+
|  1 | 李明   |  18 ||
|  2 | 刘梅   |  17 ||
|  2 | 路遥   |  19 ||
+----+--------+-----+--------+
3 rows in set (0.00 sec)

MariaDB [class_info]> insert into test1 values(3,'马力',19,'男');
Query OK, 1 row affected (0.00 sec)

MariaDB [class_info]> select * from test1;
+----+--------+-----+--------+
| id | name   | age | gender |
+----+--------+-----+--------+
|  1 | 李明   |  18 ||
|  2 | 刘梅   |  17 ||
|  2 | 路遥   |  19 ||
|  3 | 马力   |  19 ||
+----+--------+-----+--------+
4 rows in set (0.00 sec)

MariaDB [class_info]> insert into test1 values(3,'宋江',19,'男');
ERROR 1062 (23000): Duplicate entry '3-19' for key 'PRIMARY'

  test1将id和age连接起来作为复合主键,每一个字段时可以重复的,但是两个字段不能同时重复。多个字段的复合主键也是一样的,比如有A、B、C三个字段作为复合主键,当插入(1,1,1)时与前面的记录数据完全相同就会出错。

ABC√ / ×
111
112
121
211
122
212
221
111×

  (2) 虽然复合主键只有第一个字段在查询时才可以用到索引,但是这多个字段组成了唯一的组合,不能为空,不然在插入时就会报错。

MariaDB [class_info]> select * from test1;
+----+--------+-----+--------+
| id | name   | age | gender |
+----+--------+-----+--------+
|  1 | 李明   |  18 ||
|  2 | 刘梅   |  17 ||
+----+--------+-----+--------+
2 rows in set (0.00 sec)

MariaDB [class_info]> insert into test1(name,age,gender) values('张三',20,'男');
ERROR 1364 (HY000): Field 'id' doesn't have a default value

MariaDB [class_info]> insert into test1(id,name,gender) values(3,'李四','');
ERROR 1364 (HY000): Field 'age' doesn't have a default value

MariaDB [class_info]> insert into test1(name,gender) values('王麻子','男');
ERROR 1364 (HY000): Field 'id' doesn't have a default value

MariaDB [class_info]> desc test1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(50) | YES  |     | NULL    |       |
| age    | int(11)     | NO   | PRI | NULL    |       |
| gender | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值