- 1、初识数据库
- 1.1、什么是数据库
- 1.2、数据库分类
- 1.3、相关概念
- 1.4、基本命令
- 2、操作数据库
- 2.1、操作数据库
- 2.2、数据库的数据类型
- null
- 2.3、数据库的字段属性
- UnSigned
- ZEROFILL
- Auto_InCrement
- NULL 和 NOT NULL
- DEFAULT
- 2.4、创建数据库表
- 2.5、数据库存储引擎
- 2.6、修改数据库
- 3、MySQL数据管理
- 3.1、外键
- 创建外键的方法
- MySQL报错cannot add foreign key constraint解决方法
- 3.2、DML语言
- 1. 添加 insert
- 2. 修改 update
- 3. 删除 delete
- 4、DQL查询数据
- 4.1、基础查询
- 4.2、条件查询
- 4.3、分组查询
- 4.4、连接查询
- 4.5、排序和分页
- 排序
- 分页
- 4.6、子查询
- 4.7、MySQL函数
- 1. 常用函数
- 2. 聚合函数
- 5、数据库级别的MD5加密
- 6、事务
- 6.1、事务原则:ACID
- 原子性
- 一致性(Consistency)
- 持久性(Durability)
- 隔离性(Isolation)
- 6.2、事务并发导致的问题
- 6.3、隔离级别
- 6.4、事务演示
- 案列1:脏读演示,读到其他事务未提交的数据
- 6.5、执行事务的过程
- 7、索引
- 7.1、索引的分类
- 主键索引(PRIMARY KEY)
- 普通索引(KEY / INDEX)
- 唯一索引(UNIQUE KEY)
- 全文索引(FULLText)
- 7.2、索引的使用
- 1. 索引的创建
- 2. 索引的删除
- 3. 显示索引信息
- 4. explain分析sql执行的情况
- 7.3、测试索引
- 测试查询速度
- 7.4、索引原则
- 8、explain关键字
- explain 执行计划包含的信息
- id
- select_type
- type
- possible_keys
- key
- key_len
- ref
- rows
- Extra
- 9、权限管理和备份
- 9.1、用户管理
- 9.2、数据库备份
- 10、三大范式
- 三大范式的通俗理解
- 第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项
- 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
- 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
- 11、MyISAM和InnoDB区别
数据库:DB(DataBase)
概念:数据仓库,软件,安装在操作系统之上
作用:存储数据,管理数据
1.2、数据库分类关系型数据库:SQL(Structured Query Language)
- MySQL、Oracle、Sql Server、DB2、SQLlite
- 通过表和表之间,行和列之间的关系进行数据的存储
- 通过外键关联来建立表与表之间的关系
非关系型数据库:NoSQL(Not Only SQL)
- Redis、MongoDB
- 指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定
DBMS(数据库管理系统)
- 数据库的管理软件,科学有效的管理、维护和获取我们的数据
- MySQL就是数据库管理系统
所有的语句都要以分号结尾
show databases; --查看当前所有的数据库
use 数据库名; --打开指定的数据库
show tables; --查看所有的表
describe/desc 表名; --显示表的信息
create database 数据库名; --创建一个数据库
exit --退出连接
-- --单行注释
# --单行注释
/*...*/ --多行注释
2、操作数据库
2.1、操作数据库
1、创建数据库
CREATE DATABASE [IF NOT EXISTS] 数据库名;
2、删除数据库
DROP DATABASE [if EXISTS] 数据库名;
3、使用数据库
--如果表名或者字段名是特殊字符,则需要带``
use 数据库名;
4、查看数据库
SHOW DATABASES;
2.2、数据库的数据类型
- 没有值,未知
- 不要使用NULL值进行计算
无符号的
声明了该列不能为负数
ZEROFILL0填充的
不足位数的用0来填充 , 如int(3),5则为005
Auto_InCrement通常理解为自增,自动在上一条记录的基础上默认+1
通常用来设计唯一的主键,必须是整数类型
可定义起始值和步长
- 当前表设置步长(AUTO_INCREMENT=100) : 只影响当前表
- SET @@auto_increment_increment=5 ; 影响所有使用自增的表(全局)
默认为NULL , 即没有插入该列的数值
如果设置为NOT NULL , 则该列必须有值
DEFAULT默认的
用于设置默认值
例如,性别字段,默认为"男" , 否则为 “女” ; 若无指定该列的值 , 则默认值为"男"的值
拓展:每一个表,都必须存在以下五个字段: 名称描述id主键version乐观锁deleted_at伪删除created_at创建时间updated_at修改时间 2.4、创建数据库表CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
注意点:
-
表名和字段尽量使用``括起来
-
AUTO_INCREMENT 代表自增
-
所有的语句后面加逗号,最后一个不加
-
字符串使用单引号括起来
-
主键的声明一般放在最后,便于查看
-
不设置字符集编码的话,会使用MySQL默认的字符集编码Latin1,不支持中文,可以在my.ini里修改
格式:
CREATE TABLE IF NOT EXISTS `student`(
'字段名' 列类型 [属性] [索引] [注释],
'字段名' 列类型 [属性] [索引] [注释],
......
'字段名' 列类型 [属性] [索引] [注释]
)[表的类型][字符集设置][注释]
# 常用命令:
SHOW CREATE DATABASE 数据库名;-- 查看创建数据库的语句
SHOW CREATE TABLE 表名;-- 查看表的定义语句
DESC 表名;-- 显示表的具体结构
2.5、数据库存储引擎
INNODB
默认使用,安全性高,支持事务的处理,多表多用户操作
MYISAM
早些年使用,节约空间,速度较快
MYISAMINNODB事务支持不支持支持数据行锁定不支持支持外键约束不支持支持全文索引支持不支持表空间大小较小较大,约为2倍数据库文件存在的物理空间位置:
MySQL数据表以文件方式存放在磁盘中
包括表文件 , 数据文件 , 以及数据库的选项文件
位置 : Mysql安装目录\data\(目录名对应数据库名 , 该目录下文件名对应数据表)
MySQL在文件引擎上区别:
INNODB数据库文件类型就包括**.frm**、.ibd以及在上一级目录的ibdata1文件
MYISAM存储引擎,数据库文件类型就包括
.frm:表结构定义文件 .MYD:数据文件 .MYI:索引文件
2.6、修改数据库修改表名 : ALTER TABLE 旧表名 RENAME AS 新表名
添加字段 : ALTER TABLE 表名 ADD字段名 列属性[属性]
修改字段 :
ALTER TABLE 表名 MODIFY 字段名 列类型[属性]
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性[属性]
删除字段 :ALTER TABLE 表名 DROP 字段名
-- 修改表名
-- ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS teachers;
-- 增加表的字段
-- ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE teachers ADD age INT(11);
-- 修改表的字段(重命名,修改约束)
-- ALTER TABLE 表名 MODIFY 字段名 [列属性];
ALTER TABLE teachers MODIFY age VARCHAR(11);-- 修改约束
-- ALTER TABLE 表名 CHANGE 旧名字 新名字 [列属性];
ALTER TABLE teachers CHANGE age age1 INT(1);-- 字段重命名
-- 删除表的字段
-- ALTER TABLE 表名 DROP 字段名
ALTER TABLE teachers DROP age1;
语法:DROP TABLE [IF EXISTS] 表名
IF EXISTS为可选 , 判断是否存在该数据表
如删除不存在的数据表会抛出错误
-- 删除表(如果存在再删除)
DROP TABLE IF EXISTS teachers;
所有的创建和删除尽量加上判断,以免报错~
3、MySQL数据管理 3.1、外键如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键。由此可见,外键表示了两个关系之间的相关联系。以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表。
在实际操作中,将一个表的值放入第二个表来表示关联,所使用的值是第一个表的主键值(在必要时可包括复合主键值)。此时,第二个表中保存这些值的属性称为外键(foreign key)。
外键作用:
保持数据一致性,完整性,主要目的是控制存储在外键表中的数据,约束。使两张表形成关联,外键只能引用外表中的列的值或使用空值。
目标:学生表(student)的gradeid字段 要去引用年级表(grade)的 gradeid字段创建外键
方式一:在创建表的时候增加约束
-- 创建年级表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL COMMENT '年级id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年纪名称',
PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
/*
1. 定义外键key
2. 给外键添加约束(执行引用)references 引用
*/
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
PRIMARY KEY (`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_student_grade` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表)
/*
1. 定义外键key
2. 给外键添加约束(执行引用)references 引用
*/
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 创建表的时候没有外键关系
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);
-- 创建年级表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL COMMENT '年级id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年纪名称',
PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
创建顺序
以上的操作都是物理外键,数据库级别的外键,不建议使用!避免数据库过多造成困扰!
最佳实践
数据库就是用来单纯的表,只用来存数据,只有行(数据)和列(属性) 我们想使用多张表的数据,使用外键,用程序去实现
创建外键的方法首先谈一下外键的作用,一是节省空间,二是约束含外键的列中的值,含外键列的值必须为参考列中的id。
创建数据表时,创建外键方法
create table department(
id bigint auto_increment primary key,
title char(15)
)engine=innodb default charset=utf8;
create table userinfo(
uid bigint auto_increment primary key, # 创建列uid ,bigint类型,自增,主键
name varchar(32), # 创建列name varchar类型,32位
department_id bigint,
xx_id int,
CONSTRAINT fk_userinfo_department foreign key (department_id) references department(id) #创建外键
)engine=innodb default charset=utf8;
创建外键语法如下
constraint fk_userinfo_department foreign key (department_id) references department(id)
constraint 外键名字 foreign key (添加外键的列名)references 参考表的名称(参考表中的列名)
外键也可以是两列,但是前提条件是,被参考的表的两列均是主键
CREATE TABLE t5 (
nid int(11) NOT NULL AUTO_INCREMENT,
pid int(11) not NULL,
num int(11),
primary key(nid,pid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table t6(
id int auto_increment primary key,
name char(10),
id1 int,
id2 int,
CONSTRAINT fk_t5_t6 foreign key (id1,id2) REFERENCES t5(nid,pid)
)engine=innodb default charset=utf8;
MySQL报错cannot add foreign key constraint解决方法
原因分析:
创建外键错误的原因大概有一下几个原因:
1、关联的两个字段的字段的类型不一致 2、设置外键删除时set null 3、两张表的引擎不一致
3.2、DML语言数据库的意义:数据存储,数据管理
Data Manipulation Luaguge:数据操作语言
1. 添加 insert-- 普通用法
INSERT INTO `student`(`name`) VALUES ('zsr');
-- 插入多条数据
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('zsr','200024','男'),('gcc','000421','女');
-- 省略字段
INSERT INTO `student` VALUES (5,'Bareth','123456','男','2000-02-04','武汉','1412@qq.com',1);
语法:
INSERT INTO 表名([字段1,字段2..])VALUES('值1','值2'..),[('值1','值2'..)..];
注意:
1、字段和字段之间使用英文逗号隔开 2、字段是可以省略的,但是值必须完整且一一对应 3、可以同时插入多条数据,VALUES后面的值需要使用逗号隔开
2. 修改 update-- 修改学员名字,指定条件
UPDATE `student` SET `name`='zsr204' WHERE id=1;
-- 不指定条件的情况,会改动所有表
UPDATE `student` SET `name`='zsr204';
-- 修改多个属性
UPDATE `student` SET `name`='zsr',`address`='湖北' WHERE id=1;
-- 通过多个条件定位数据
UPDATE `student` SET `name`='zsr204' WHERE `name`='zsr' AND `pwd`='200024';
语法:
UPDATE 表名 SET 字段1=值1,[字段2=值2...] WHERE 条件[];
关于WHERE条件语句:
操作符含义=等于或!=不等于>大于=95 AND `StudentResult`=95 && `StudentResult`90; 4.4、连接查询-- 查询学员所属的年级(学号,学生姓名,年级名称)
SELECT `StudentNo`,`StudentName`,`GradeName`
FROM student s
INNER JOIN grade g
ON s.GradeID=g.GradeID;
-- 查询科目所属的年级
SELECT `SubjectName`,`GradeName`
FROM `subject` s
INNER JOIN `grade` g
ON s.GradeID=g.GradeID;
-- 查询列参加程序设计考试的同学信息(学号,姓名,科目名,分数)
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s
INNER JOIN result r
on s.StudentNo=r.StudentNo
INNER JOIN `subject` sub
on r.SubjectNo=sub.SubjectNo
where SubjectName='课程设计';
自连接
自己的表和自己的表连接,核心:一张表拆为两张一样的表即可
-- 创建一个表
CREATE TABLE `course` (
`courseid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '课程id',
`pid` INT(10) NOT NULL COMMENT '父课程id',
`courseName` VARCHAR(50) NOT NULL COMMENT '课程名',
PRIMARY KEY (`courseid`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
-- 插入数据
INSERT INTO `course` (`courseid`, `pid`, `courseName`)
VALUES('2','1','信息技术'),
('3','1','软件开发'),
('4','3','数据库'),
('5','1','美术设计'),
('6','3','web开发'),
('7','5','ps技术'),
('8','2','办公信息');
得到下表:
将该表进行拆分:
操作:查询父类对应的子类关系
父类子类信息技术 2办公信息 4软件开发 3数据库 4、web开发 6美术设计 5ps技术 7SELECT a.`courseid` AS '父课程',b.`courseid` AS '子课程'
FROM course AS a,course AS b
WHERE a.`courseid`=b.`pid`;
语法:
select 查询列表
from 表
where 筛选条件
order by 排序列表 asc/desc
order by 的位置一般放在查询语句的最后(除limit语句之外)
SELECT `StudentNo`,`StudentName`,`GradeName`
FROM student s
INNER JOIN grade g
ON s.GradeID=g.GradeID
ORDER BY `StudentNo` DESC;
分页
语法:
select 查询列表
from 表
limit offset,pagesize;
offset 代表的是起始的条目索引,默认从0开始 size 代表的是显示的条目数 offset=(n-1)*pagesize
-- 第一页 limit 0 5
-- 第二页 limit 5,5
-- 第三页 limit 10,5
-- 第n页 limit (n-1)*pagesize,pagesize
-- pagesize:当前页面大小
-- (n-1)*pagesize:起始值
-- n:当前页面
-- 数据总数/页面大小=总页面数
-- limit n 表示从0到n的页面
4.6、子查询
本质:在 where子句中嵌套一个子查询语句
-- 查询‘课程设计’的所有考试结果(学号,科目编号,成绩)降序排列
-- 方式一:使用连接查询
SELECT `StudentNo`,r.`SubjectNo`,`StudentResult`
FROM result r
INNER JOIN `subject` s
on r.StudentNo=s.SubjectNo
WHERE SubjectName='课程设计'
ORDER BY StudentResult DESC;
-- 方式二:使用子查询(由里到外)
SELECT StudentNo,SubjectNo,StudentResult
from result
WHERE SubjectNo=(
SELECT SubjectNo FROM `subject`
WHERE SubjectName='课程设计'
)
4.7、MySQL函数
1. 常用函数
-- 数学运算
SELECT ABS(-8); -- 绝对值
SELECT CEIL(5.1); -- 向上取整
SELECT CEILING(5.1); -- 向上取整
SELECT RAND(); -- 返回0~1之间的一个随机数
SELECT SIGN(-10); -- 返回一个数的符号;0返回0;正数返回1;负数返回-1
-- 字符串函数
SELECT CHAR_LENGTH('我喜欢你'); -- 字符串长度
SELECT CONCAT('我','喜欢','你'); -- 拼接字符串
SELECT INSERT('我喜欢',1,1,'超级') -- INSERT(str,pos,len,newstr) 从str的pos位置开始替换为长度为len的newstr
SELECT UPPER('zsr'); -- 转大写
SELECT LOWER('ZSR'); -- 转小写
SELECT INSTR('zsrs','s'); -- 返回第一次出现字串索引的位置
SELECT REPLACE('加油就能胜利','加油','坚持'); -- 替换出现的指定字符串
SELECT SUBSTR('坚持就是胜利',3,6); -- 返回指定的字符串(源字符串,截取位置,截取长度)
SELECT REVERSE('rsz'); -- 反转字符串
-- 时间日期函数
SELECT CURRENT_DATE(); -- 获取当前日期
SELECT CURDATE(); -- 获取当前日期
SELECT now(); -- 获取当前时间
SELECT LOCALTIME(); -- 本地时间
SELECT SYSDATE(); -- 系统时间
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());
-- 系统信息
SELECT SYSTEM_USER();
SELECT USER();
SELECT VERSION();
2. 聚合函数
函数描述max最大值min最小值sum和avg平均值count计算个数
SELECT COUNT(StudentName) FROM student;
SELECT COUNT(*) FROM student;
SELECT COUNT(1) FROM student;
SELECT SUM(`StudentResult`) FROM result;
SELECT AVG(`StudentResult`) FROM result;
SELECT MAX(`StudentResult`) FROM result;
SELECT MIN(`StudentResult`) FROM result;
select count(*)和select count(1)的区别
1、 一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的
2、 假如表沒有主键(Primary key), 那么count(1)比count(*)快,
3、 如果有主键的話,那主键作为count的条件时候count(主键)最快
4、 如果你的表只有一个字段的话那count(*)就是最快的
5、count(*) 跟 count(1) 的结果一样,都包括对NULL的统计,而count(column) 是不包括NULL的统计
5、数据库级别的MD5加密MD5信息摘要算法(MD5 Message-Digest Algorithm)
MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性
MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值
CREATE TABLE `testMD5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET =utf8;
-- 明文密码
INSERT INTO `testMD5` VALUES(1,'zsr','200024'),
(2,'gcc','000421'),(3,'bareth','123456');
-- 加密
UPDATE `testMD5` SET `pwd`=MD5(pwd) WHE RE id=1;
UPDATE `testMD5` SET `pwd`=MD5(pwd); -- 加密全部的密码
-- 插入的时候加密
INSERT INTO `testMD5` VALUES(4,'barry',MD5('654321'));
-- 如何校验:将用户传递进来的密码,进行MD5加密,然后对比加密后的值
SELECT * FROM `testMD5` WHERE `name`='barry' AND `pwd`=MD5('654321');
要么都成功,要么都失败。
将一组SQL放在一个批次中去执行
例如银行转账:
只有A转账成功且B成功到账,该事件才算结束,如果一方不成功,则该事务不成功
6.1、事务原则:ACID 名称描述 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 一致性(Consistency)事务前后数据的完整性必须保持一致。 隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。 持久性(Durability)事务一旦被提交则不可逆,被持久化到数据库中,接下来即使数据库发生故障也不应该对其有任何影响 原子性针对同一个事务 这个过程包含两个步骤
A: 800 - 200 = 600 B: 200 + 200 = 400
原子性表示,这两个步骤一起成功,或者一起失败,不能只发生其中一个动作。
一致性(Consistency)针对一个事务操作前与操作后的状态一致 操作前A:800,B:200 操作后A:600,B:400
一致性表示事务完成后,符合逻辑运算
持久性(Durability)表示事务结束后的数据不随着外界原因导致数据丢失
操作前A:800,B:200 操作后A:600,B:400
如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:800,B:200
如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:600,B:400
隔离性(Isolation)针对多个用户同时操作,主要是排除其他事务对本次事务的影响 事务一)A向B转账200 事务二)C向B转账100
两个事务同时进行,其中一个事务读取到另外一个事务还没有提交的数据,执行步骤如图所示,按照数字顺序执行
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别
读未提交:
一个事务读取到其他事务未提交的数据;这种隔离级别下,查询不会加锁,一致性最差,会产生脏读、不可重复读、幻读的问题
读已提交:
一个事务只能读取到其他事务已经提交的数据;该隔离级别避免了脏读问题的产生,但是不可重复读和幻读的问题仍然存在;
读提交事务隔离级别是大多数流行数据库的默认事务隔离级别,比如 Oracle,但是不是 MySQL 的默认隔离界别
可重复读:
事务在执行过程中可以读取到其他事务已提交的新插入的数据,但是不能读取其他事务对数据的修改,也就是说多次读取同一记录的结果相同;该个里级别避免了脏读、不可重复度的问题,但是仍然无法避免幻读的问题
可重复读是MySQL默认的隔离级别
串行化:
事务串行化执行,事务只能一个接着一个地执行,、,并且在执行过程中完全看不到其他事务对数据所做的更新;缺点是并发能力差,最严格的事务隔离,完全符合ACID原则,但是对性能影响比较大
事务隔离级别脏读不可重复读幻读读未提交(read-uncommitted)是是是读已提交(read-committed)否是是可重复读(repeatable-read)否否是串行化(serializable)否否否四种隔离级别设置
数据库
set transaction isolation level 设置事务隔离级别
select @@tx_isolation 查询当前事务隔离级别
设置描述Serializable可避免脏读、不可重复读、虚读情况的发生。(串行化)Repeatable read可避免脏读、不可重复读情况的发生。(可重复读)Read committed可避免脏读情况发生(读已提交)。Read uncommitted最低级别,以上情况均无法保证。(读未提交) REPEATABLE-READ 此为默认事务隔离级别。
进入MySQL
mysql -h localhost -uroot -p
数据测试准备
create database db_test;
use db_test;
CREATE TABLE `amount` (
`id` varchar(10) NULL,
`money` numeric NULL
);
insert into amount(id,money) values('A', 800);
insert into amount(id,money) values('B', 200);
insert into amount(id,money) values('C', 1000);
insert into amount(id,money) values('D', 1000);
mysql事务隔离性相关语句说明
-- 查询当前控制台(客户端)当前事务级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- 设置当前控制台(客户端)当前事务级别
SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted;
SET SESSION TRANSACTION ISOLATION LEVEL read committed;
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read;
SET SESSION TRANSACTION ISOLATION LEVEL serializable;
--开启事务
start transaction;
--提交事务,同时事务结束
commit;
--回退事务,回退操作,同时事务结束
rollback
案列1:脏读演示,读到其他事务未提交的数据
操作步骤
1、事务一(右):A向B转200,不提交事务 2、事务二(左):查看B金额 3、事务一(右):回滚事务 4、事务二(左):查看B金额
改变事务二(左)事务级别为READ-UNCOMMITTED
两种方式
gif演示
转账SQL
update amount set money = money - 200 where id = 'A';
update amount set money = money + 200 where id = 'B';
其他事务级别请自行测试(与理论预期一致)
- 案列2,将事务二(左)在事务设置为REPEATABLE-READ,再看看操作结果(操作步骤同案例1,步骤三改为提交事务-commit)
- 案列3,将事务二(左)在事务设置为REPEATABLE-READ,再看看操作结果(操作步骤同案例1,步骤三改为提交事务-commit)
- 案列4,将事务二(左)在事务设置为SERIALIZABLE,再看看操作结果(操作步骤同案例1)
这里说明一下,SERIALIZABLE事务是串行执行,演示的时候只能由其中一个客户端操作,直到提交事务,另外一个客户端才能操作。
6.5、执行事务的过程1️⃣ 关闭自动提交
SET autocommit=0;
2️⃣ 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的sql都在同一个事务内
3️⃣ 成功则提交,失败则回滚
-- 提交:持久化(成功)
COMMIT
-- 回滚:回到原来的样子(失败)
ROLLBACK
4️⃣ 事务结束
SET autocommit=1; -- 开启自动提交
5️⃣ 其他操作
SAVEPOINT 保存点名; -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名; -- 回滚到保存点
RELEASE SAVEPOINT 保存点名; -- 撤销保存点
7、索引
索引(Index)是帮助MySQL高效获取数据的数据结构。
1、提高查询速度 2、确保数据的唯一性 3、可以加速表和表之间的连接 , 实现表与表之间的参照完整性 4、使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间 5、全文检索字段进行搜索优化
- NOT NULL: 用于控制字段的内容一定不能为空(NULL)。
- UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。
- PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一个。
- FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一。
- CHECK: 用于控制字段的值范围。
-- 创建学生表student
CREATE TABLE `student`(
`StudentNo` INT(4) NOT NULL COMMENT '学号',
`LoginPwd` VARCHAR(20) DEFAULT NULL,
`StudentName` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
`Sex` TINYINT(1) DEFAULT NULL COMMENT '性别,取值0或1',
`GradeID` INT(11) DEFAULT NULL COMMENT '年级编号',
`Phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空,即可选输入',
`Adress` VARCHAR(255) NOT NULL COMMENT '地址,允许为空,即可选输入',
`BornDate` DATETIME DEFAULT NULL COMMENT '出生时间',
`Email` VARCHAR(50) NOT NULL COMMENT '邮箱账号,允许为空,即可选输入',
`IdentityCard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`StudentNo`),
UNIQUE KEY `IdentityCard` (`IdentityCard`),
KEY `Email` (`Email`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8;
主键索引(PRIMARY KEY)
唯一的标识,主键不可重复,只有一个列作为主键
最常见的索引类型,不允许为空值 确保数据记录的唯一性 确定特定数据记录在数据库中的位置
-- 创建表的时候指定主键索引
CREATE TABLE tableName(
......
PRIMARY INDEX (columeName)
)
-- 修改表结构添加主键索引
ALTER TABLE tableName ADD PRIMARY INDEX (columnName)
普通索引(KEY / INDEX)
默认的,快速定位特定数据
index 和 key 关键字都可以设置常规索引 应加在查询找条件的字段 不宜添加太多常规索引,影响数据的插入,删除和修改操作
-- 直接创建普通索引
CREATE INDEX indexName ON tableName (columnName)
-- 创建表的时候指定普通索引
CREATE TABLE tableName(
......
INDEX [indexName] (columeName)
)
-- 修改表结构添加普通索引
ALTER TABLE tableName ADD INDEX indexName(columnName)
唯一索引(UNIQUE KEY)
它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值
与主键索引的区别:主键索引只能有一个、唯一索引可以有多个
-- 直接创建唯一索引
CREATE UNIQUE INDEX indexName ON tableName(columnName)
-- 创建表的时候指定唯一索引
CREATE TABLE tableName(
......
UNIQUE INDEX [indexName] (columeName)
);
-- 修改表结构添加唯一索引
ALTER TABLE tableName ADD UNIQUE INDEX [indexName] (columnName)
全文索引(FULLText)
快速定位特定数据(百度搜索就是全文索引)
在特定的数据库引擎下才有:MyISAM 只能用于CHAR , VARCHAR , TEXT数据列类型 适合大型数据集
-- 增加一个全文索引
ALTER TABLE `student` ADD FULLTEXT INDEX `StudentName`(`StudentName`);
-- EXPLAIN 分析sql执行的情况
EXPLAIN SELECT * FROM student; -- 非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(StudentName) AGAINST('d'); -- 全文索引
7.2、索引的使用
1. 索引的创建
在创建表的时候给字段增加索引
CREATE TABLE 表名 (
字段名1 数据类型 [完整性约束条件…],
字段名2 数据类型 [完整性约束条件…],
[UNIQUE|FULLTEXT|SPATIAL] INDEX|KEY [索引名] (字段名[(长度)] [ASC |DESC])
);
创建完毕后,增加索引
-- 方法一:CREATE在已存在的表上创建索引
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名
ON 表名 (字段名[(长度)] [ASC |DESC]) ;
-- 方法二:ALTER TABLE在已存在的表上创建索引
ALTER TABLE 表名 ADD [UNIQUE|FULLTEXT|SPATIAL]
INDEX 索引名 (字段名[(长度)] [ASC |DESC]) ;
2. 索引的删除
-- 删除索引
DROP INDEX 索引名 ON 表名;
-- 删除主键索引
ALTER TABLE 表名 DROP PRIMARY KEY;
3. 显示索引信息
SHOW INDEX FROM 表名;
-- 增加一个全文索引
ALTER TABLE `student` ADD FULLTEXT INDEX `StudentName`(`StudentName`);
-- EXPLAIN 分析sql执行的情况
EXPLAIN SELECT * FROM student; -- 非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(StudentName) AGAINST('d'); -- 全文索引
7.3、测试索引
建表 app_user:
CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '用户昵称',
`email` varchar(50) NOT NULL COMMENT '用户邮箱',
`phone` varchar(20) DEFAULT '' COMMENT '手机号',
`gender` tinyint(4) unsigned DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` varchar(100) NOT NULL COMMENT '密码',
`age` tinyint(4) DEFAULT '0' COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'
批量插入数据:100w
-- 1418错解决方案(创建函数前执行此语句)
set global log_bin_trust_function_creators=true;
-- 插入100万条数据
DELIMITER $$ -- 写函数之前要写的标志
CREATE FUNCTION mock_data() -- 创建mock_data()函数
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i set global log_bin_trust_function_creators = 1;
Query OK, 0 rows affected (0.00 sec)
-- 查看是否开启创建函数的功能
mysql> show variables like '%func%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | ON |
+---------------------------------+-------+
1 row in set (0.01 sec)
-- 开启创建函数的功能
mysql> set global log_bin_trust_function_creators=true;
Query OK, 0 rows affected (0.00 sec)
在执行函数
在执行
删除已存在的函数 DROP FUNCTION mock_data; TRUNCATE app_user; 清空表
-- 查询用户名为'用户9999'性能分析
EXPLAIN SELECT * FROM app_user where name='用户99999'
增加索引后测试
-- 给name列创建常规索引
CREATE INDEX id_app_user_name ON app_user(`name`)
-- 再测试
EXPLAIN SELECT * FROM app_user where name='用户99999'
对比两次结果,速度有了很大的提升
索引不是越多越好,小数据量的表不需要加索引
不要对经常变动的数据增加索引
索引一般加在经常要查询的列上
8、explain关键字1、表的读取顺序 2、数据读取操作的操作类型 3、哪些索引可以使用 4、哪些索引被实际使用 5、表之间的引用 6、每张表有多少行被优化器查询
使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈。
explain执行计划包含的信息
其中最重要的字段为:id、type、key、rows、Extra
explain用法 explain+SQL语句即可!
explain 执行计划包含的信息 信息描述id查询的序号,包含一组数字,表示查询中执行select子句或操作表的顺序 **两种情况** id相同,执行顺序从上往下 id不同,id值越大,优先级越高,越先执行select_type查询类型,主要用于区别普通查询,联合查询,子查询等的复杂查询 1、simple ——简单的select查询,查询中不包含子查询或者UNION 2、primary ——查询中若包含任何复杂的子部分,最外层查询被标记 3、subquery——在select或where列表中包含了子查询 4、derived——在from列表中包含的子查询被标记为derived(衍生),MySQL会递归执行这些子查询,把结果放到临时表中 5、union——如果第二个select出现在UNION之后,则被标记为UNION,如果union包含在from子句的子查询中,外层select被标记为derived 6、union result:UNION 的结果table输出的行所引用的表type显示联结类型,显示查询使用了何种类型,按照从最佳到最坏类型排序 1、system:表中仅有一行(=系统表)这是const联结类型的一个特例。 2、const:表示通过索引一次就找到,const用于比较primary key或者unique索引。因为只匹配一行数据,所以如果将主键置于where列表中,mysql能将该查询转换为一个常量 3、eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于唯一索引或者主键扫描 4、ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,可能会找多个符合条件的行,属于查找和扫描的混合体 5、range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是where语句中出现了between,in等范围的查询。这种范围扫描索引扫描比全表扫描要好,因为它开始于索引的某一个点,而结束另一个点,不用全表扫描 6、index:index 与all区别为index类型只遍历索引树。通常比all快,因为索引文件比数据文件小很多。 7、all:遍历全表以找到匹配的行 注意:一般保证查询至少达到range级别,最好能达到ref。possible_keys指出MySQL能使用哪个索引在该表中找到行key显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。查询中如果使用覆盖索引,则该索引和查询的select字段重叠。key_len表示索引中使用的字节数,该列计算查询中使用的索引的长度在不损失精度的情况下,长度越短越好。如果键是NULL,则长度为NULL。该字段显示为索引字段的最大可能长度,并非实际使用长度。ref显示索引的哪一列被使用了,如果有可能是一个常数,哪些列或常量被用于查询索引列上的值rows根据表统计信息以及索引选用情况,大致估算出找到所需的记录所需要读取的行数Extra包含不适合在其他列中显示,但是十分重要的额外信息 1、Using filesort:说明mysql会对数据适用一个外部的索引排序。而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成排序操作称为“文件排序” 2、Using temporary:使用了临时表保存中间结果,mysql在查询结果排序时使用临时表。常见于排序order by和分组查询group by。 3、Using index:表示相应的select操作用使用覆盖索引,避免访问了表的数据行。如果同时出现using where,表名索引被用来执行索引键值的查找;如果没有同时出现using where,表名索引用来读取数据而非执行查询动作。 4、Using where :表明使用where过滤 5、using join buffer:使用了连接缓存 6、impossible where:where子句的值总是false,不能用来获取任何元组 7、select tables optimized away:在没有group by子句的情况下,基于索引优化Min、max操作或者对于MyISAM存储引擎优化count(*),不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。 8、distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作。 idselect查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
三种情况:
1、id相同:执行顺序由上至下
2、id不同:如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
3、id相同又不同(两种情况同时存在):id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
查询的类型,主要是用于区分普通查询、联合查询、子查询等复杂的查询
1、SIMPLE:简单的select查询,查询中不包含子查询或者union 2、PRIMARY:查询中包含任何复杂的子部分,最外层查询则被标记为primary 3、SUBQUERY:在select 或 where列表中包含了子查询
4、DERIVED:在from列表中包含的子查询被标记为derived(衍生),mysql或递归执行这些子查询,把结果放在零时表里
5、UNION:若第二个select出现在union之后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为derived
6、UNION RESULT:从union表获取结果的select
访问类型,sql查询优化中一个很重要的指标,结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,好的sql查询至少达到range级别,最好能达到ref
1、system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,可以忽略不计
2、const:表示通过索引一次就找到了,const用于比较primary key 或者 unique索引。因为只需匹配一行数据,所有很快。如果将主键置于where列表中,mysql就能将该查询转换为一个const
3、eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键 或 唯一索引扫描。
注意:ALL全表扫描的表记录最少的表如t1表
4、ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质是也是一种索引访问,它返回所有匹配某个单独值的行,然而他可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体
5、range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了那个索引。一般就是在where语句中出现了bettween、、in等的查询。这种索引列上的范围扫描比全索引扫描要好。只需要开始于某个点,结束于另一个点,不用扫描全部索引
6、index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常为ALL块,应为索引文件通常比数据文件小。(Index与ALL虽然都是读全表,但index是从索引中读取,而ALL是从硬盘读取)
7、ALL:Full Table Scan,遍历全表以找到匹配的行
查询涉及到的字段上存在索引,则该索引将被列出,但不一定被查询实际使用
key实际使用的索引,如果为NULL,则没有使用索引。
查询中如果使用了覆盖索引,则该索引仅出现在key列表中
表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。key_len是根据表定义计算而得的,不是通过表内检索出的
ref显示索引的那一列被使用了,如果可能,是一个常量const。
rows根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
Extra不适合在其他字段中显示,但是十分重要的额外信息
1、Using filesort : mysql对数据使用一个外部的索引排序,而不是按照表内的索引进行排序读取。也就是说mysql无法利用索引完成的排序操作成为“文件排序”
由于索引是先按email排序、再按address排序,所以查询时如果直接按address排序,索引就不能满足要求了,mysql内部必须再实现一次“文件排序”
2、Using temporary: 使用临时表保存中间结果,也就是说mysql在对查询结果排序时使用了临时表,常见于order by 和 group by
3、Using index: 表示相应的select操作中使用了覆盖索引(Covering Index),避免了访问表的数据行,效率高。
如果同时出现Using where,表明索引被用来执行索引键值的查找(参考上图)
如果没用同时出现Using where,表明索引用来读取数据而非执行查找动作
覆盖索引(Covering Index):
也叫索引覆盖。就是select列表中的字段,只用从索引中就能获取,不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
注意:
a、如需使用覆盖索引,select列表中的字段只取出需要的列,不要使用select * b、如果将所有字段都建索引会导致索引文件过大,反而降低crud性能
4、Using where : 使用了where过滤
5、Using join buffer : 使用了链接缓存
6、Impossible WHERE: where子句的值总是false,不能用来获取任何元祖
7、select tables optimized away:
在没有group by子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即可完成优化
8、distinct:
优化distinct操作,在找到第一个匹配的元祖后即停止找同样值得动作
9、权限管理和备份 9.1、用户管理方式一:可视化管理
-- 创建用户
CREATE USER zsr IDENTIFIED BY '123456'
-- 删除用户
DROP USER zsr
-- 修改当前用户密码
SET PASSWORD = PASSWORD('200024')
-- 修改指定用户密码
SET PASSWORD FOR zsr = PASSWORD('200024')
-- 重命名
RENAME USER zsr to zsr2
-- 用户授权(授予全部权限,除了给其他用户授权)
GRANT ALL PRIVILEGES on *.* TO zsr2
-- 查询权限
SHOW GRANTS FOR zsr
-- 查看root用户权限
SHOW GRANTS FOR root@localhost
-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM zsr
9.2、数据库备份
保证重要的数据不丢失、数据转义
方式一:直接拷贝物理文件,MySQL数据表以文件方式存放在磁盘中
包括表文件 , 数据文件 , 以及数据库的选项文件
位置 : Mysql安装目录\data\(目录名对应数据库名 , 该目录下文件名对应数据表)
方式二:可视化管理
Navicat打开要备份的数据库,然后点击新建备份
方式三:可视化管理
方式四:命令mysqldump导出
# mysqldump -h主机 -u用户名 -p密码 数据库 [表1 表2 表3] >物理磁盘位置/文件名
# 导出school数据库的cource grade student表到D:/school.sql
mysqldump -hlocalhost -uroot -p200024 school course grade student >D:/school.sql
source命令导入
规范化理论:
改造关系模式,通过分解关系模式来消除其中不合适的数据依赖,以解决插入异常、删除异常、更新异常和数据冗余的问题。
为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定规范化理论。
在关系型数据库中这种规则就称为范式
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由,比如性能,事实上,我们经常会为了性能而妥协数据库的设计。
三大范式的通俗理解目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
而通常我们用的最多的就是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),也就是本文要讲的“三大范式”。
第一范式:每个列不可再拆分 第二范式:在第一范式的基础上,非主键完全依赖于主键,而不是依赖于主键的一部分 第三范式:在第二范式的基础上,非主键只依赖于主键,不依赖于其他非主键
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项举例说明: 在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:
可见,调整后的每一列都是不可再分的,因此满足第一范式(1NF);
第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
举例说明: 在上图所示的情况中,同一个订单中可能包含不同的产品,因此主键必须是“订单号”和“产品号”联合组成,
但可以发现,产品数量、产品折扣、产品价格与“订单号”和“产品号”都相关,但是订单金额和订单时间仅与“订单号”相关,与“产品号”无关,
这样就不满足第二范式的要求,调整如下,需分成两个表:
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
举例说明: 上表中,所有属性都完全依赖于学号,所以满足第二范式,但是“班主任性别”和“班主任年龄”直接依赖的是“班主任姓名”,
而不是主键“学号”,所以需做如下调整:
这样以来,就满足了第三范式的要求。
ps:如果把上表中的班主任姓名改成班主任教工号可能更确切,更符合实际情况,不过只要能理解就行。
11、MyISAM和InnoDB区别 MyISAMInnoDB存储结构frm-表格定义、MYD(MYData)-数据文件、MYI(MYINDEX)-索引文件所有的表都保存在同一个数据文件中(也可能是多个文件,或是独立的表空间文件)表大小受限于操作系统文件的大小,一般为2GB存储空间可被压缩,存储空间小表需要更多的存储空间,他会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引可移植性、备份及恢复由于MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了文件格式*.MYI、 *.MYD表结构存在*.frm文件,数据和索引都是集中存储的*.ibd外键不支持 支持事务不支持 支持锁支持(锁是避免资源争用的一个机制,MySQL锁对用户几乎是透明的)表级锁定 行级锁定、表级锁定,锁定力度小 并发能力高SELECTMyISAM更优INSERT、UPDATE、DELETEInnoDB更优索引的实现方式B+树索引,MyISAM表B+树索引、InnoDB是索引组织表哈希索引不支持支持全文索引不支持支持记录存储顺序按记录插入顺序保存按主键大小有序插入select count(*)MyISAM更快,因为MyISAM内部维护了一个计数器,可以直接调取。 索引InnoDBMyISAMMemoryBTREE支持支持支持HASH不支持不支持支持R-tree不支持支持不支持Full-test5.6版本后支持支持不支持聚集索引、复合索引、前缀索引、唯一索引默认都是使用B+tree树(多路搜索树,不一定是二叉的)索引,统称索引
存储引擎表级锁行级锁页面锁MyISAM支持不支持不支持InnoDB支持支持不支持MEMORY支持不支持不支持BDB支持不支持支持