MySQL PK,FK,视图,索引,引擎总结【12000字概览MySQL】用于查漏补缺
Java养成计划----学习打卡第七十四,五,六天
内容导航
- 主键的注意要点
- 外键约束 foreign key FK
- 父子的顺序
- 外键约束的创建格式
- 存储引擎
- SHOW ENGINES\G
- 常用引擎
- MYISAM引擎
- InnoDB引擎 --- 支持事务保证安全
- MEMORY引擎
- 事务
- 事务提交COMMIT
- 事务回滚ROLLBACK
- 事务的特性ACID
- 事务的隔离性
- 事务的隔离级别
- 查看事务的隔离级别 SELECT @@TRANSACTION_ISOLATION
- 设置事务的隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL ……
- GLOBAL和SESSION和缺省
- 索引
- 索引的实现原理
- 添加索引的情况
- 如何添加索引和删除索引
- 查看是否使用了索引
- 索引失效
- 索引的分类
- 视图view
- 创建视图 CREATE VIEW view_name AS SELECT ……
- 视图的作用
- DBA命令
- 导出数据库到文件
- 数据库设计范式
- 数据库设计第一范式 PK,atomicity
- 数据库第二范式 : 非PK字段完全依赖PK
- 数据库第三范式 : 直接依赖PK,不传递依赖
- MySQL设计原则
- MySQL搜索题
- Q.哪些人的薪水在部门平均薪水之上
- Q.取得公司中所有人的薪水等级平均值
Java(打卡第七十四,五,六天)
主要内容: 主键PK,外键,引擎,事务,索引,视图,数据库范式,MySQL题目
在大概将内容过一遍之后,会详细就一些细节进行分析,当然,还有JDBC的内容,使用JDBC连接MySQL数据库来创建项目,之后的java项目就会运用数据库来进行管理数据
表级约束主要是对于多个字段联合起来添加约束,可以使用表级约束给一个字段添加主键约束,也可以同时添加多个字段,也就是复合主键,复合主键就是将字段联合起来共同识别重复;
在实际看法中,尽量采用单一主键,因为主键是记录的唯一标识,单一主键容易达到,复合主键达到较为复杂
主键的注意要点
主键的数量只能为一个
: 定义中就强调了是唯一标识,所以一个记录,只能有一个主键,可以看一下多个主键的报错
mysql> CREATE TABLE temp(-> name VARCHAR(25) PRIMARY KEY,-> sex CHAR(1) PRIMARY KEY-> );
ERROR 1068 (42000): Multiple primary key defined
ERROR 1068 (42000): Multiple primary key defined ----- 定义多个主键
复合主键也是一个主键,只是约束时将复合的字段看成一个字段操纵
也就是说: 一张表只能一个主键
主键值的类型定长
: 主键值的类型尽量为int,bigint,char等类型 ;不建议使用varchar类型的来做主键,主键值一般是数字,一般是定长的。
主键的分类:自然和业务
- 主键除了按照字段是否联合分为单一主键和业务主键
- 按照主键值类型也可以分为自然主键和业务主键
- 自然主键: 主键是一个自然数,和业务没有关系,没有实际的意义
- 业务主键: 主键值和业务紧密关联,例如银行账号为主键
在实际开发中,使用自然主键较多,因为主键只要做到不重复就可以,不需要由意义,所以world表和film表的主键类型都是自然主键;业务主键不好 ----- 主键和业务关系紧密,一旦业务变动,可能会影响主键值,所以尽量 使用自然主键
AUTO_INCREMENT
: 自然主键自动递增,就不需要专门来进行字段的插入了
mysql> CREATE TABLE t_student(-> ID INT PRIMARY KEY AUTO_INCREMENT,-> name VARCHAR(25)-> );
Query OK, 0 rows affected (0.04 sec)mysql> INSERT INTO t_student (name) VALUES ('Li');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO t_student (name) VALUES ('Di');
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO t_student (name) VALUES ('Linda');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO t_student (name) VALUES ('Wang');
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM t_student;
+----+-------+
| ID | name |
+----+-------+
| 1 | Li |
| 2 | Di |
| 3 | Linda |
| 4 | Wang |
+----+-------+
4 rows in set (0.00 sec)
当加上了auto_increment之后,自然主键INT类型的就可以进行自然的递增了,这个时候插入数据就可以不用再写ID字段了
外键约束 foreign key FK
外键约束
: 一种约束
外键字段
: 使用外键约束修饰的字段
外键值
: 外键字段下的每一个记录
这里引入外键约束,来一个例子,就是设计数据库表来存储学生和其班级的信息
学生信息包含学号和姓名,班级信息包含班级编号和班级名称
- 第一种方案: 设计成一张表来存储t_student
no name classno classname
-----------------------------------------------
1 Lucy 100 英才一班
2 JACK 100 英才一班
3 Wang 100 英才一班
4 Liu 100 英才一班
5 Linda 100 英才一班
6 Zhang 101 英才二班
7 Sun 101 英才二班
8 Ge 101 英才二班
9 Hu 101 英才二班
10 Hong 101 英才二班
这种方案的缺点就是数据大量重复,造成空间的浪费,数据冗余,设计是失败的
- 第二种方案,设计成为两张表
t_class
classno classname
---------------------------
100 英才一班
101 英才二班
t_student
no name
--------------
1 Lucy
2 JACK
3 Wang
4 Liu
5 Linda
6 Zhang
7 Sun
8 Ge
9 Hu
10 Hong
现在的数据重复最少,空间没有浪费,但是有了一个新的问题: 两个表没有任何的关系,没有联结点
之前的emp表和dept表的连接点就是都有deptno,有一个字段可以产生关系,这里没有产生任何关系,那么也就要让它们产生关系,这里也就新加一个字段cno代表班级编号【简单为依据】
no name cno (FK引用t_class种的classno)
----------------------------
1 Lucy 100
2 JACK 100
3 Wang 100
4 Liu 100
5 Linda 100
6 Zhang 101
7 Sun 101
8 Ge 101
9 Hu 101
10 Hong 101
现在两张表就顺利产生关联了,虽然有了重复,单相比第一张表来说重复已经大量减少了
- 背景介绍完了,问题就是如果数据庞大t_student表的cno字段的值可能会写误,在t_class表中没有记录,这样表连接就出现问题? 那么如何避免这种情况
这时,就可以使用外键约束了FK,加了FK,那么该字段值只能为关联字段的值域中的值,不能为其它值
给cno加上外键约束之后,cno就是外键字段,cno字段中的每一个值就是外键值
注意: 添加外键后,两张表就具有了父子关系,被引用的表为父表,引用的表为子表
这里t_class就是父表,t_student就是子表
父子的顺序
先有支持的,才能使用,父给子提供支持
- 创建表,插入数据的顺序为 : 先创建父表,再创建子表
- 删除表,删除数据的顺序 : 先删除子表,再删除父表
外键约束的创建格式
外键约束这里就采用表级约束的方式来创建约束
FOREIGN KEY(col_name) REFERENCES table_name(col_name2)
这里表示的就是col_name和table_name表中的col_name2字段关联,给col_name字段加上了外键
这里可以实现一下上面的表
mysql> CREATE TABLE t_class(-> classno INT PRIMARY KEY,-> classname VARCHAR(25)-> );
Query OK, 0 rows affected (0.04 sec)mysql> CREATE TABLE t_student(-> id INT PRIMARY KEY,-> name VARCHAR(25),-> cno INT,-> FOREIGN KEY(cno) REFERENCES t_class(classno)-> );
Query OK, 0 rows affected (0.04 sec
FOREIGN KEY(cno) REFERENCES t_class(classno) 就是加上外键,同时记得给每一张 表加上主键,没有主键的表没有意义
加了外键约束的表,父表的删除就不能使用TRUNCATE,只能使用DELETE FROM
mysql> TRUNCATE t_class;
ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint (`cfengbase`.`t_student`, CONSTRAINT `t_student_ibfk_1`)
mysql> DELETE FROM t_class;
Query OK, 2 rows affected (0.01 sec)mysql> SELECT * FROM t_class;
Empty set (0.00 sec)
annot truncate a table referenced in a foreign key constraint (cfengbase
.t_student
, CONSTRAINT t_student_ibfk_1
)
这里可以实验一下加了外键约束的效果
mysql> UPDATE t_class SET classname = 'Class one' WHERE classno = 100;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> SELECT * FROM t_class;
+---------+-----------+
| classno | classname |
+---------+-----------+
| 100 | Class one |
| 101 | Class two |
+---------+-----------+
2 rows in set (0.01 sec)mysql> INSERT INTO t_student (id,name,cno) VALUES (1,'Linda',100);
Query OK, 1 row affected (0.02 sec)mysql> INSERT INTO t_student (id,name,cno) VALUES (2,'Wang',102);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`cfengbase`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`))
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (cfengbase
.t_student
, CONSTRAINT t_student_ibfk_1
FOREIGN KEY (cno
) REFERENCES t_class
(classno
))
这里的cno只能为classno值域中的值,所以这里的只能为100或者101,这里102就报错了
- 注意: 外键值可以为NULL,NULL代表啥都没有,没有在值域之外
- 注意: 外键被引用的字段,这里的classno不一定是主键,但是一定要有UNIQUE约束,因为匹配不能匹配多个数据,只能一个
存储引擎
存储引擎是MySQL中的一个术语,Oracle中也有,但是叫法不同
- 存储引擎其实就是一个表存储/组织数据的方式
- 不同的存储引擎,表存储数据的方式不同
那如何给表增加一个存储引擎呢?
首先我们看一下表的详细结构
mysql> SHOW CREATE TABLE t_student\G;
*************************** 1. row ***************************Table: t_student
Create Table: CREATE TABLE `t_student` (`id` int NOT NULL,`name` varchar(25) DEFAULT NULL,`cno` int DEFAULT NULL,PRIMARY KEY (`id`),KEY `cno` (`cno`),CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
这里有一个语句ENGINE = InnoDB,这就是引擎;还有一个是CHARSET ,表明这张表的字符编码方式
在建立表的时候,在最后的小括号‘(’后面可以使用 ENGINE = ……来指定引擎
ENGINE 来指定引擎,CHARSET来指定表的字符编码方式
mysql> CREATE TABLE temp(-> id int PRIMARY KEY AUTO_INCREMENT,-> name VARCHAR(25)-> )ENGINE = InnoDB,CHARSET = utf8b4;
ERROR 1115 (42000): Unknown character set: 'utf8b4'
mysql> CREATE TABLE temp(-> id int PRIMARY KEY AUTO_INCREMENT,-> name VARCHAR(25)-> )ENGINE = InnoDB,CHARSET = utf8mb4;
Query OK, 0 rows affected (0.05 sec)
==MySQL默认的引擎是InnoDB,默认的字符编码方式为utf8mb4
SHOW ENGINES\G
该命令可以查看mysql支持那些存储引擎,也可以将\G去掉
mysql> SHOW ENGINES;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
可以看到有9个存储引擎可以使用,其中InnoDB是默认的,版本不同,支持的情况不同,这里8.0.27支持8个
常用引擎
MYISAM引擎
引擎不同,表的组织方式不同,MYISAM引擎组织的表的特征是
使用三个文件表示每一个表
- 格式文件 ----- 存储表结构的定义(mytable.frm)
- 数据文件 ------ 存储表行的内同(mytable.MYD)
- 索引文件 ----- 存储表上索引 (mytable.MYI):索引就对应书的目录,所以可以缩小扫描范围,提高查询效率; 对一张表来说,只要是主键或者加了UNIQUE的都可以自动创建索引
灵活处理AUTO_INCREMENT修饰的字段
可被转为压缩、只读表来节省存储空间
----- 就是可以节省空间
InnoDB引擎 — 支持事务保证安全
InnoDB是MySQL默认的引擎,其特点是 支持事务,支持数据库崩溃后自动恢复机制,所以其特点就是安全
效率较低以保证数据安全,但是不能压缩,不能转化为只读,不能很好的节省存储空间
它管理的表有以下特点
- 每一个InnoDB表在数据库目录中只有一个文件,为.frm格式文件【也是只有结构】
InnoDB表空间tablespace被用于存储表的内容 表空间tablespace是一个逻辑名称,其中存数据,索引
- 提供用来记录事务性活动的日志文件 ---- 安全
- 用COMMIT提交,ROLLBACK,SAVEPOINT 支持事务处理
- 全ACID兼容
- 在MySQL服务器崩溃后自动恢复
- 多版本和行级锁定
- 支持外键和引用的完整新,包括级联删除和更新
MEMORY引擎
使用MEMORY存储引擎管理的表具有以下特征
- 在数据库目录中,每个表都以.frm格式的文件表示
- 表数据和索引被存储在内存中 ------ 目的就是快,查询快
- 表级锁机制
不能包含TEXT或BLOB字段
不需要和硬盘交互
MEMORY存储引擎之前被称为HELP 引擎, 其优点就是查询效率最高, 缺点就是—极度不安全,数据关机之后消失,因为数据和索引都是内存中
内存是直接抽取, 而从硬盘上取是机械行为
事务
- 之前一直都提到事务保证安全,那么是什么是事务呢?
一个事务其实就是一个完整的业务逻辑,是一个最小的工作单元,不可再分
- 什么是完整的业务逻辑?
比如张三转账给李四3万元 ,那么这个业务分为两个部分 : 张三账户减少3万元; 李四账户加上3万元;这就是一个完整的业务逻辑
上面的操作都是最小的工作单元,不可以再划分,几个操作要么同时成功,要么同时失败,才能保证业务的正确性,比如上面的转账,可以看成两个update语句,这两个语句要么同时成功,要么同时失败,不然账户的余额就不准确了
- 注意 :
只有DML语句才有事务的说法,其他的语句和事务无关,也就是UPDATE,INSERT,DELETE!
因为只有DML语句才是对表中的数据进行增删改,只要操作涉及数据的增删改,那么就要考虑数据的安全的,因为数据的重要性不言而喻
这也就是为什么TRUNCATE不支持事务,DELETE支持事务
- 事务的本质
假设所有的业务只需要一条DML语句就可以完成,那么就可以不存在事务了,正式因为需要多条DML语句配合,所以事务才有存在的价值,其实事务就是一个机制 : 多条【批量】DML语句同时成功或者同时失败
- 事务如何保证多条语句同时成功?
上面提到InnoDB引擎提供了一组用来记录事务性活动的日志文件,
这是什么意思?
比如现在要完成对数据的操纵事务开启
insert
insert
update
update
delete
事务结束在该事务执行的过程中,每一条DML的操作都会记录到事务性活动的日志文件中
在事务执行过程中,可以提交事务,也可以回滚事务
- 事务提交 COMMIT
清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中
清空事务标志着事务结束,并且是一种全都成功的结束
- 事务回滚 ROLLBACK
将之前的所有DML操作撤销,并且清空事务性活动的日志文件
回滚也标志着事务的结束,是全部失败的结束
事务提交COMMIT
mysql默认情况下是默认支持事务提交的,自动提交不符合开发要求,因为业务一般不是一条DML语句解决,所以正常的情况下,需要使用START TRANSACTION来结束默认机制
也就是说,如果不使用TCL,那么Mysql就是每执行一条DML语句就会执行一次事务提交
所以之前的操作,每次执行之后都会显示ok,这时事务日志也就清空了,操作就是不能rollback的
因为rollback只能返回到上次的事务提交点
关闭自动提交机制就可以使用start transaction
START TRANSACTION;mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
事务回滚ROLLBACK
事务回滚也是一个事务的结束,事务就是一个完整的业务逻辑,因为COMMIT也是一个事务的结束,一个事务的开启时START TRANSACTION,结束之后如果不开启事务,又回回到默认的执行一条语句就提交一次
这里完整演示一下
//开始事务和提交事务
mysql> TRUNCATE temp;
Query OK, 0 rows affected (0.06 sec)mysql> SELECT * FROM temp;
Empty set (0.00 sec)mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO temp (name) VALUES ('Linda');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO temp (name) VALUES ('Li');
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO temp (name) VALUES ('La');
Query OK, 1 row affected (0.00 sec)mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM temp;
+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
| 2 | Li |
| 3 | La |
+----+-------+
3 rows in set (0.00 sec)
//开始事务和回滚事务;回到上次的提交点
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO temp (name) VALUES ('Liu');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO temp (name) VALUES ('Ha');
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO temp (name) VALUES ('Lin');
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM temp;
+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
| 2 | Li |
| 3 | La |
| 4 | Liu |
| 5 | Ha |
| 6 | Lin |
+----+-------+
6 rows in set (0.01 sec)mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)mysql> SELECT * FROM temp;
+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
| 2 | Li |
| 3 | La |
+----+-------+
3 rows in set (0.00 sec)
事务的特性ACID
- A 原子性(atomicity) 说明事务是最小的工作单元,不可再分
- C 一致性(consistency) 所有的事务要求,再同一个事务中,所有的操作必须同时成功或者同时失败
- I 隔离性 (isolation) A事务和B事务之间具有一定的隔离 ,A事务和B事务同时操作一张表会被隔离
- D(durability) 持久性 事务是最终结束的一个保障,事务提交,相当于将没有保存到硬盘上的数据保存到硬盘上
事务的隔离性
两个事务同时操作一张表,就类似多个线程操作一个对象,是需要使用手段保证安全的,java中是synchronized对象锁,事务与事务的隔离就像两个教室的墙壁,墙壁越厚,隔离的级别越高
事务的隔离级别
读未提交
: read uncommitted : 事务A可以读取到事务B没有提交到的数据 — 这种隔离级别最低,存在的问题就是 : dirty read 脏读现象 — 读取到了脏数据,这种级别很少使用,一般不采用;因为未提交可能会rollback,那么数据不准确读已提交
: read committed : 事务A只能读取到事务B提交之后的数据,这种隔离级别解决了脏读现象-----但是问题是不可重复读取数据 这种隔离级别是比较真实的数据,每一次读取的数据都是绝对的真实,ORACLE就是默认读已提交- 不可重复读 : 因为事务B在不断提交,比如事务开启后,事务A开始读取的数据是3条,事务B又提交了,数据变多了,第二次读取的就是4条了,3和4不相当,这就是不可重复读
可重复读
: repeatable read : 事务A开启之后,不管开启多久,每次在事务A中读取的数据都是一致的,即使事务B将数据修改,并且提交哦,事务A读取的数据还是没有发生改变,这就是可重复读 ----- 解决了不可重复读,但是存在的问题就是每一次读取到的数据都是幻象,幻影读,不够真实 【因为读取的数据早就改变了】MySQL中默认的事务隔离级别就是这个 ---- 就是读取的A刚开启的数据,A做的修改都读取不到序列化/串行化
:serializable : 类似线程中的synchronized对象锁,也就是事务A开启之后,事务B不能执行,称为事务同步,每一次读取的数据都是最真实的,但是效率最低 ---- 序列化解决了所有的问题,比如脏读,幻影读,表示的是事务排队,不能并发
总结一下就是 : 读未提交 可以读取还未提交的数据 ;读已提交 可以读取已经提交的数据 ;可重复读提交之后也读不到 ,永远读取的都是事务开启时的数据【幻象】 序列化 只能执行一个事务了,另外一个事务不执行
查看事务的隔离级别 SELECT @@TRANSACTION_ISOLATION
要查看事务的隔离级别,那就要使用命令
查看全局的事务隔离级别
SELECT @@GLOBAL.TRANSACTION_ISOLATION;查看会话的事务隔离级别
SELECT @@SESSION.TRANSACTION_ISOLATION;
SELECT @@TRANSACTION_ISOLATION; //查询事务的隔离级别mysql> SELECT @@TRANSACTION_ISOLATION;
+-------------------------+
| @@TRANSACTION_ISOLATION |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT @@GLOBAL.TRANSACTION_ISOLATION;
+--------------------------------+
| @@GLOBAL.TRANSACTION_ISOLATION |
+--------------------------------+
| READ-COMMITTED |
+--------------------------------+
1 row in set (0.00 sec)mysql> SELECT @@SESSION.TRANSACTION_ISOLATION;
+---------------------------------+
| @@SESSION.TRANSACTION_ISOLATION |
+---------------------------------+
| REPEATABLE-READ |
+---------------------------------+
1 row in set (0.00 sec)
设置事务的隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL ……
设置事务的隔离级别就是英语的翻译,加上一个全局global , set global transaction isolation level,设置全局事务隔离级别
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.01 sec)
//这里修改的是全局的事务隔离级别,查询时也要查询全局的
mysql> SELECT @@GLOBAL.TRANSACTION_ISOLATION;
+--------------------------------+
| @@GLOBAL.TRANSACTION_ISOLATION |
+--------------------------------+
| READ-COMMITTED |
+--------------------------------+
1 row in set (0.00 sec)
GLOBAL和SESSION和缺省
这时三个不同的事务隔离级别的应用范围
- SESSION : 会话,表示的是当前session会话【当前cmd窗口】内的所有事务
- GLOBAL: 全局 ,表示的是所有的session 全局的所有的事务 ,但是==已经存在的会话session不受影响】
- 缺省 : 表示的是当前会话session 内的下一个还没有开始的事务【当前cmd窗口的下一个事务】
这里可以分别验证一下几个事务隔离级别
//可以解释为什么刚刚修改了全局的事务之后查看当前的事务隔离级别,发现还是REPEATABLE-READ,这就是因为GLOBAL不会应用到当前存在的session,退出之后重新开启会话发现应用了
mysql> SELECT @@TRANSACTION_ISOLATION;
+-------------------------+
| @@TRANSACTION_ISOLATION |
+-------------------------+
| READ-COMMITTED |
+-------------------------+
1 row in set (0.00 sec)
这里验证事务的隔离性,打开两个cmd窗口,执行多个会话,并行
//验证READ-UNCOMMITTED
事务A 事务B
---------------------------------------------------------
USE cfengbase;USE cfengbase;
START TRANSACTION; START TRANSACTION;
SELECT * FROM temp; -->empty INSERT INTO temp (name) VALUES ('Linda');
SELECT * FROM temp; +----+-------+
| id | name |
+----+-------+
| 1 | Linda |
+----+-------+
1 row in set (0.00 sec)
可以发现事务B只是执行了,还没有提交事务,事务A就可以看到事务B的操作了,但是这样就脏读了,因为事务B如果是ROLLBACK,那么数据就不好
接下来验证read-committed
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)事务A 事务B
-------------------------------------------------------------------------------
USE cfengbase;USE cfengbase;
START TRANSACTION; START TRANSACTION;
SELECT * FROM temp; -->empty INSERT INTO temp (name) VALUES ('Linda');
SELECT * FROM temp; ---> emptyCOMMIT;
SELECT * FROM temp; +----+-------+
| id | name |
+----+-------+
| 1 | Linda |
+----+-------+
1 row in set (0.00 sec)
这里就是只能读取到事务B提交的数据,之前没有提交的时候查询不到,并且要成功的事务
再验证默认的repeatable- read
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)INSERT INTO temp (name) VALUES ('Linda');事务A 事务B
-------------------------------------------------------------------------------
USE cfengbase;USE cfengbase;
START TRANSACTION; START TRANSACTION;
SELECT * FROM temp;+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
+----+-------+INSERT INTO temp (name) VALUES ('Hu');INSERT INTO temp (name) VALUES ('Wang');INSERT INTO temp (name) VALUES ('Liu');SELECT * FROM temp;+----+-------+| id | name |+----+-------+| 1 | Linda || 4 | Hu || 5 | Wang || 6 | Liu |+----+-------+COMMIT;
SELECT * FROM temp; +----+-------+
| id | name |
+----+-------+
| 1 | Linda |
+----+-------+
可以发现事务A能查找到的都是事务B最开始的状态,并没有因为B的提交而发生改变,但是这是幻影读,不知道数据改变了多少
如果并行事务结束了,查找数据
mysql> SELECT * FROM temp;
+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
| 4 | Hu |
| 5 | Wang |
| 6 | Liu |
+----+-------+
4 rows in set (0.01 sec)//因为事务的提交是确确实实修改了数据,所以只是并行的时候查询不到修改而已
这里再验证一下序列化,事务排队serializable
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;事务A 事务B
-------------------------------------------------------------------------------
USE cfengbase;USE cfengbase;
START TRANSACTION; START TRANSACTION; INSERT INTO temp (name) VALUES ('Linda');
SELECT * FROM temp; ---> 光标一直闪动等待COMMIT;+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
+----+-------+
1 row in set (0.00 sec)
需要注意的是,这里的等待时间不能过长,要及时操作
Lock wait timeout exceeded; try restarting transaction 锁等待超时过度
不然就会报错,timeout exceeded 超时 过度的
索引
- 什么是索引?index 位置 ,索引
索引是再数据库表的字段上添加的,是为了提高查询效率存在的一种机制
一张表的一个字段可以添加一个索引,当然和标记约束一样,多个字段也可以联合添加索引,索引相当于一本书的目录,是为了缩小查找范围所存在的一种机制
现实生活中,我们查字典的时候,就可以有两种方式 : 第一种一页一页的查找,也就是全局扫描;第二种是先找到一个大概的范围,之后再进行局域性搜索
Mysql中也是一样,比如之前直接SELECT 的时候,那就是整张表一个一个查询,几千条记录还好,查询时间还是比较少,如果是百万记录,那么一条一条匹配就太慢了,这个时候就需要目录了
SELECT * FROM temp WHERE name = 'Linda';这里执行的时候,会到name字段上进行扫描,因为这里条件就是name
没有添加索引,那么这里就会一条一条搜索整个字段,效率低可以给每一个字段都添加索引,当然,如果数据较少,就不需要索引了
- 索引需要排序吗?
字典的目录是需要排序的,按照字母顺序,只有排序了才可以区间查找;在Mysql这个索引也是需要排序的,这个排序和TreeSet数据结构相同,TreeSet和TreeMap的底层都是自平衡二叉树,在MYSQL中索引是一个b-Tree结构 ----- 遵循左小右大的原则,中序遍历取数据
上面的引擎内容之中,也提到文件组织分别是 结构文件.frm;数据文件和索引文件,MYISAM是分别组织,可以压缩,InnoDB索引和数据在逻辑空间tablespace中,而MEMORY把这两个放在内存中,非常高效但是非常不安全
索引的实现原理
- 首先上面也提到过,添加主键约束或者UNIQUE约束的字段会自动添加索引对象
- 在任何数据库当中,任何一张表的任何一条记录 在硬盘存储上都有一个硬盘的物理存储编号
就类似于地址,这里是物理的地址;每一行数据都是一个记录
- 索引是一个单独的的对象,只是不同的引擎存储在不同的位置,但是不管储存在哪里,索引在mysql中都是以一个树的形式存在 ----- 自平衡二叉树 B-Tree
这里就可以看出来索引就是一个对象,这个对象为一颗b+树,查找时就比较,如果比根节点大就在右子树查找,比根节点小就在左子树查找 【缩小范围,快速定位】
比如查找到之后,因为节点放置着每一行记录的物理地址,马上就可以转化SQL语句了
SELECT * FROM temp WHERE id = 55;
id 是PRIMARY KEY
这里id就有一个索引对象,那么这里就是通过上面的那种b+树的结构来遍历查找
找到后得到物理地址,变化为
SELECT * FROM temp WHERE 物理编号 = ……; 这样直接就取出数据了
所以索引实现的原理就是缩小查找范围,避免全表扫描;表中的字段不会动,但是索引对象会排序
添加索引的情况
什么情况下会添加索引呢? 这里的主要条件就是
数据量十分庞大 — 相对的概念
该字段经常出现在WHERE后面,也就是说经常被当作查询的条件,经常被扫描
该字段很少进行DML操作,因为一旦修改之后就要进行平衡,会重新排序形成b+树
但是不要随意添加索引,因为索引需要维护,太多索引的话可能会影响系统的性能。建议通过主键查询或者UNIQUE修饰字段进行查询,效率较高
如何添加索引和删除索引
- 创建索引的语法格式为
CREATE INDEX 索引名称 ON table_name(col_name);
这里的索引名称可以为tablename_colname_index 【按照下划线命名法】
mysql> CREATE INDEX fruits_name_index ON fruits(fruits_name);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
可以看到这里下面有几个栏目 : records , duplicates ,warnings
- 删除索引的语法格式将CREATE 改为DROP,同时范围限制不用具体到字段,只要到表就可,因为名称指定了索引
DROP INDEX 索引名称 ON table_name;
mysql> DROP INDEX fruits_name_index ON fruits;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
查看是否使用了索引
使用explain命令可以查看
语法格式为
EXPLAIN SELECT ……
这里可以分别看一下主键查找和普通字段查找的区别
mysql> EXPLAIN SELECT * FROM fruits WHERE id = 1002;
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | fruits | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)mysql> SHOW WARNINGS;
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select '1002' AS `id`,'苹果' AS `fruits_name`,'2.8' AS `fruits_price`,'山东' AS `fruits_origin`,'红富士' AS `fruits_remark`,'NULL' AS `fruits_bonus` from `cfengbase`.`fruits` where true |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)mysql> EXPLAIN SELECT * FROM fruits WHERE fruits_price = 2.8;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | fruits | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)mysql> SHOW WARNINGS;
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select `cfengbase`.`fruits`.`id` AS `id`,`cfengbase`.`fruits`.`fruits_name` AS `fruits_name`,`cfengbase`.`fruits`.`fruits_price` AS `fruits_price`,`cfengbase`.`fruits`.`fruits_origin` AS `fruits_origin`,`cfengbase`.`fruits`.`fruits_remark` AS `fruits_remark`,`cfengbase`.`fruits`.`fruits_bonus` AS `fruits_bonus` from `cfengbase`.`fruits` where (`cfengbase`.`fruits`.`fruits_price` = 2.8) |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
如何看呢,EXPLAIN语句表格中的数据
rows代表的就是扫描记录条数,fruits表一共有3条,上面的主键查询的rows为1,下面的普通字段查询rows为1 --索引查询就直接找到地址取出
type也可以看出是否索引,上面的主键有索引,type为const限制,下面的普通字段type为ALL代表全局搜索
filtered代表的过滤的程度,索引查询时100,普通的查询为1/all
上面的key还有possible_keys也可以看出来字段是否是含有键值和索引,mysql索引的底层结构十分复杂,之后会进行分析
现在是先进行大致的分析,后面会在数据库原理中继续深入了解底层
索引失效
不是添加了索引,索引就可以一直使用
- 比如SELECT * FROM emp WHERE ename LIKE ‘%T’; 这个SQL语句只能全表扫描,为什么?
因为这里是模糊查询,并且是以%开始的,底层B+树不能正确匹配%
所以模糊查询时要尽量避免以%开始,匹配先匹配第一个字符,所以不是%开始可以使用索引 ---- 这时优化的策略
可以来查看一下
//普通情况下的查询
mysql> EXPLAIN SELECT * FROM emp WHERE empno = 7934;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
//%开始的模糊查询
mysql> EXPLAIN SELECT * FROM emp WHERE empno LIKE '%4';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 11.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效的第二种情况
使用OR的时可能会失效,如果使用or那么要求两边的字段都要有索引,才会进行索引,如果其中一边有一个字段没有索引,那么另一个字段的索引也就没有用,所以不建议使用OR ----- 优化的策略
这里可以看下这种情况的失效
empno为主键字段,ename为普通字段
mysql> EXPLAIN SELECT * FROM emp WHERE empno = 7934;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)mysql> EXPLAIN SELECT * FROM emp WHERE empno = 7934 OR empno = 7902;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 2 | 100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)mysql> EXPLAIN SELECT * FROM emp WHERE empno = 7934 OR ename = 'FORD';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | PRIMARY | NULL | NULL | NULL | 14 | 16.43 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
可以发现普通一个字段为const,两个字段为range,下面的OR所以失效了,type为ALL
那么如何优化呢? — 可以采用union的方式,union前面的索引查询和下面的查询,效率更高
- 失效的第三种情况,就是复合索引的时候,没有使用左侧的列进行查找
复合索引
: 多个字段联合添加索引
CREATE INDEX 索引名称 ON table_name(col1,col2……);
mysql> CREATE INDEX fruits_nameprice_index ON fruits(fruits_name,fruits_price);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> EXPLAIN SELECT * FROM fruits WHERE fruits_name = '苹果';
+----+-------------+--------+------------+------+------------------------+------------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------------+------------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | fruits | NULL | ref | fruits_nameprice_index | fruits_nameprice_index | 137 | const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+------+------------------------+------------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)mysql> EXPLAIN SELECT * FROM fruits WHERE fruits_price = 2.8;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | fruits | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
这里就是因为树中是先匹配的前面的,所以没有使用左字段就没有用,就像模糊查询使用%开始
- 在WHERE中索引列参与了运算索引也会失效
这里就是如果索引字段参与了运算就 会失效
mysql> DROP INDEX fruits_nameprice_index ON fruits;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> CREATE INDEX fruits_price_index ON fruits(fruits_price);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> EXPLAIN SELECT * FROM fruits WHERE fruits_price = 2.8;
+----+-------------+--------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | fruits | NULL | ref | fruits_price_index | fruits_price_index | 8 | const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)mysql> EXPLAIN SELECT * FROM fruits WHERE fruits_price+1 = 3.8;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | fruits | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
这里可以清楚看到上面的搜索使用了索引,下面+1操作就是全表查询
- 失效的第五种情况 在WHERE中,索引列使用了函数,也会失效
因为这里就是对源字段进行了类似的修改查询,那么就和原来的索引树对应不上了,所以只能走普通的查询
mysql> SELECT * FROM fruits WHERE ROUND(fruits_price,0) = 3;
+------+-------------+--------------+---------------+---------------+--------------+
| id | fruits_name | fruits_price | fruits_origin | fruits_remark | fruits_bonus |
+------+-------------+--------------+---------------+---------------+--------------+
| 1002 | 苹果 | 2.8 | 山东 | 红富士 | NULL |
+------+-------------+--------------+---------------+---------------+--------------+
1 row in set (0.01 sec)mysql> EXPLAIN SELECT * FROM fruits WHERE ROUND(fruits_price,0) = 3;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | fruits | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
这里可以看到使用了ROUND函数之后这里就是查询了所有的数据
当然所索引失效还有其他的情况,比如类型转化之类的
总结一下
索引失效有很多种情况
第一种就是模糊查询%开始和复合索引没有左字段,都是因为匹配不了就失效了
第二种就是使用了OR,OR的两边要都是索引字段才会进行索引
第三种就是对索引字段进行了操作查询 ,比如类型转换,函数,数学运算,原来的索引对象不能匹配,所以就失效了
索引的分类
索引是各种数据库进行优化的重要手段,优化的时候优先考虑的手段就是索引,索引在数据库种分了很多种类
- 单一索引 : 一个字段上添加索引
- 复合索引: 多个字段上添加索引
- 唯一索引 : UNIQUE 约束的字段上添加索引
- 主键索引 : 主键上添加索引
根据索引的结构,所以唯一性比较弱的字段上添加索引用处不大,因为唯一性比较弱,那么数据可能会大量重复,这个时候索引用处不大
越唯一效率越高
视图view
- 什么是视图呢?
视图就是站在不同的角度去看待同一份数据
创建视图 CREATE VIEW view_name AS SELECT ……
这里的view后面只能是DQL语句,也即是data query language 就是SELECT 语句;也就是DQL语句才能以view的形式创建;同时后面不仅可以是单表,也可以是表连接得到的临时
其实之前接触的FROM子查询的时候,当时所提到的临时表就类似一个视图
CREATE VIEW emp_view AS SELECT * FROM emp;
这里可以看一下这个的使用
mysql> CREATE VIEW emp_view AS SELECT * FROM emp LIMIT 5;
Query OK, 0 rows affected (0.01 sec)
- 删除视图 — 就是类似于DROP VIEW view_name;
mysql> DROP VIEW emp_view;
Query OK, 0 rows affected (0.02 sec)
用视图可以做什么呢? 【视图也可以看成一张特殊的表】
- 视图的作用: 可以面向视图对象进行增删查改,但是会导致原表被操作 视图指向了原表的数据
这里就区别于之前的表复制 CREATE TABLE table_name AS SELECT ……
表复制创建一张全新的表,对新表的操作不会影响旧表的数据;但是对视图的操作会影响到原表的数据
所以这里就可以按照普通的对表的操作对视图进行操作
mysql> CREATE VIEW temp_view AS SELECT * FROM temp LIMIT 3;
Query OK, 0 rows affected (0.01 sec)mysql> SELECT * FROM temp_view;
+----+-------+
| id | name |
+----+-------+
| 1 | Linda |
| 4 | Hu |
| 5 | Wang |
+----+-------+
3 rows in set (0.00 sec)mysql> INSERT INTO temp_view (name) VALUES ('LIUzhen');
ERROR 1471 (HY000): The target table temp_view of the INSERT is not insertable-into
mysql> DELETE FROM temp_view WHERE id = 5;
ERROR 1288 (HY000): The target table temp_view of the DELETE is not updatable
这里报错说明不可操作
- 面向视图就是可以方便获取各种的临时的表,并且可以直接在视图中进行操作,这样就可以达到效果;比如在庞大的数据中可以建立一个小视图,或者表连接的时候的视图直接修改,则可以影响原来表的数据
ysql> SHOW TABLES;
+---------------------+
| Tables_in_cfengbase |
+---------------------+
| culture |
| emp |
| fruits |
| fruitsgrade |
| t_class |
| t_person |
| t_student |
| temp |
| temp_view |
+---------------------+
可以看到视图也可以搜索到,所以命名要易于辨认
视图的作用
视图的作用就是简化SQL语句,比如要对表连接的部分进行持续修改,如果原来的方式就会使用FROM子查询,可是问题是,这个语句可能特别特别长,那么就像字段起别名一样,如果多次操作,并且是要确实修改原表的数据,那就不能用复制表,而是使用视图。
这样就可以简化开发了,可以将复杂的SQL语句直接以视图对象的形式创建,利于后期的维护,修改只需要修改一个位置就可以,只需要修改视图所映射的SQL语句
面向视图开发的时候,就是像使用表一样,视图不是存储在内存中,而是存储在硬盘中,不会消失的。视图对应的语句只能是DQL语句,但是视图建立之后可以进行增删改查 CRUD create retrieve(检索) update delete 事务的acid
DBA命令
还有的DCL命令比如GRANT和REVOKE后面再分享,这里分享两个主要的命令
删库跑路,一旦失手删除数据库难道只能cry,所以平时使用数据库要记得备份数据
导出数据库到文件
我们在操作之后可以记得随时将数据库导出到文件之中
mysqldump basename >路径+xx.sql -u user -p password
这里演示将数据库cfengtest导出到D盘Download中
C:\Users\OMEY-PC>mysqldump cfengtest>D:\Download\cfengtest.sql -u root -p
Enter password: ********
//这里就用的root,因为cfeng用户没有权限
这样就算删除数据库了,可以使用SOURCE命令将数据库给导入就可以获取到数据了,创建数据库,之后USE ,use之后再source就可以重新开始操作了
数据库设计范式
数据库设计范式就是数据库表的设计依据,怎么进行数据库表的设计
数据库范式共有3个,之前其实提到过的,设计表的时候,按照范式进行,避免表中数据的冗余,避免空间的浪费
数据库设计第一范式 PK,atomicity
任何一张表必须有主键,每一个字段的原子性不能再分
第一个挺好理解,使用workbench的时候也就提示让第一个字段设计为主键
//下面的表就不合理
学生编号 姓名 联系方式
---------------------------------------------------
1001 张三 zhagnsan@liu.cn,1787823978
1002 李素 lisu@liu.cn,235589768这里的问题是没有主键 ,第二个就是联系方式字段不具有原子性,可以分为邮箱和qq学生编号(PK) 姓名 邮箱 QQ
---------------------------------------------------
1001 张三 zhagnsan@liu.cn 1787823978
1002 李素 lisu@liu.cn 235589768
数据库第二范式 : 非PK字段完全依赖PK
建立在第一范式的基础上,就是要求所有的非主键字段完全依赖主键,不要产生部分依赖
//下面的表也不合理
no name classno classname
-----------------------------------------------
1 Lucy 100 英才一班
2 JACK 100 英才一班
3 Wang 100 英才一班
4 Liu 100 英才一班
5 Linda 100 英才一班
6 Zhang 101 英才二班
7 Sun 101 英才二班
8 Ge 101 英才二班
9 Hu 101 英才二班
10 Hong 101 英才二班首先是没有主键,这里可以对no 和 classno设计复合主键;这里是多对一的关系;这样设计之后 name依赖的是no,classname依赖的是classno;都是部分依赖主键,所以不满足数据库第二范式,需要修改
直接变为两张表,FK就可以
如果是对对多的关系,那么就建立3张表来解决问题
多对多,三张表;关系表,两个外键
假设上面的学生和班级不是多对一,而是多对多,那么表的设计就是
t_student
---------------
no (PK) namet_class
-----------------------
classno(PK) classnamet_association 关系表
-------------------------
id(自然PK) 学生编号no(FK t_student no) 教师编号(FK)
普通的多对一就两张表,让其中简单的字段连接就可以外键
数据库第三范式 : 直接依赖PK,不传递依赖
建立在第二范式的基础上,要求所有的非主键字段直接依赖主键,而不是传递依赖
这里可以用二中的数据
//下面的表也不合理
no(PK) name classno classname
-----------------------------------------------
1 Lucy 100 英才一班
2 JACK 100 英才一班
3 Wang 100 英才一班
4 Liu 100 英才一班
5 Linda 100 英才一班
6 Zhang 101 英才二班
7 Sun 101 英才二班
8 Ge 101 英才二班
9 Hu 101 英才二班
10 Hong 101 英才二班//这里是单一主键,一对多关系,满足第一范式和第二范式
但是不满足第三范式,以为classname依赖classno,classno依赖no(PK)怎么设计一对多
拆分成两张表 --- 一张表是no为主键,一张表是classno为主键
也就是上面讲外键的时候分析的数据
一对多,两张表,多的表加外键
- 总结一下就是
一对一设计 : 一张表可能字段太多,太庞大,需要拆分表,那么select可能不好使用,那么这个时候就建议拆分成两张表 ,这个时候拆分的时候第一部分的主键字段拿来当外键字段并加唯一性约束
一对一: 外键唯一
多对一 : 两张表,多的表加外键
多对多: 三张表,关系表两个外键
MySQL设计原则
上面说的范式只是一个大概的参考,实际开发中不一定要照搬,实际和理论是有偏差的,最终的目的是满足客户的要求
冗余的表虽然耗费内存,但是优点就是查询的效率高一些,冗余换速度,因为可以减少表的连接次数,并且对于开发人员来说,SQL语句的编写会降低
MySQL搜索题
之前已经做过第一个题目了,就一个FROM的子查询和连接查询就可以解决问题
Q.哪些人的薪水在部门平均薪水之上
这里还是用FROM的子查询和连接查询,查询条件就是deptno相等并且大于平均薪资
mysql> SELECT e.ename,e.sal,e.deptno,t.avgsal-> FROM-> (SELECT deptno,AVG(sal) avgsal FROM emp GROUP BY deptno) t-> JOIN-> emp e-> ON-> (e.deptno = t.deptno) AND (e.sal > t.avgsal);
+-------+---------+--------+-------------+
| ename | sal | deptno | avgsal |
+-------+---------+--------+-------------+
| ALLEN | 1600.00 | 30 | 1566.666667 |
| JONES | 2975.00 | 20 | 2175.000000 |
| BLANK | 2850.00 | 30 | 1566.666667 |
| SCOTT | 3000.00 | 20 | 2175.000000 |
| KING | 5000.00 | 10 | 2916.666667 |
| FORD | 3000.00 | 20 | 2175.000000 |
+-------+---------+--------+-------------+
6 rows in set (0.00 sec)
Q.取得公司中所有人的薪水等级平均值
这里注意临时表要起别名
mysql> SELECT-> AVG(grade)-> FROM-> (SELECT g.grade FROM emp e JOIN salgrade g ON e.sal BETWEEN g.losal AND g.hisal);
ERROR 1248 (42000): Every derived table must have its own alias
Every derived table must have its own alias 每一个衍生表必须有它自己的别名
所以要给临时表起别名
mysql> SELECT AVG(t.grade) FROM (SELECT g.grade FROM emp e JOIN salgrade g ON e.sal BETWEEN g.losal AND g.hisal) t;
+--------------+
| AVG(t.grade) |
+--------------+
| 2.8571 |
+--------------+
1 row in set (0.01 sec)
之后的会补上~已经12000字了
MySQL PK,FK,视图,索引,引擎总结【12000字概览MySQL】用于查漏补缺相关推荐
- mysql 是如何利用索引的_10 分钟搞明白 MySQL 是如何利用索引的!
一.前言 在MySQL中进行SQL优化的时候,经常会在一些情况下,对MySQL能否利用索引有一些迷惑. 譬如: MySQL 在遇到范围查询条件的时候就停止匹配了,那么到底是哪些范围条件? MySQL ...
- 唯一约束判断 细微差mysql别_50道MySQL面试题,查漏补缺看你掌握多少?(附答案解析)...
1.MySQL 中有哪几种锁? 1.表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最 高,并发度最低. 2.行级锁:开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲突的概率最 低 ...
- MySQL基础查漏补缺
1. char 与 varchar ? char 定义的是定长的字符串类型,比如电话号码.性别等字段,如果插入的数据长度小于定长就会以unicode编码补缺'\u0000'(我们看着是空格),大于定长 ...
- mysql oracle创建视图索引吗_Oracle视图,索引,序列
什么是视图[View] (1)视图是一种虚表 (2)视图建立在已有表的基础上, 视图赖以建立的这些表称为基表 (3)向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELE ...
- mysql支持事务的存储引擎_MySQL基础(三)【MySQL事务与存储引擎】
3.1-数据库事务 什么是事务 一系列有序的数据库操作: 要么全部成功 要么全部回退到操作前的状态 中间状态对其他连接不可见 事务的基本操作: 基本操作 说明 start transaction 开始 ...
- Mysql查漏补缺笔记
目录 查漏补缺笔记2019/05/19 文件格式后缀 丢失修改,脏读,不可重复读 超键,候选键,主键 构S(Stmcture)/完整性I(Integrity)/数据操纵M(Malippulation) ...
- rds mysql 视图 索引_数据库 视图 索引
SQL2K数据库开发二十二之索引操作在视图上创建索引 1.在企业管理器中,右击要创建索引的视图,在弹出的菜单中选择"设计视图"命令进入视图设计器. 2.在视图设计器中显示了视图所包 ...
- mysql表的视图怎么建立_MySQL如何创建视图
基本语法 可以使用 CREATE VIEW 语句来创建视图. 语法格式如下: CREATE VIEW AS 语法说明如下. :指定视图的名称.该名称在数据库中必须是唯一的,不能与其他表或视图同名. : ...
- mysql中的视图_分布式 | DBLE 是如何实现视图的?
作者:苏仕祥 浩鲸科技 PaaS 组件团队成员,长期从事分库分表中间件的相关解决方案工作,热爱技术,乐于分享. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并 ...
最新文章
- Java源码下载和阅读(JDK1.8/Java 11)
- 求n!中含有某个因子个数的方法
- Linux安装pecl和pear
- 页面重构-让我们的布局自适应
- 信息学奥赛一本通(1174:大整数乘法)
- C#代码规范化(代码风格化)的几个函数
- Linux系统特殊符号的作用
- Day4:html和css
- 2019年上海春运志愿服务启动 3000余名志愿者守护归乡路
- SQL:postgresql一条sql语句查询多个count
- centos系统盘满了 如何清理_如何拯救爆满的磁盘空间?这款 8 M小软件比 SpaceSniffer 更快更简单,支持中文。...
- 【绿豆识别】基于matlab形态学绿豆计数【含Matlab源码 1113期】
- 开源的魔兽世界参考架构——mangos--网络游戏引擎BigWorld 服务器介绍
- ISBN书号怎么查询
- 王者荣耀英雄分析--孙悟空
- UVM基础-Sequence、Sequencer(二)
- IFS认证辅导,国际食品企业认证BRC和IFS起源和发展
- win10此计算机未连接到网络,win10提示无法连接到此网络是怎么回事 怎么办
- 2020美赛F奖论文(四):模拟退火算法驱动的结构策略设计
- (转)VC++之系统控制之设置显示系统当前时间