19.9 MySQL 约束
约束
用于确保数据库的数据满足特定的商业规则,在mysq|中,约束包括: not null
,unique
,primary key
,foreign key
,check
五种
主键约束,非空约束,唯一约束,外键约束,检查约束
注意:去除约束的办法
19.9.1 primary key
-
基本介绍
-
注意事项
- primary key
不能重复且不能为null
- 一张表
最多只能有一个主键,但是可以是复合主键
- 主键有两种指定方式
- 直接在字段名字后面:
字段名 primary key
- 在表定义最后写:
primary key(列名)
- 直接在字段名字后面:
- 使用
desc 表名
,可以看到primary key
的情况 - 在实际开发中,每个表往往都会设计一个主键
- 删除主键约束:
alter table 表名 drop primary key或者not null等
- primary key
-
举例说明
sql-- 主键使用 -- id name email CREATE TABLE t17 (id INT PRIMARY KEY, -- 表示id列是主键 `name` VARCHAR(32), email VARCHAR(32)); -- 主键列的值是不可以重复 INSERT INTO t17 VALUES(1, 'jack', 'jack@sohu.com'); INSERT INTO t17 VALUES(2, 'tom', 'tom@sohu.com'); INSERT INTO t17 VALUES(1, 'hsp', 'hsp@sohu.com'); SELECT * FROM t17; -- 主键使用的细节讨论 -- primary key不能重复而且不能为 null。 INSERT INTO t17 VALUES(NULL, 'hsp', 'hsp@sohu.com'); -- 一张表最多只能有一个主键, 但可以是复合主键(比如 id+name) CREATE TABLE t18 (id INT PRIMARY KEY, -- 表示id列是主键 `name` VARCHAR(32), PRIMARY KEY -- 错误的,不能添加两个主键 email VARCHAR(32)); -- 演示复合主键 (id 和 name 做成复合主键) CREATE TABLE t18 (id INT , `name` VARCHAR(32), email VARCHAR(32), PRIMARY KEY (id, `name`) -- 这里就是复合主键,即在添加数据时id与name不能同时相同 ); INSERT INTO t18 VALUES(1, 'tom', 'tom@sohu.com'); INSERT INTO t18 VALUES(1, 'jack', 'jack@sohu.com'); INSERT INTO t18 VALUES(1, 'tom', 'xx@sohu.com'); -- 这里就违反了复合主键 SELECT * FROM t18; -- 主键的指定方式 有两种 -- 1. 直接在字段名后指定:字段名 primakry key -- 2. 在表定义最后写 primary key(列名); CREATE TABLE t19 (id INT , `name` VARCHAR(32) PRIMARY KEY, email VARCHAR(32) ); CREATE TABLE t20 (id INT , `name` VARCHAR(32) , email VARCHAR(32), PRIMARY KEY(`name`) -- 在表定义最后写 primary key(列名) ); -- 使用desc 表名,可以看到primary key的情况 DESC t20 -- 查看 t20表的结果,显示约束的情况 DESC t18
19.9.2 not null 与 unique
-
not null
-
unique
sql-- unique的使用 CREATE TABLE t21 (id INT UNIQUE , -- 表示 id 列是不可以重复的. `name` VARCHAR(32) , email VARCHAR(32) ); INSERT INTO t21 VALUES(1, 'jack', 'jack@sohu.com'); INSERT INTO t21 VALUES(1, 'tom', 'tom@sohu.com'); -- unqiue使用细节 -- 1. 如果没有指定 not null , 则 unique 字段可以有多个null -- 如果一个列(字段), 是 unique not null 使用效果类似 primary key INSERT INTO t21 VALUES(NULL, 'tom', 'tom@sohu.com'); SELECT * FROM t21; -- 2. 一张表可以有多个unique字段 CREATE TABLE t22 (id INT UNIQUE , -- 表示 id 列是不可以重复的. `name` VARCHAR(32) UNIQUE , -- 表示name不可以重复 email VARCHAR(32) ); DESC t22
19.9.3 foreign key
-
基本介绍
sqlCONSTRAINT 外键名 FOREIGN KEY 字段名 REFERENCES 主表名(主键名)
用于定义主表和从表之间的关系:外键约束
要定义在从表上
,主表则必须具有主键约束或是unique约束(即唯一)
,当定义外键约束后,要求外键列数据必须在主表的主键列存在
或是为null
举例说明
如下图所示,其中外键要定义在学生表上,即从表,且班级表id列唯一,即具有主键或者唯一约束,如果不唯一,那学生表的class_id到底对应那个班级则不明确,当建立外键约束后,除非班级表的班级里面已经没有学生了,才能将那个班级删除成功,同理,向学生表插入数据时,如果班级表中没有对应的id,则会插入失败,如果
class_id
为空,能插入成功 -
注意细节
-
举例
sql-- 外键演示 -- 创建 主表 my_class CREATE TABLE my_class ( id INT PRIMARY KEY , -- 班级编号 `name` VARCHAR(32) NOT NULL DEFAULT ''); -- 创建 从表 my_stu CREATE TABLE my_stu ( id INT PRIMARY KEY , -- 学生编号 `name` VARCHAR(32) NOT NULL DEFAULT '', class_id INT , -- 学生所在班级的编号 -- 下面指定外键关系 FOREIGN KEY (class_id) REFERENCES my_class(id)) -- 测试数据 INSERT INTO my_class VALUES(100, 'java'), (200, 'web'), (300, 'php'); SELECT * FROM my_class; INSERT INTO my_stu VALUES(1, 'tom', 100); INSERT INTO my_stu VALUES(2, 'jack', 200); INSERT INTO my_stu VALUES(3, 'hsp', 300); INSERT INTO my_stu VALUES(4, 'mary', 400); -- 这里会失败...因为400班级不存在 INSERT INTO my_stu VALUES(5, 'king', NULL); -- 可以, 外键 没有写 not null SELECT * FROM my_class; -- 一旦建立主外键的关系,数据不能随意删除了 DELETE FROM my_class WHERE id = 100;
19.9.4 check
-
基本介绍
-
举例讲解
sql-- 演示check的使用 -- mysql5.7目前还不支持check ,只做语法校验,但不会生效,mysql 8.0已经生效 -- 了解 -- 学习 oracle, sql server, 这两个数据库是真的生效. -- 测试 CREATE TABLE t23 ( id INT PRIMARY KEY, `name` VARCHAR(32) , sex VARCHAR(6) CHECK (sex IN('man','woman')), sal DOUBLE CHECK ( sal > 1000 AND sal < 2000) ); -- 添加数据 INSERT INTO t23 VALUES(1, 'jack', 'mid', 1); SELECT * FROM t23;
19.9.5 自增长
-
基本介绍
-
注意细节
-
一般来说自增长是和
primary key
配合使用的 -
自增长也可以单独使用(但是需要配合一个
unique
) -
自增长修饰的字段为整数型的(虽然小数也可以但是非常非常少这样使用)
-
自增长默认从1开始,也可以通过如下命令修改
mysqlalter table 表名 auto_increment = 新开始的值
-
如果添加数据时,给自增长字段(列)指定的值,则以指定的值为准,如果指定了字增长,一般来说,就按照自增长的规则来添加数据
-
自增长是在目前最大的数上进行增长,例如id这列有数据1,10,11,则自增长下一个数据为12
-
-
举例说明
sql-- 演示自增长的使用 -- 创建表 CREATE TABLE t24 (id INT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(32)NOT NULL DEFAULT '', `name` VARCHAR(32)NOT NULL DEFAULT ''); DESC t24 -- 测试自增长的使用 INSERT INTO t24 VALUES(NULL, 'tom@qq.com', 'tom'); -- 插入数据后 id 列为1 INSERT INTO t24 (email, `name`) VALUES('hsp@sohu.com', 'hsp'); -- 插入数据后 id 列为2 SELECT * FROM t24; -- 修改默认的自增长开始值 ALTER TABLE t25 AUTO_INCREMENT = 100 CREATE TABLE t25 (id INT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(32)NOT NULL DEFAULT '', `name` VARCHAR(32)NOT NULL DEFAULT ''); INSERT INTO t25 VALUES(NULL, 'mary@qq.com', 'mary'); INSERT INTO t25 VALUES(666, 'hsp@qq.com', 'hsp'); SELECT * FROM t25; CREATE DATABASE tmp; CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, dname VARCHAR(20) NOT NULL DEFAULT "", loc VARCHAR(13) NOT NULL DEFAULT "" ) ; #创建表EMP雇员 CREATE TABLE emp ( empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/ job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/ mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/ hiredate DATE NOT NULL,/*入职时间*/ sal DECIMAL(7,2) NOT NULL,/*薪水*/ comm DECIMAL(7,2) NOT NULL,/*红利*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/ ) ; #工资级别表 CREATE TABLE salgrade ( grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, losal DECIMAL(17,2) NOT NULL, hisal DECIMAL(17,2) NOT NULL ); #测试数据 INSERT INTO salgrade VALUES (1,700,1200); INSERT INTO salgrade VALUES (2,1201,1400); INSERT INTO salgrade VALUES (3,1401,2000); INSERT INTO salgrade VALUES (4,2001,3000); INSERT INTO salgrade VALUES (5,3001,9999);
19.9.6 练习 - 约束

sql
-- 使用约束的课堂练习
CREATE DATABASE shop_db;
-- 现有一个商店的数据库shop_db,记录客户及其购物情况,由下面三个表组成:
-- 商品goods(商品号goods_id,商品名goods_name,单价unitprice,商品类别category,
-- 供应商provider);
-- 客户customer(客户号customer_id,姓名name,住址address,电邮email性别sex,身份证card_Id);
-- 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums);
-- 1 建表,在定义中要求声明 [进行合理设计]:
-- (1)每个表的主外键;
-- (2)客户的姓名不能为空值;
-- (3)电邮不能够重复;
-- (4)客户的性别[男|女] check 枚举..
-- (5)单价unitprice 在 1.0 - 9999.99 之间 check
-- 商品goods
CREATE TABLE goods (
goods_id INT PRIMARY KEY,
goods_name VARCHAR(64) NOT NULL DEFAULT '',
unitprice DECIMAL(10,2) NOT NULL DEFAULT 0
CHECK (unitprice >= 1.0 AND unitprice <= 9999.99),
category INT NOT NULL DEFAULT 0,
provider VARCHAR(64) NOT NULL DEFAULT '');
-- 客户customer(客户号customer_id,姓名name,住址address,电邮email性别sex,
-- 身份证card_Id);
CREATE TABLE customer(
customer_id CHAR(8) PRIMARY KEY, -- 程序员自己决定
`name` VARCHAR(64) NOT NULL DEFAULT '',
address VARCHAR(64) NOT NULL DEFAULT '',
email VARCHAR(64) UNIQUE NOT NULL,
sex ENUM('男','女') NOT NULL , -- 这里老师使用的枚举类型, 是生效
card_Id CHAR(18));
-- 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,
-- 购买数量nums);
CREATE TABLE purchase(
order_id INT UNSIGNED PRIMARY KEY,
customer_id CHAR(8) NOT NULL DEFAULT '', -- 外键约束在后
goods_id INT NOT NULL DEFAULT 0 , -- 外键约束在后
nums INT NOT NULL DEFAULT 0,
FOREIGN KEY (customer_id) REFERENCES customer(customer_id),
FOREIGN KEY (goods_id) REFERENCES goods(goods_id));
DESC goods;
DESC customer;
DESC purchase;
19.10 MySQL 索引
简单介绍
通过在某字段上加索引
,加上索引后表所占内存会增加
,但是通过where
语句对该字段进行查询
时,速度会快很多,如八万条数据,未加索引时查找耗时 4s4s4s 多,加上索引后变为 0.0020.0020.002 秒左右,索引的原理就是维护一颗排序二叉树,即一个堆
,原来的查找就是直接遍历,加上索引后就是在排序二叉树上进行查找,大大减少了查找时间,但是只对加了索引的字段有效
,同时如果频繁修改改字段
的话,效率会比较低
,因为维护堆的代价也比较大
19.10.1 索引原理及类型
-
索引原理
-
索引类型
-
主键索引
primary key
:主键自动的为主索引(即主键自动添加索引)sqlcreate table t1 ( id int primary key, -- 主键,同时也是索引 name varchar(32));
-
唯一索引
unique
sqlcreate table t2 ( id int unique, -- id是唯一的,同时也是索引,称为unique索引 name varchar(32));
-
普通索引
index
-
全文索引
fulltext
(适用于MyISAM)一般开发中不使用
mysql
自带的全文索引,而是使用:全文搜索Solr
和ElasticSearch(ES)
-
19.10.2 索引的使用
-
基本使用
sql-- 演示mysql的索引的使用 -- 创建索引 CREATE TABLE t25 ( id INT , `name` VARCHAR(32)); -- 查询表是否有索引 SHOW INDEXES FROM t25; -- 添加索引 -- 添加唯一索引 CREATE UNIQUE INDEX id_index ON t25 (id); -- 添加普通索引方式1 CREATE INDEX id_index ON t25 (id); -- 如何选择 -- 1. 如果某列的值,是不会重复的,则优先考虑使用unique索引, 否则使用普通索引 -- 添加普通索引方式2 ALTER TABLE t25 ADD INDEX id_index (id) -- 添加主键索引 CREATE TABLE t26 ( id INT , `name` VARCHAR(32)); ALTER TABLE t26 ADD PRIMARY KEY (id) SHOW INDEX FROM t25 -- 删除索引 DROP INDEX id_index ON t25 -- 删除主键索引 ALTER TABLE t26 DROP PRIMARY KEY -- 修改索引 , 先删除,在添加新的索引 -- 查询索引 -- 1. 方式 SHOW INDEX FROM t25 -- 2. 方式 SHOW INDEXES FROM t25 -- 3. 方式 SHOW KEYS FROM t25 -- 4 方式 DESC t25
-
注意事项
-
较频繁的作为查询添加的字段应该创建索引
mysqlselect from emp where empno = 1;
-
唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
mysqlselect * from emp where sex = '男';
-
更新非常频繁的字段不适合创建索引
mysqlselect * from emp where logincount = 1;
-
不会出现
where
子句的字段不适合用索引,即不会被用作查询条件的
-
-
练习