MySql 数据库 - 第3章:约束、事务、索引、视图、范式

MySql 数据库 - 第3章:约束、事务、索引、视图、范式

    • 1、约束(Constraint)
    • 2、存储引擎(了解)
    • 3、事务(Transaction)
    • 4、索引
    • 5、视图(view)
    • 6、DBA命令
    • 7、数据库设计三范式(重点,面试常问)
  • 传送门

1、约束(Constraint)

1.0、什么是约束?常见的约束有哪些呢?
	在创建表的时候,可以给表的字段添加相应的约束,添加约束的目的是为了保证表中数据的
	合法性、有效性、完整性。
	
	常见的约束有哪些呢?
		非空约束(not null):约束的字段不能为NULL
		唯一约束(unique):约束的字段不能重复
		主键约束(primary key):约束的字段既不能为NULL,也不能重复(简称PK)
		外键约束(foreign key):...(简称FK)
		检查约束(check):注意Oracle数据库有check约束,但是mysql没有,目前mysql不支持该约束。


1.1、非空约束 not null
	drop table if exists t_user; //删表
	create table t_user(    //建表
		id int,
		username varchar(255) not null,
		password varchar(255)
	);
	
	insert into t_user(id,password) values(1,'123');  // 报错
	ERROR 1364 (HY000): Field 'username' doesn't have a default value
	报错了,因为username要求非空。

	insert into t_user(id,username,password) values(1,'lisi','123');  // 可以


1.2、唯一性约束(unique)
	
	唯一约束修饰的字段具有唯一性,不能重复。但可以为NULL。
	
	【案例1】给某一列添加unique
		drop table if exists t_user;
		create table t_user(
			id int,
			username varchar(255) unique  // 【列级约束】
		);
		insert into t_user values(1,'zhangsan');
		insert into t_user values(2,'zhangsan'); //报错了
		ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'username'

		insert into t_user(id) values(2);
		insert into t_user(id) values(3);
		insert into t_user(id) values(4);
		这三个数据的username都为NULL是可以的

	【案例2】给两个列或者多个列添加unique
		drop table if exists t_user;
		create table t_user(
			id int, 
			usercode varchar(255),
			username varchar(255),
			unique(usercode,username) // 多个字段联合起来添加1个unique约束 【表级约束】
		);
		insert into t_user values(1,'111','zs');
		insert into t_user values(2,'111','ls');
		insert into t_user values(3,'222','zs');
		select * from t_user;
		insert into t_user values(4,'111','zs');   //报错了
		ERROR 1062 (23000): Duplicate entry '111-zs' for key 'usercode'

		drop table if exists t_user;
		create table t_user(
			id int, 
			usercode varchar(255) unique,   // 【列级约束】
			username varchar(255) unique    // 【列级约束】
		);
		insert into t_user values(1,'111','zs');
		insert into t_user values(2,'111','ls');   //报错了
		ERROR 1062 (23000): Duplicate entry '111' for key 'usercode'
	
	注意:上面的not null非空约束只有列级约束。没有表级约束。


1.3、主键约束
	
	(1)怎么给一张表添加主键约束呢?
		drop table if exists t_user;
		create table t_user(
			id int primary key,  // 列级约束
			username varchar(255),
			email varchar(255)
		);
		insert into t_user(id,username,email) values(1,'zs','[email protected]');
		insert into t_user(id,username,email) values(2,'ls','[email protected]');
		insert into t_user(id,username,email) values(3,'ww','[email protected]');
		select * from t_user;
		+----+----------+------------+
		| id | username | email      |
		+----+----------+------------+
		|  1 | zs       | [email protected] |
		|  2 | ls       | [email protected] |
		|  3 | ww       | [email protected] |
		+----+----------+------------+

		insert into t_user(id,username,email) values(1,'jack','[email protected]');
		ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
		报错了

		insert into t_user(username,email) values('jack','[email protected]');
		ERROR 1364 (HY000): Field 'id' doesn't have a default value
		报错了

		根据以上的测试得出:id是主键,因为添加了主键约束,主键字段中的数据不能为NULL,也不能重复。
		主键的特点:不能为NULL,也不能重复。
	
	(2)主键相关的术语?
		主键约束 : primary key
		主键字段 : id字段添加primary key之后,id叫做主键字段
		主键值 : id字段中的每一个值都是主键值。
	
	(3)主键有什么作用?
		- 表的设计三范式中有要求,第一范式就要求任何一张表都应该有主键。
		- 主键的作用:主键值是这行记录在这张表当中的唯一标识。(就像一个人的身份证号码一样。)
	
	(4)主键的分类?
		根据主键字段的字段数量来划分:
			单一主键(推荐的,常用的。)
			复合主键 (多个字段联合起来添加一个主键约束)(复合主键不建议使用,因为复合主键违背三范式。)(三范式最下面会讲)
		根据主键性质来划分:
			自然主键:主键值最好就是一个和业务没有任何关系的自然数。(这种方式是推荐的)
			业务主键:主键值和系统的业务挂钩,例如:拿着银行卡的卡号做主键,拿着身份证号码作为主键。(不推荐用)
				
				最好不要拿着和业务挂钩的字段作为主键。因为以后的业务一旦发生改变的时候,主键值可能也需要
				随着发生变化,但有的时候没有办法变化,因为变化可能会导致主键值重复。
	
	(5)重点:一张表的主键约束只能有1个。

	(6)使用 表级约束 方式定义主键:
		drop table if exists t_user;
		create table t_user(
			id int,
			username varchar(255),
			primary key(id)
		);
		insert into t_user(id,username) values(1,'zs');
		insert into t_user(id,username) values(2,'ls');
		insert into t_user(id,username) values(3,'ws');
		insert into t_user(id,username) values(4,'cs');
		select * from t_user;

		insert into t_user(id,username) values(4,'cx');
		ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'

		以下内容是演示以下复合主键,不需要掌握:
			drop table if exists t_user;
			create table t_user(
				id int,
				username varchar(255),
				password varchar(255),
				primary key(id,username)    
			);
			insert .......
	
	(7)mysql提供主键值自增:(非常重要。)
		drop table if exists t_user;
		create table t_user(
			id int primary key auto_increment, 
			username varchar(255)
		);
		// id字段自动维护一个自增的数字,从1开始,以1递增。
		insert into t_user(username) values('a');
		insert into t_user(username) values('b');
		insert into t_user(username) values('c');
		insert into t_user(username) values('d');
		insert into t_user(username) values('e');
		insert into t_user(username) values('f');
		select * from t_user;

		提示:Oracle当中也提供了一个自增机制,叫做:序列(sequence)对象。


1.4、外键约束
	
	(1)外键约束的相关术语:
		外键约束: foreign key
		外键字段:添加有外键约束的字段
		外键值:外键字段中的每一个值。
	
	(2)业务背景:
		请设计数据库表,用来维护学生和班级的信息?
			【方案一】一张表存储所有数据
				no(pk)		name		classno		classname
				----------------------------------------------------------------------------------------
				1			zs1				101		北京大兴区经济技术开发区亦庄二中高三1班
				2			zs2				101		北京大兴区经济技术开发区亦庄二中高三1班
				3			zs3				102		北京大兴区经济技术开发区亦庄二中高三2班
				4			zs4				102		北京大兴区经济技术开发区亦庄二中高三2班
				5			zs5				102		北京大兴区经济技术开发区亦庄二中高三2班
				缺点:冗余。【不推荐】

			【方案二】两张表(班级表和学生表)
				t_class 班级表
				cno(pk)		cname
				--------------------------------------------------------
				101			北京大兴区经济技术开发区亦庄二中高三1班
				102			北京大兴区经济技术开发区亦庄二中高三2班

				t_student 学生表
				sno(pk)		sname		classno(该字段添加外键约束fk)
				------------------------------------------------------------
				1			zs1			101
				2			zs2			101
				3			zs3			102
				4			zs4			102
				5			zs5			102
		
	(3)将以上表的建表语句写出来:

		t_student中的classno字段引用t_class表中的cno字段,此时t_student表叫做子表。t_class表叫做父表。

		顺序要求:
			创建表的时候,先创建父表,再创建子表。
			删除表的时候,先删除子表,在删除父表。
			添加数据的时候,先添加父表,在添加子表。
			删除数据的时候,先删除子表,再删除父表。
		
		drop table if exists t_student;
		drop table if exists t_class;

		create table t_class(
			cno int,
			cname varchar(255),
			primary key(cno)
		);

		create table t_student(
			sno int,
			sname varchar(255),
			classno int,
			primary key(sno),
			foreign key(classno) references t_class(cno)
		);

		insert into t_class values(101,'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
		insert into t_class values(102,'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy');

		insert into t_student values(1,'zs1',101);
		insert into t_student values(2,'zs2',101);
		insert into t_student values(3,'zs3',102);
		insert into t_student values(4,'zs4',102);
		insert into t_student values(5,'zs5',102);
		insert into t_student values(6,'zs6',102);
		select * from t_class;
		select * from t_student;

		insert into t_student values(7,'lisi',103);
		ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails 
		(`zt`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`classno`) REFERENCES `t_class` (`cno`))
	
	(4)外键值可以为NULL。
		insert into t_student values(7,'lisi',null);
	
	(5)外键字段引用其他表的某个字段的时候,被引用的字段必须是主键吗?
		注意:不是,被引用的字段不一定是主键,但至少具有unique约束。(一般情况下都是主键)

2、存储引擎(了解)

2.1、完整的建表语句
		mysql> show create table t_class;
		+---------+--------------------------------------+
		| Table   | Create Table                                                                                                                                                   |
		+---------+--------------------------------------+
		| t_class | CREATE TABLE `t_class` (
		  `cno` int(11) NOT NULL DEFAULT '0',
		  `cname` varchar(255) DEFAULT NULL,
		  PRIMARY KEY (`cno`)
		) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
		+---------+--------------------------------------+
		1 row in set (0.00 sec)

	注意:在MySQL当中,凡是标识符是可以使用飘号(键盘左上角数字键1左边的)括起来的。最好别用,不通用。

	建表的时候可以指定存储引擎,也可以指定字符集。

	mysql默认使用的存储引擎是InnoDB方式。默认采用的字符集是UTF8(可在上面最后一行看到)

2.2、什么是存储引擎呢?
	存储引擎这个名字只有在mysql中存在。
	(Oracle中有对应的机制,但是不叫做存储引擎。Oracle中没有特殊的名字,就是“表的存储方式”)

	mysql支持很多存储引擎,每一个存储引擎都对应了一种不同的存储方式。
	每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。

2.3、查看当前mysql支持的存储引擎?
	mysql> show engines \G

	mysql 5.5.36版本支持的存储引擎有9个:

		*************************** 1. row ***************************
		      Engine: FEDERATED
		     Support: NO
		     Comment: Federated MySQL storage engine
		Transactions: NULL
			  	  XA: NULL
		  Savepoints: NULL
		*************************** 2. row ***************************
		      Engine: MRG_MYISAM
		     Support: YES
		     Comment: Collection of identical MyISAM tables
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		*************************** 3. row ***************************
		      Engine: MyISAM
		     Support: YES
		     Comment: MyISAM storage engine
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		*************************** 4. row ***************************
		      Engine: BLACKHOLE
		     Support: YES
		     Comment: /dev/null storage engine (anything you write to it disappears)
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		*************************** 5. row ***************************
		      Engine: CSV
		     Support: YES
		     Comment: CSV storage engine
		Transactions: NO
			  XA: NO
		  Savepoints: NO
		*************************** 6. row ***************************
		      Engine: MEMORY
		     Support: YES
		     Comment: Hash based, stored in memory, useful for temporary tables
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		*************************** 7. row ***************************
		      Engine: ARCHIVE
		     Support: YES
		     Comment: Archive storage engine
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		*************************** 8. row ***************************
		      Engine: InnoDB
		     Support: DEFAULT
		     Comment: Supports transactions, row-level locking, and foreign keys
		Transactions: YES
			      XA: YES
		  Savepoints: YES
		*************************** 9. row ***************************
		      Engine: PERFORMANCE_SCHEMA
		     Support: YES
		     Comment: Performance Schema
		Transactions: NO
			      XA: NO
		  Savepoints: NO

2.4、常见的存储引擎?
	上面第3个:
		*************************** 3. row ***************************
		      Engine: MyISAM
		     Support: YES
		     Comment: MyISAM storage engine
		Transactions: NO
			      XA: NO
		  Savepoints: NO

		MyISAM这种存储引擎不支持事务。
		MyISAM是mysql最常用的存储引擎,但是这种引擎不是默认的。
		MyISAM采用三个文件组织一张表:
			xxx.frm(存储表结构格式的文件)
			xxx.MYD(存储表中数据的文件)
			xxx.MYI(存储表中索引的文件)
		优点:可被压缩,节省存储空间。并且可以转换为只读表,提高检索效率。
		缺点:不支持事务。

	------------------------------------------------------------------------------------
	上面第8个	
		*************************** 8. row ***************************
		      Engine: InnoDB
		     Support: DEFAULT
		     Comment: Supports transactions, row-level locking, and foreign keys
		Transactions: YES
			      XA: YES
		  Savepoints: YES
			
		优点:支持事务、行级锁、外键等。这种存储引擎数据的安全得到保障。
		
		表的结构存储在xxx.frm文件中
		数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。
		这种InnoDB存储引擎在MySQL数据库崩溃之后提供 自动恢复机制。
		InnoDB支持级联删除和级联更新。
	
	-------------------------------------------------------------------------------------
	上面第6个:
		*************************** 6. row ***************************
		      Engine: MEMORY
		     Support: YES
		     Comment: Hash based, stored in memory, useful for temporary tables
		Transactions: NO
			      XA: NO
		  Savepoints: NO
		
		缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
		优点:查询速度最快。
		以前叫做HEPA引擎。

3、事务(Transaction)

3.1、什么是事务?

	一个事务是一个完整的业务逻辑单元,不可再分。

	比如:银行账户转账,从A账户向B账户转账10000.需要执行两条update语句:
		update t_act set balance = balance - 10000 where actno = 'act-001';
		update t_act set balance = balance + 10000 where actno = 'act-002';
	
	以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。
	(同java中的多线程)

	要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。

MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第1张图片

3.2、和事务相关的语句只有:DML语句。(insert、delete、update)
	为什么?因为它们这三个语句都是和数据库表当中的“数据”相关的。
	事务的存在是为了保证数据的完整性,安全性。

3.3、假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗?
	不需要事务。
	但实际情况不是这样的,通常一个“事儿(事务【业务】)”需要多条DML语句共同联合完成。

3.4、事务的特性?
	事务包括四大特性:ACID
	A: 原子性:事务是最小的工作单元,不可再分。整个事务中的所有操作,必须作为一个单元全部完成(或全部取消)。
	C: 一致性:事务必须保证多条DML语句同时成功或者同时失败。
	I:隔离性:事务A与事务B之间具有隔离。
	D:持久性:在事务完成以后,该事务对数据库所作的更改将持久地保存在数据库之中,并不会被回滚。

3.5、关于事务之间的隔离性
	事务隔离性存在隔离级别,理论上隔离级别包括4个:
		第一级别:【读未提交】(read uncommitted)
			对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
			读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据。
		
		第二级别:【读已提交】(read committed)
			对方事务提交之后的数据我方可以读取到。
			这种隔离级别解决了: 脏读现象没有了。
			读已提交存在的问题是:不可重复读。
		
		第三级别:【可重复读】(repeatable read)
			这种隔离级别解决了:不可重复读问题。
			这种隔离级别存在的问题是:读取到的数据是幻象。
		
		第四级别:【序列化读/串行化读】(serializable) 
			解决了所有问题。
			效率低。事务A和事务B不能并发,只能排队。
		
		oracle数据库默认的隔离级别是:第二级别(读已提交)
		mysql数据库默认的隔离级别是: 第三级别(可重复读)
		
		【脏读】:是指在一个事务处理过程中读取了另一个未提交(commit)的事务中的数据。
		【不可重复读】:是指对于数据库中的某个数据,一个事务内多次查询却返回了不同的数据值,
			     这是由于在事务执行过程中,数据被另一个事务修改并提交了。
		【幻读】:是事务非独立执行时发生的一种现象。
		     例如,事务T1对一个表中 所有行 的某个字段做了从“1”修改为“2”的操作,
		     这时事务T2又插入了一条新的记录,而该字段的值为“1”并且提交给数据库。
		     这时,操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,
		     其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是产生了幻读。

MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第2张图片

3.6、演示事务
	* mysql事务默认情况下是自动提交的。
		(什么是自动提交?只要执行任意一条DML语句则提交一次。)怎么关闭自动提交?start transaction;
	
	* 准备表:
		drop table if exists t_user;
		create table t_user(
			id int primary key auto_increment,
			username varchar(255)
		);
		(其中id 自增)
	
	【演示1】mysql中的事务是支持自动提交的,只要执行一条DML,则提交一次。
		mysql> insert into t_user(username) values('zs');
		Query OK, 1 row affected (0.03 sec)

		mysql> select * from t_user;
		+----+----------+
		| id | username |
		+----+----------+
		|  1 | zs       |
		+----+----------+
		1 row in set (0.00 sec)

		mysql> rollback;
		Query OK, 0 rows affected (0.00 sec)

		mysql> select * from t_user;
		+----+----------+
		| id | username |
		+----+----------+
		|  1 | zs       |
		+----+----------+
		1 row in set (0.00 sec)
		
		这里即使rollback回滚了,数据还是没有变,已经自动提交了
	
	【演示2】使用start transaction;关闭自动提交机制。
		1、开启事务机制(开始)
			mysql> start transaction;
			Query OK, 0 rows affected (0.00 sec)
		
		2、插入一条数据
			mysql> insert into t_user(username) values('lisi');
			Query OK, 1 row affected (0.00 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			|  2 | lisi     |
			+----+----------+
			2 rows in set (0.00 sec)
		
		3、插入第二条数据
			mysql> insert into t_user(username) values('wangwu');
			Query OK, 1 row affected (0.00 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			|  2 | lisi     |
			|  3 | wangwu   |
			+----+----------+
			3 rows in set (0.00 sec)
		
		4、回滚(结束)
			mysql> rollback;
			Query OK, 0 rows affected (0.02 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			+----+----------+
			1 row in set (0.00 sec)

		5、回滚之后,在start transaction之后的所有修改又都没有了,返回最初的样子

	【演示3】
		1、开启事务机制(开始)	
			mysql> start transaction;
			Query OK, 0 rows affected (0.00 sec)
		
		2、连续插入 3 条数据
			mysql> insert into t_user(username) values('wangwu');
			Query OK, 1 row affected (0.00 sec)

			mysql> insert into t_user(username) values('rose');
			Query OK, 1 row affected (0.00 sec)

			mysql> insert into t_user(username) values('jack');
			Query OK, 1 row affected (0.00 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			|  4 | wangwu   |
			|  5 | rose     |
			|  6 | jack     |
			+----+----------+
			4 rows in set (0.00 sec)
		
		3、提交(结束)
			mysql> commit;
			Query OK, 0 rows affected (0.04 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			|  4 | wangwu   |
			|  5 | rose     |
			|  6 | jack     |
			+----+----------+
			4 rows in set (0.00 sec)

			mysql> rollback;
			Query OK, 0 rows affected (0.00 sec)

			mysql> select * from t_user;
			+----+----------+
			| id | username |
			+----+----------+
			|  1 | zs       |
			|  4 | wangwu   |
			|  5 | rose     |
			|  6 | jack     |
			+----+----------+
			4 rows in set (0.00 sec)
		
		4、提交之后,所有的操作都已经完成了,即使回滚,也不会发生变化。

3.7 使用两个事务,演示4个隔离级别
	需要开启两个dos窗口

	查看事务的全局隔离级别:(mysql默认是第三级别:可重复)
			select @@global.tx_isolation;
			+-----------------------+
			| @@global.tx_isolation |
			+-----------------------+
			| REPEATABLE-READ       |
			+-----------------------+

	【演示第1级别】:读未提交(read uncommitted)
		设置 全局事务隔离级别为 读未提交:
		set global transaction isolation level read uncommitted;

	【演示第2级别】:读已提交(read committed)
		set global transaction isolation level read committed;

	【演示第3级别】:可重复读(repeatable read)
		set global transaction isolation level repeatable read;
	
	【演示第4级别】:序列化读/串行化读(serializable) 
		set global transaction isolation level serializable;

MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第3张图片
MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第4张图片
MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第5张图片
MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第6张图片

4、索引

4.1、什么是索引?有什么用?
	索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
	在数据库方面,查询一张表的时候有两种检索方式:
		第一种方式:全表扫描
		第二种方式:根据索引检索(效率很高)

	索引为什么可以提高检索效率呢?
		其实最根本的原理是缩小了扫描的范围。
	
	索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,
	也需要数据库不断的维护,是有维护成本的。
	比如,表中的数据经常被修改,这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。

	添加索引是给某一个字段,或者说某些字段添加索引。

	select ename,sal from emp where ename = 'SMITH';
	当ename字段上没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中的所有值。
	当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位。

4.2、怎么创建索引对象?怎么删除索引对象?查看索引?
	创建索引对象:
		create index 索引名称 on 表名(字段名);
		...
	删除索引对象:
		drop index 索引名称 on 表名;
		...
	查看索引:	
		show index from 表名;
	
	注:有多种方式创建和删除索引

4.3、什么时候考虑给字段添加索引?(满足什么条件)
	数据量庞大。(根据客户的需求,根据线上的环境)
	该字段很少的DML操作。(因为字段进行修改操作,索引也需要维护)
	该字段经常出现在where子句中。(经常根据哪个字段查询)

4.4、注意:主键和具有unique约束的字段自动会添加索引。
	根据主键查询效率较高。尽量根据主键检索。

4.5、查看sql语句的执行计划:
	mysql> explain select ename,sal from emp where sal = 5000;
	+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
	| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
	+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
	|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
	+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
	其中的第4列:type为ALL,表示是全表扫描;第9列rows为14,表示扫描了14行

	给薪资sal字段添加索引:
		create index emp_sal_index on emp(sal);
	
	mysql> explain select ename,sal from emp where sal = 5000;
	+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
	| id | select_type | table | type | possible_keys | key           | key_len | ref   | rows | Extra       |
	+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
	|  1 | SIMPLE      | emp   | ref  | emp_sal_index | emp_sal_index | 9       | const |    1 | Using where |
	+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
	第4列:type为ref,不再是ALL,不是全表扫描了;
	第5列:possible_keys 为 emp_sal_index,就是刚建的索引名称;
	第9类:rows为1,表示扫描了1行就出来了
	
	删除索引:
		drop index emp_sal_index on emp;

4.6、索引底层采用的数据结构是:B + Tree

4.7、索引的实现原理?
	通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,
	最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。
		
		select ename from emp where ename = 'SMITH';
		通过索引转换为:
		select ename from emp where 物理地址 = 0x3;

MySql 数据库 - 第3章:约束、事务、索引、视图、范式_第7张图片

4.8、索引的分类?
	单一索引:给单个字段添加索引
	复合索引: 给多个字段联合起来添加1个索引
	主键索引:主键上会自动添加索引
	唯一索引:有unique约束的字段上会自动添加索引
	....

4.9、索引什么时候失效?
	select ename from emp where ename like '%A%';
	模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。
	......

5、视图(view)

5.1、什么是视图?
	视图是从一个或者几个基本表(或视图)导出的表。它与基本表不同,是一个虚表。
	数据库中只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。
	所以一旦基本表中发生数据变化,从视图中查询出的数据也就随之改变了。
	从这个意义上讲,视图就是一个窗口,通过视图可以看到数据库中自己想了解的数据变化。

	视图有时也被成为“虚拟表”。 
	视图可以被用来从常规表(称为“基表”)或其他视图中查询数据。
	
	相对于从基表中直接获取数据,视图有以下好处:
		访问数据变得简单
		可被用来对不同用户显示不同的表的内容
		用来协助适配表的结构以适应前端现有的应用程序


5.2、怎么创建视图?怎么删除视图?
	create view 视图名 as 查询语句;
	drop view 视图名;

	注意:只有DQL语句(select查询语句)才能以视图对象的方式创建出来。

5.3、对视图进行增删改查,会影响到原表数据。
	可以对视图进行CRUD操作。
	(Create(增) Retrieve(检索) Update(修改) Delete(删除))

5.4、面向视图操作?
	(为了不影响到emp表,这里新建一个表emp_bak)
		create table emp_bak as select * from emp;
	创建视图:
		create view myview1 as select empno,ename,sal from emp_bak;
	通过视图修改原表数据。
		update myview1 set ename='hehe',sal=1 where empno = 7369; 
	通过视图删除原表数据。
		delete from myview1 where empno = 7369; 

5.5、视图的作用?
	作用:视图可以隐藏表的实现细节【面向视图操作】。
	保密级别较高的系统,数据库只对外提供相关的视图,
	java程序员只对视图对象进行CRUD。

6、DBA命令

数据库管理员(Database Administrator,简称DBA)

6.1、将数据库当中的数据导出
	使用mysqldump命令

	在windows的dos命令窗口中执行:(导出整个库)   
		C:\Users\Administrator> mysqldump zt>F:\zt.sql -uroot -p123
	
	在windows的dos命令窗口中执行:(导出指定数据库当中的指定表)
		C:\Users\Administrator> mysqldump zt emp>F:\zt.sql -uroot –p123

6.2、导入数据
	登录MYSQL数据库管理系统之后:
	create database zt;
	use zt;
	source F:\zt.sql

另外还有新建用户、授权、回收权限等等命令。

7、数据库设计三范式(重点,面试常问)

7.1、什么是设计范式?
	设计表的依据。按照这个三范式设计的表不会出现数据冗余。

7.2、三范式都是哪些?

	第一范式:任何一张表都应该有主键(唯一标识、不可重复),并且每一个字段原子性不可再分。

		【不符合1NF的示例】
		学生表:
		--------------------------------------------------------
		sno		  sname		lianxifangshi
		--------------------------------------------------------
		1001		张三		[email protected],13599999
		1002		李四		[email protected],13699999
		1001		王五		[email protected],13488888
		--------------------------------------------------------

		【存在的问题】:
			最后一条记录和第一条重复(不唯一,没有主键)
			联系方式字段可以再分,不是原子性的
		
		【修改后】
		学生表:
		--------------------------------------------------------
		sno(pk)		sname		email		telephone
		----------------------------------------------------------
		1001		张三		[email protected]	13599999
		1002		李四		[email protected]	13699999
		1003		王五		[email protected]	    13488888
		--------------------------------------------------------

		关于第一范式,每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求,
		主要通常采用数值型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。如联系方式,
		为了开发上的便利行可能就采用一个字段了。

	第二范式:建立在第一范式的基础之上,所有非主键字段完全依赖主键,不能产生部分依赖。
		
		【不符合2NF的示例】:
		学生教师表:
		--------------------------------------------------------
		sno(PK)		tno(PK)	sname		tname
		--------------------------------------------------------
		1001		001		张三		王老师
		1002		002		李四		赵老师
		1003		001		王五		王老师
		1001		002		张三		赵老师
		--------------------------------------------------------
		
		【存在的问题】:
			以上虽然确定了主键,但此表会出现大量的冗余。主要涉及到的冗余字段
			为学生姓名sname和教师姓名tname,出现冗余的原因在于:
			sno和tno一起构成主键,但是存在sname部分依赖与主键中的一个sno、
			tname部分依赖与主键中的一个tno,不符合2NF。
		
		【修改后】

		t_student学生表
		---------------------
		sno(pk)		sname
		---------------------
		1001		张三
		1002		李四
		1003		王五
		---------------------

		t_teacher 讲师表
		---------------------
		tno(pk)		tname
		----------------------
		001		王老师
		002		张老师
		---------------------

		t_student_teacher_relation 学生讲师关系表
		---------------------------------------
		id(pk)		sno(fk)		tno(fk)
		---------------------------------------
		1		1001		001
		2		1002		002
		3		1003		001
		4		1001		002
		---------------------------------------
		
		以上是一种典型的“多对多”的设计。
		两个“多”各自建一个表,它们的“联系”建一张表。【多对多?三张表,关系表、两外键】
		多对多:一个教师可以教多个学生,一个学生也可以有多个教师。

		如果一个表符合1NF,并且是单一主键,那么它一定也符合2NF,因为不可能存在部分依赖。


	第三范式:建立在第二范式的基础之上,所有非主键字段直接依赖主键,不能产生传递依赖。
		
		【不符合3NF的示例】:
		---------------------------------------------------------			
		sno(pk)	sname	classno	cname
		---------------------------------------------------------
		101		张三		01		班级1
		102		李四		01		班级1
		103		王五		02		班级2
		104		赵六		02		班级2
		---------------------------------------------------------			

		【存在的问题】:
			班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,
			班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是
			将冗余字段单独拿出来建立表
		
		【修改后】

		班级t_class
		---------------------
		classno(pk)	cname
		---------------------
		01		班级1
		02		班级2
		---------------------

		学生t_student
		-------------------------------------------
		sno(pk)		sname		classno(fk)
		-------------------------------------------
		101		张三		01		
		102		李四		01		
		103		王五		02		
		104		赵六		02
		-------------------------------------------
		以上是一种典型的“一对多”的设计,
		“一”建一张表,“多”建一张表,在多的那张表中添加外键指向一的一方的主键【一对多?两张表,多的表、加外键】
		一对多:一个班级有多个学生,一个学生只属于一个班级

	提醒:在实际的开发中,以满足客户的需求为主,有的时候会拿冗余换执行速度。

7.3、一对一怎么设计?
	一对一,一般来说放到一张表里面,但也有时候需要放到两张表里。
	例如用户表,可能需要拆成两张表:用户登录表、用户详细信息表
	这个用户登录表和用户详细信息表要一一对应。

	一对一设计有两种方案:

	方案一:【主键共享】

		t_user_login  用户登录表
		----------------------------------------
		id(pk)	username password
		----------------------------------------
		1		zs		123
		2		ls		456
		----------------------------------------

		t_user_detail 用户详细信息表
		------------------------------------------
		id(pk+fk)	reallyname	tel	....
		------------------------------------------
		1		张三		1111111111
		2		李四		1111415621
		------------------------------------------


	方案二:【外键唯一】

		t_user_login  用户登录表
		-----------------------------------------
		id(pk)		username	password
		-----------------------------------------
		1			zs			123
		2			ls			456
		-----------------------------------------

		t_user_detail 用户详细信息表
		---------------------------------------------------------------
		id(pk)		realname	tel		userid(fk+unique)....
		---------------------------------------------------------------
		1		张三			1111111111			1
		2		李四			1111415621			2
		---------------------------------------------------------------

总结:			
	【多对多?三张表,关系表、两外键】
	【一对多?两张表,多的表、加外键】
	【一对一?两方案,主键共享、外键唯一】	

传送门

上一章:MySql 数据库 - 第2章:连接查询、子查询、union、limit、数据的增删改
下一章:MySql 数据库 - 34道练习题

你可能感兴趣的:(MySql,数据库)