学习mysql时记录的笔记

数据库(数据库管理系统,简单的sql语句)
objectoutputStream
不方便
反序列化
new java 对象
readobject() ----自己操作id流
writeobject

常见的数据库管理系统
oracle
java现在由oracle升级
sun收购了mysql,orcle收购了sun,mysql在oracle之下
端口号在同一端口不能重复。
端口是软件的
上网的端口是80

mysql -uroot-p123456登陆

修改密码(省)
mysql卸载双击安装包remove
手动删除program files 中的mysql目录
手动删除programdate目录中的mysql
sql,db,dbms
db:database(数据库,数据库实际上在硬盘上以文件的形式存在)
dbms:
database management system(数据库操作系统)
sql
结构化查询语言,是已满标准用用语言
sql属于高级语言
sql语句在执行的时候,实际上内部会先进行编译,然后再执行sql。
dbms负责执行sql语句,通过执行sql语句来操作db中数据
dbms-执行-sql(操作)-db
表:table是数据库的基本组成单元,所以的数据都以表格的形式组织,目的是可读性强。
一个表包括行和列:
行被称为记录,列被称为字段
sql语句分类:
dql(数据查询语言):查询语句,凡是selesct语句都是dql
dml(数据操作语言):insert delete update,对表当中的数据进行增删改。
ddl(数据定义语言):create drop alter 对表结构的增删改。
dcl(数据控制语言):grant授权,revoke撤销权限等。
tcl(事务控制语言):commit提交事务。rollbac回滚事务。(tcl中的T是transactional)
DDL(Data Definition Language)数据定义语言

用来定义数据库对象:数据库,表,列等。关键字:create, drop,alter 等

DML(Data Manipulation Language)数据操作语言

用来对数据库中表的数据进行增删改。关键字:insert, delete, update 等

DQL(Data Query Language)数据查询语言

用来查询数据库中表的记录(数据)。关键字:select, where 等

DCL(Data Control Language)数据控制语言(了解)

用来定义数据库的访问权限和安全级别,及创建用户。关键字:GRANT, REVOKE 等
数据库基本指令:
查看数据库
show databases;
创建数据库
create database bjpowernode;
使用bjpowernode数据
use bjpowernode(这个不是sql语句,属于mysql命令)
查表
show tables(这个不是sql语句,属于mysql命令)
初始化数据
mysql>source D:\bjpowernode。sql(执行sql脚本)
数据初始化完成后有三张表

以sql结尾的文件称为sql脚本。
sql脚本的数据量太大的时候,无法打开,请使用source命令完成初始化
删除数据库 drop dtabase bjowernode
常用命令 select database();查看当前使用的是哪个数据库
select version();查看mysql的版本号。
\c结束一条语句
exit推出sql
查看创建表的语句:
show create table emp;

简单的查询语句(dql)
语法格式:
select 字段名。。。from 表名。
提示:任何一条sql语句以";"结尾。
sql语句不区分大小写。

给查询结果的列重命名
select ename,sal*12 as yearsal from emp;
select ename ,SAL as ab from emp where sal>ab错误,因为where的优先级大于select,此时他并不知道ab是什么

重命名为中文时必须加单引号戒双引号;
2. 标准SQL询句中类型为字符串时必须加单引号,加单引号适用亍任何数据库;
3. SQL询句中类型为字符串时也可加双引号,叧适用亍MySQL数据库中;
4. 为了SQL询句的通用性,建议全部使用单引号;

意:
MySQL在windows下是丌区分大小写的,将script文件导入MySQL后表名也会自劢转化为小写,结
果再想将数据库导出放到linux服务器中使用时就出错了。因为在linux下表名区分大小写而找丌到表,查
了很资料都说在linux下更改MySQL配置使其也丌区分大小写,但是有没有办法反过来让windows下大小
写敏感呢?其实方法是一样的,相应的更改windows中MySQL的设置就行了。
具体操作:在MySQL的配置文件my.ini中增加一行:lower_case_table_names = 0
其中 0:区分大小写 ; 1:丌区分大小写
MySQL在Linux下数据库名、表名、列名、别名大小写规则是这样的:
数据库名不表名是严格区分大小写的;
表的别名是严格区分大小写的;
列名不列的别名在所有的情况下均是忽略大小写的;
变量名也是严格区分大小写的;(MySQL的变量名在windows下都丌区分大小写)

1.取得每个部门最高薪水的人员名称
select * from emp;
实际开发中不建议使用。注:采用 select * from emp,虽然简单,但是 * 号丌是很明确,并丏 select * 语句会先去编
译,将“*”转换成字段,建议查询全部字段将相关字段写到 select 语句的后面,在以后 java
连接数据库的时候,是需要在 java 程序中编写 SQL 语句的,这个时候编写SQL语句丌建议
使用 select * 这种形式,建议写明字段,这个 SQL 语句的可读性强。

条件查询:
语法格式
select
字段 ,字段。。。
from
表名
where
条件;

and
between
between and 必须左小右大。
between and除了可以使用在数字方面还可以使用在字符串方面。
select ename from emp where ename between ‘A’and‘B’左闭右开
在数据库中null不是一个值,代表什么也没有,为空。
空不是一个值,泵使用等号衡量。
必须使用is noll 或者 is not null;
找出工作岗位是xx和xxx的员工用or
使用and 和or的时候注意优先级使用括号括起来。一般情况下and的优先级大于or
in后面的值不是区间是值。
select ename,job from emp where sal in(800,1000);
模糊查询
找出名字中第二个字母是A的
select ename from emp where ename like ‘_A%’;
使用\转义字符_使_不具备转义
排序(升序,降序)
按照工资高升序,找出员工名和薪资
select
ename,sal
from
emp
order by
sal;
默认是升序,怎么指定是升序还是降序呢?asc表示升序,desc表示降序。
selcet ename,sal from emp order by 2;
以第二列排序。
分组函数:多行分组函数
count 计数
sum 求和
avg 平均值
max 最大值
min 最小值
select sum(sal) from emp;
所有的分组函数都是对”某一组数据进行操作的”
分组函数还有另一个名字,多行处理函数。
多行处理函数的特点:输入多行,最终输出的结果都是一行。
单行处理函数:
输入一行,输出一行ifnull()

分组函数自动忽略null。不需要额外添加条件。
所以数据库都是这样规定的,只要有null参加的原酸结果一定是null。
select ename,(sal+comm)12 as yearsql from emp
如果comm是nullname结果会变成null;
ifnull()空处理函数。
ifnull(可能为null的数据,被当作什么处理)属于单行处理函数。
ifnull(需要判断的字段,为null之后输出的结果)
找出工资高于平均工资的员工?
select avg(sal) from emp;//平均工资
select ename,sal from emp where sal>avg(sal)
错误
原因:sql语句当中有一个语法规则,分组函数不可直接使用在where 子句当中。
count(
)和count具体的某个字段,他们有什么区别?
count(
);不是统计某个字段中数据的个数,而是统计总记录条数,(和某个字段无关)
count(comn)表示统计comn字段中不为null的数据总数量。
group by和having
group by:按照某个字段或者某些字段进行分组
having :having是对分组之后的数据进行再次过滤。
分组函数永远在group by之后执行。(group by)先执行。
注意:分组函数一般都会和group by 联合使用,这也是为什么它被称为分组函数的原因。
并且在任何一个分组函数(count sum avg max、min)都是在group by 语句执行结束之后才会执行。
当一条sql语句没有group by的话,整张表的数据会自成一组。
排序采用 order by 子句,order by 后面跟上排序字段,排序字段可以放多个,多个采
用逗号间隔,order by默认采用升序(asc),如果存在 where 子句,那么 order by 必须放到
where 询句后面。
group by 是在where 执行之后才会执行。
select ename,sal from emp where sal>avg(sal)
错误(还没有分组就使用了分组)
sql语句当中有一个语法规则,分组函数不可以直接使用在where子句当中。
因为group by 是在where 执行之后才会执行的。
第一步:找出平均工资
select avg(sal)from emp;
第二步:找出高于平均工资的员工。
select ename,sal from emp where sal>2073.214026;

select ename,sal from emp where sal>(select avg(sal)from emp);

seelect ename,max(sal),job from emp group by job–错误
使用group by 分组的话,select后面只能跟分组函数和参与分组的字段。
mysql无意义,oracle报错
每个工作岗位的平均工资:
select job,avg(sal) from emp group by job;
多个字段能不能联合分组?
找出每个部门不同工作岗位的最高薪资。
select
deptno,job,max(sal)
from
emp
group by
deptno,job;

having 过滤
找出每个部门的最高薪资字,要求显示薪资大于2900的薪资。
第一步找出每个部门的最高的薪资
select max(sal),deptno from emp group by deptno;
第二部:找出薪资大于2900
select max(sal),deptno from group by deptno having sal>2900(效率低)
分析:group by 分组完再去掉max(sal)小于2900的数据,还不如分组之前便将数据去除,参与分组的数据比where多,鞥使用where就用where
效率高
select max(Sal),deptno from emp where sal>2900 group by deptno (where会先执行)

使用group by select查询的只能是分组的字段和分组函数
select
deptno,JOB,sal from emp
group by deptno,JOB;
分组之后这样算出来的sal是错误的,默认是显示分组的第一个。
–不能用where的情况,平均工资,不能使用分组函数
什么情况下只能用having 当要查询的数据中涉及分组函数的时候:
查出每个部门的平均工资,要求显示薪资大于2000的数据:

select ename,sal,avg(sal) from emp group by sal HAVING avg(sal)>sal
错误sal为空
select deptno,avg(sal) from emp where avg(sal)>2000 group by deptno 错误:因为where子句里面不能使用分组函数,where会比groupby先执行。
正确:
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;分组函数在group by之后才能使用 having是group by的搭档,对分组完不满意的数据进行过滤
select 5
。。
from 1
。。
where2
。。
group by 3
。。
having 4
。。
order by 6
。。


必须在执行了分组查询group by之后才能执行分组函数,如果没有group by 默认会将整张表作为一组(实际上就是表是一组,一张表就是一组),查询的select的字段必须是group中存在要查询的字段
关于查重结果的去重。
在字段前加distinct

select destinct job from emp;//distinct 关键字去除重复记录
distinct只能出现在所有字段的最前面。
统计岗位的数量
select count(distinct job)from emp;
select ename,distinct job from emp;错误,distinct只能出现在所有字段的最前面。
select distinct job,ename from emp;表示去除job和ename重复的

连接查询:
在实际开发中,大部分的情况都不是在从单表中查询数据,一般都是多张表联合查询出最终结果。
学生和班级信息存储到一张表中,会出现数据的冗余。
stuno stuname classno classname
1 1 name
2 1 name
连接查询的分类
根据语法出现的年代来划分的,包括:sql92
(一些老的DBA可能还在使用这种语法。DBA:database administrator,数据库管理员)
sql99(比较新的语法)

根据表的连接方式来划分,包括:
内连接:等值连接 非等值连接 自连接
外连接:
左外连接(左连接)
右外连接(右链接)
全连接。

在表的连接查询方面有一种现象被称为:笛卡尔积现象。 笛卡尔乘积现象
select ename,dname from emp,dept;会出现56条记录,emp14条,dept4条,记录是他们的乘积(笛卡尔积),没有加条件,所有数据都要
关于表的别名:执行效率高,可读性好
select e.ename,d.dname from emp e,dept d;
select ename,dname from emp,dept;ename,dname要联合起来一块显示,粘到一块。

怎么避免笛卡尔积现象?当然是加条件进行过滤。避免笛卡尔积现象不会减少匹配次数,只不过
会显示有效记录

内连接之等值连接,最大的特点是:条件是等量关系。

查询每个员工的部门名称,要求显示员工名和部门名。
等值连接:
sql92:
select
e.ename,d.dname
from
emp e,dept d
where
e.deptno=d.deptno;(结构不清晰)以后不用

sql99:(常用的)
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno=d.deptno;
语法
。。
A
inner JOIN//inner可以省略,戴着inner可读性好一些
B
ON
连接条件
where

sql99语法结构更清晰一些,表的连接条件和后来的where分离了。和过滤的条件分离了。

内连接值非等值连接,最大的特点是,连接条件中的关系是非等量关系。
找出每个员工的工资等级,要求显示员工名,工资,工资等级。
select ename ,sal from emp;e
select * from salgrade ;s
select e.ename,e.sal,s.grade
from
emp e
inner join (inner可省略)
salgrade s
on
e.sal between s.losal and s.hisal;(条件是非等值的)

自连接:最大的特点是:一张表看做两张表,自己连接自己。
找出每个员工的上级领导,要求显示员工名和对应的领导名。
select empno,ename,mgr from emp;
员工的领导编号=领导的员工编号。
select
a.ename as ‘员工名’,b.ename as ‘领导名’
from
emp a
join
emp b
on
a.mgr=b.empno;
原理:将一张表分成两张表。属于等值连接,如果是null会丢失记录
也可以分成非等值连接。

外连接----
什么是外连接,和内连接的区别:
内连接:假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来这就是内连接。null的情况不查,能匹配就差,不匹配就不查
AB两张表没有主副之分,两张表是平等的。
外连接
假设A和B进行连接,使用外连接的话,AB两张表中有一张是主表,另外一张是副表,主要查询主表中的数据,捎带着查询副表,
当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配。

外连接的分类:
左外连接:表示左边的这张表是主表。
右外连接:表示右边的这张表是主表。
左连接有右连接的写法,右连接也会有对应的左连接的写法。
案列:找出每个员工的上级领导。
select
a.ename as ‘员工名’,b.ename as ‘领导名’
from
emp a
left join(左边是主表,一定要查出来)
emp b
on
a.mgr=b.empno;

inner 内
outer外
两者都能省略
select
a.ename as ‘员工名’,b.ename as ‘领导名’
from
emp a
right outer join(左边是主表,一定要查出来)outer可以省略
emp b
on
a.mgr=b.empno;
外连接的最重要的特点是:主表中的数据五条的全部查询出来。
案列:找出哪个部门没有员工:
select
d.*
from
emp e
right outer join(outer可以省略)
dept d
on
e.deptno=d.deptno
where e.empno=null;

外连接使用多,内连接可能会有数据丢失,

三张表的连接查询

AJOIN b
join c
on

案列:找出每一个员工的部门名称以及员工等级。
emp表的部门编号和部门表的部门编号连接,连接后emp表的工资和s表的工资等级连接。
select
e.ename,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno=d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;

案列:找出每一个员工的部门名称,工资等级,以及上级领导。

select
e.ename,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno=d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp e1
on
e.mgr=e1.empno;

----子chaxun
什 么是子查询
select 语句当中嵌套select语句,被嵌套的select语句是子查询
select
…(select).
from
…(select).
where
…(select).

where 子句中使用子查询
案列:找出高于平均薪资的员工信息。
select * from emp where sal>avg(sal);//错误写法,where 后面不能直接使用分组函数。
第一步找出平均工资
select avg(sal) from emp;
第二部找出大于平均工资的员工信息。
select * from emp where sal>xxx;
合并查询
select * from emp where sal>(select avg(sal) from emp);

–from 后面嵌套子查询
案列:找出每个部门平均薪水的薪资等级。
第一步:找出每个部门的平均薪水(按照部门编号分组,求出sal的平均值)
select deptno,avg(sal) as avgsal from emp group by deptno;
第二步:将以上的查询结果当做临时表t,让t表和salgrade表连接,条件是:t。avgsal between s.losal and s.hisal

from 后面跟表但是他可以是一条查询语句。
select
t.* ,s.grade
from
(select deptno,avg(Sal) as avgsal from emp group by deptno)t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;

案列:找出每个部门平均的薪水等级。
第一步:找出每个员工的薪水等级。
select
e.ename,e.sal,e.deptno,s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal;

第二步:基于以上的结果,继续按照deptno分组,求grade平均值。
select
e.deptno,avg(s.grade)
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal
group by
e.deptno;

在select后面嵌套子查询。
案列:找出每个员工所在的部门名称,要求显示员工名和部门名。
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno=d.deptno;

select e.ename,(select d.dname from dept d where e.deptno =d.deptno)as dname from emp e;

—union(可以将查询结果集相加)
案列:找出工作岗位是SALESMAN和MANAGER的员工。

selct ename,job from emp where job =‘MANAGER’
union
select ename,job from emp where job =‘SALESMAN’;
通常用于两张不相干的表中数据拼接在一起。

limit******(重点中的重点,以后分页查询全靠它)
limit是mysql特有的,其他数据库没有,不通用.(oracle中有一个相同的机制,叫做rownum)
limit取结果集中的部分数据,这时它的作用。
语法机制:
limit starIndex,length
starInndex表示起始的位置,从0开始,0表示第一条数据。
length表示取几个。
案列:
取出工资前五的员工(降序取前五个);
select ename,sal from emp oreder by sal desc;
取前五个
select ename,sal from emp order by sal desc limit 0,5;
limit 是sql语句最后执行的一个环节;

select 5

from 1

where 2

group by 3

having 4

…order by 6

limit 7
…;

每页显示3条记录:
第一页:0,3
第二页:3,3

每页显示的pagesize条记录;
第pagesize页:(pageno -1)*pagesize,pagesize
pagesize是什么?是每页显示多少条记录
pageno是什么?显示第几页

java代码{
int pageno=2;//页码是2
itn pagesize=10;//每页显示10条
limit (pagesize -1)*pagesize,pagesize}

创建表:
建表语句的语法格式:
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
。。。
);
常见的数据类型:
int 整数型
bigint 长整型
float 浮点型
char 定长字符串
vchar 不定长字符串
date 日期类型
blob 二进制大对象(存储图片,视频等流媒体信息)
clob 字符大对象 (存储较大文本,比如,可以存储4g的字符串。)

insert语句插入数据
insert into 表名(字段名1,字段名2.。。)values(值1,值2,。。。)
字段的数量和值的数量相同并且数据类型要对应相同。
create table t_student(
no int(4),
name varchar(32),
gender char(1),
birth date,
email varchar(128)
);

drop table t_student;
drop table if exists t_student;

复制表:create table 表名 as 查询语句
create table emp_bak as select * from emp;

DML语句:insert update delete
insert语法:
insert into 表名(字段名,字段名,字段名,字段名) values(字段值,字段值,字段值,字段值);

`
insert into t_student(no,name,gender,birth,email) values(1,‘zhangsan’,‘1’,str_to_date(‘1949-10-01’,‘%Y-%m-%d’),‘zhangsan@126.com’);
insert into t_student(no,name,gender,birth,email) values(2,‘lisi’,‘0’,‘1949-11-11’,‘lisi@126.com’);
insert into t_student(no,name,gender,birth,email) values(3,‘hanmeimei’,‘0’,str_to_date(‘11-11-1950’,‘%m-%d-%Y’),‘hanmeimei@126.com’);

insert into t_student values(5,‘jerry’,‘1’,‘1949-01-01’,‘jerry@126.com’);//如果不写t_student()那么就必须插入所有字段的值

insert into t_student(no,name,gender) values(4,‘lilei’,‘1’);

create table t_student(
no int(4),
name varchar(32),
gender char(1) default ‘1’,
birth date,
email varchar(128)
);
insert into t_student(no,name) values(1,‘zhangsan’);

insert into t_student(no,name) values(2,‘李四’);

指定默认值,不插入数据时则默认为1
不指定则为null
当一条insert语句执行成功之后,表格当中必然会多一行数据,只能使用update进行更新。

----表的复制
语法:
create table 表名 as select语句;
将查询结果当做表创建出来。
insert into dept1 select * from dept;
将后面的查询结果当做数据插入到表里面。

删除数据
语法格式
delete from 表名 where 条件;
没有条件会全部删除。
删除部门编号为10的数据
delete from dept1 where deptno=10。
怎么删大表
delete删除的速度慢,没有释放delete的真实存储空间。可以回滚,删除的速度慢。
truncate table 表名;(删除表中的数据)截断的
表被截断,不可回滚,永久丢失。
对表的结构修改使用工具完成,修改表结构的语句不会出现在java代码中。
删除表
droup table 表名;
droup table if exists 表名;

增删改查有一个术语:crud操作
alter table 表名 add
alter table 表名 modify 字段名称 字段类型 字段长度 字段约束;
alter table 表名 drop 字段名称;
alter table 表名 change 原字段名 新字段名 (修改表中的字段名)

修改数据:update
语法格式:
update 表名 set 字段名1=值1,字段名2=值2.。。where条件
注意:没有条件整张表更新
案列:
将部门10的LOC修改为shanghai,将部门名称改为renshibu
update dept1 set loc=‘shanghai’,dname=‘renshibu’ where deptno=10
约束(constraint)
表格
id username password(非空约束)
在创建表是时候可以给表的字段添加相应的约束,添加的约束的目的是为了保证表中的数据的合法性,有效性,完整性。

非空约束(not null);约束的字段不能为null
唯一约束(unique);约束的字段不能重复
主键约束(primary key);约束的字段既不能为null,也不能重复简称pk
外键约束(foreign key) : 简称fk
检查约束(check),注意oracle数据库有check约束,但是mysql没有,目前mysql不支持该约束。

非空约束 not null。

唯一性约束(unique)
唯一约束修饰的字段具有唯一性,不能重复,但可以为NULL。
案列:
create table t_user(
id int,
username varchar(255) unique
);
insert into t_user values(1,‘zhangsan’);
insert into t_user values(2,‘zhangsan’);(报错,提示已经存在)

案列:给两个列或者多个列添加unique
drop table if exists t_user;
create table t_user(
id int,
usercode varchar(255) unique,
username varchar(255) unique----列级约束
);

drop table if exists t_user;
create table t_user(
id int,
usercode varchar(255) ,
username varchar(255) ,
unique(username,usercode)----这是联合约束(表级约束)
);
insert into t_user values(1,‘zhangsan’,‘lisi’)
insert into t_user values(2,‘zhangsan’,‘lisi’)–不可执行
insert into t_user values(1,‘zhangsan’,‘liwu’)–可执行

总结:
列级约束只要一个相同都不能执行,而表级约束只有都相同时才不能执行。

主键约束
create table t_user(
id int primary key,//列级约束
username varchar(255),
email varchar(255)
);
insert into t_user(id,username,email) values(1,‘zs’,‘122.com’);
insert into t_user(id,username,email) values(2,‘yis’,‘1222.com’);
insert into t_user(id,username,email) values(3,‘zs’,‘12222.com’);

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

使用表级约束定义主键:
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,‘zs’);
insert into t_user (id,username) values(3,‘zs’);
insert into t_user (id,username) values(3,‘zs’);

create table t_user(
id int,
username varchar(255),
primary key(id,username)–复合主键
);

mysql 提供主键值自增:
drop table if exists t_user;
create table t_user(
id int primary key auto_increment,//id字段自动维护一个自增的数字,从1开始自增
username varchar(255)
)
;
insert into t_user (username) values(‘zs’);
insert into t_user (username) values(‘zs’);
insert into t_user (username) values(‘zs’);

注册的时候不需要用户添加,系统自动添加。
oracle当中也提供了一个自增机制,叫做:序列(sequence)对象。

外键约束
关于外键的相关术语:外键约束:foreign key
外键字段:
添加有外键约束的字段
外键值:外键字段中的每一个值。

t——class 班级表
cno(pk) cname
101 某一班
102 某2班

t_student 学生表
sno(pk) sanme classno(该字段添加外键约束fk)
1 sa1 101
2 sa2 102
将以上表的建表语句写出来:
t——student 中的classno字段引用t——class表中的cno字段,此时t_studnt表叫做子表叫做父表
删除数据时先删除子表,再删除父表
添加数据的时候先添加父表,再添加子表
创建表的时候先创建父表,再创建子表,
删除表的时候先删除子表,再删除父表。

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,‘1111222’);
insert into t_class values(102,‘1111222222’);
insert into t_student values(1,‘zs1’,101);
insert into t_student values(1,‘zs1’,101);
insert into t_student values(1,‘zs1’,103);
报错,子表中被约束的字段的来自父表中的数据

外键值可以为NULL吗
可以。
外键可以不是另外一张表的主键,但是必须具备唯一性

----存储引擎
—表的存储方式
不同的存储引擎,表在存储的时候存储的方式不同。mysql特有

show create table emp;
可查看建表时存储引擎innodb
没有指定的时候存储引擎默认是innodb
字符集为utf-8
完整的建表语句
create table t_x(
id int(11) DEFAULT NULL
)ENGINE=InnoDB DEFAULT CEARSET=utf-8
注意在mysql当中,烦死标识符是可以使用飘号扣起来,最好别用,不通用。
建表的时候可以指定存储引擎,也可以指定字符集。
存储引擎之歌名字只在mysql中存在
oracle中有对应的机制,但是不叫存储引擎,oracle没有特殊的名字。
mysql支持多种存储方式,每一个存储都对应一种存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
查看当前mysql支持的存储引擎
show engines\G
有9种存储引擎。
常见的存储引擎:3
MYISAM存储引擎:
不支持事务(TCL)MYISAM是mysql最常用的,但是不是默认的
它管理的表具有以下特征:
使用三个文件表示每个表:
格式文件-存储表结构的定义frm
数据文件-存储表的内容myd
索引文件-存储表上的索引。myi
可转换为压缩文件,节省空间。(可被压缩,节省空间,并且可以转化为只读表,)
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO

innodb
有点:支持事务,行级锁,外键等这种存储引擎数据的安全得到保障。
它管理的表具有以下特征:(表空间的概念)
每个innodb表在数据库目录中以frm格式文件表示
innodb表空间tablespqce被用于存储表的内容(无法被压缩)
提供一组用来记录事务性活动的日志文件。
甩commit(提交),savepoint及rollback 回滚支持事务处理
提供ACID兼容
在mysqk服务器崩溃后自动恢复。
多版本(mvcc)和行级锁定。
支持外键及引用完整性,包括级联删除和更新(删除外键的时候,可直接删掉父表)
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
memory存储引擎
缺点:不支持事务,数据容易丢失,因为所有数据和索引都是存储在内存当中(断电丢失)
优点:速度快
memory存储一起拿管理的表具有以下特征:
在数据库目录内,每个表以frm格式的文件表示。
表数据及索引被存储在内存中。
表级锁机制
不能包含text(clob)或blob字段
memory 存储以前被称为hfap引擎。
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO

----事务
什么是事务:
一个事务是一个完整的业务逻辑单元,不可再分。
比如:银行转账,从A账户向B账户转账1000,需要执行update语句。
update t_act set balance=balance - 10000 where actno=‘act_001’;
update t_act set balance=balance + 10000 where actno=‘act_002’;

以上两条dml语句必须同时成功,或者同时失败,不允许一条成功一条失败。
要想保住以上两条dml语句成功或者同时失败,那么必须使用到数据库的事务机制。(只有dml支持事务,其他都不支持)。
和事务相关的语句只有:dml语句(insert,delete,update)
因为它们这三个语句都是和数据库当中的数据有关。
事务是为了保证数据的完整性,安全性。

如果所有的业务都能使用一条dml语句搞定,则不需要事务机制。
通常一个事儿需要多条mdl语句共同联合完成。

一个最小的丌可再分的工作单元
通常一个事务对应一个完整的业务;(如:银行转账业务)
而一个完整的业务需要批量的DML(insert、update、delete)诧句共同完成
事务叧和DML诧句有关系,戒者说叧有DML诧句才有事务;
以上所描述的批量DML诧句共有多少DML诧句,这个和业务逻辑有关系,业务逻辑丌同DML诧句个数丌
同。
假设需要先执行一条insert,再执行一条update,再执行delete语句,这事才算完成。
开启事务机制:
insert。。。执行成功后,把这个执行记录到数据库的历史当中,并不会改变数据,不会真正的修改硬盘上的数据。
update。。。执行成功后,把这个执行记录到数据库的历史当中,并不会改变数据,不会真正的修改硬盘上的数据。
delete。。。执行成功后,把这个执行记录到数据库的历史当中,并不会改变数据,不会真正的修改硬盘上的数据。
提交事务或者回滚事务。
事务的特性:
事务包括四大特性:
ACID
A.原子性 atom事务是最小的工作单元不可再分
C:一致性 coherence 事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性 isolation 事务A与事务B之间具有隔离
D:持久性 durability 持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。

关于事务之间的隔离性
事务隔离性存在隔离级别,理论上隔离级别包括4个:
第一级别:读未提交(read uncommitted)
对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
读未提交存在脏读(Dirty read )现象:表示读到了脏的数据。
第二级别:读已提交(read committed)
对方事务提交之后的数据我方可以读取到。
这种隔离级别解决了:脏读现象。
读已提交存在的问题:不可重复读。
第三级别:可重复读(repetable read)
这种隔离解决了:不可重复读问题。
这种隔离级别存在的问题是:读取到的数据是幻象。
第四级别:序列化/串行化读
解决了所有问题
效率低。需要事务排队。
oracle数据库默认的隔离级别是:读已提交。
mysql数据库默认的隔离级别是:可重复读。三档起步

演示事务
mysql事务默认情况下是自动提交的。
(什么是自动提交?只要执行任意一条DML语句则提交一次。)怎么关闭自动提交?start transaction
吧保存回滚点:savepoint name
回滚:rollback name
演示:
drop table if exists t_user;
create table t_user{
id int primary key auto_increment,
username varchar(255)
};
rollback无效,commit自动提交了
mysql事务是自动提交的,
开启事务start transaction(关闭自动提交机制)
提交之后会把数据提交到内存当中,rollback就没有用了。

使用两个事务演示以上的隔离级别
第一:演示read uncommitted
set global transaction isolation level read uncommitted;设置事务的隔离级别
select @@global.transaction_isolation;查看隔离级别
select @@global.tx_isolation;//失效
可以读取到没有提交的数据

第二:
读已提交
set global transaction isolation level read committed;只能读已经提交的
第三:读到备份数据
幻象
set global transaction isolation level repetable read。
第四:序列化,最保险,事务排队,一边结束之后另外才能进行操作
set global trasation isolation level serializable
commit之后才能进行操作。


mysql远程登录:mysql -h192.168.151.18 -uroot -p123456

—索引

索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
在数据库方面,查询一张表的时候有两种检索方式:
第一种:全表扫描
第二种根据索引检索(效率高)
索引为什么可以提交检索效率呢-其实根本的原理是缩小了扫描的范围。
索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护,是有
维护成本的,表中的数据经常被修改这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。
什么时候添加索引
1数据量庞大,(根据用户的要求)
2该字段很少的DML操作。(因为字段进行修改操作,索引也需要维护)insert delete update,数据操作
3该字段经常出现在where
添加索引是给某一个字段,或者说某些字段添加索引。
select ename,sal from emp 、where ename=’shith‘;
当ename没有添加索引的时候,该sql语句会进行全表扫描,扫描ename字段索引的值.
当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位。

注意:主键和具有unique约束的字段会自动添加索引。
根据主键查询效率较高,尽量根据主键检索。
explain命令jiasql语句 查看执行、过程

给薪资sal字段添加索引:
create index emp_sal_index on emp(sal);

怎么创建索引:
create index 索引名称 on 表名(字段名);
删除索引对象:
drop index 索引名称 on 表;

索引底层采用的数据结构是:B+tree
索引的实现原理:
索引会进行分区,存储到B-tree上,缩短了扫描的数量
数据库表中的任何一个数据都有一个物理地址。
select ename from emp where enmae=‘smith’.
会变形成
select ename from emp where 物理地址=0x3。缩短了扫描的范围。

通过 B tree缩小扫描的范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,
最终通过索引检索到数据之后,获得到关联的物理地址,通过物理地址定位到表中的数据,效率是最高的。
索引的分类:
单一索引:给单个字段添加索引
复合索引:给多个字段联合起来添加一个索引
主键索引:主键会自定添加索引
唯一索引:有unique约束的字段会自动添加索引。
索引什么时候失效:
select ename from emp where ename like ‘%A%’;模糊查询不能随便用
第一个通配符使用的是%,这个索引是失效的。

试图(view):
什么是视图:站在不同的角度去看数据(同一张表的数据,通过不同的角度去看待)。

怎么创建视图
create view myview as select ename from emp;
删除视图:
drop view myview;
只有DQL语句才能以视图对象方式创建出来,但是可以对视图进行CRUD操作。
对视图进行增删改查,会影响到原表数据。

create table emp_back as select * from emp;
create view myview as select empno,ename,sal from emp_bak;
update myview set ename=‘hehe’,sal=1 where empno=7369
delete from myview where empno=7369;

视图的作用:
视图可以隐藏表的实现细节,保密级别较高的系统,数据库只对外提供相关的视图,java只能对视图进行CRUD操作。

DBA命令:授权,撤销权限。
将数据库当中的数据导出。
在windows的dos命令窗口中执行。
mysqldump bjpowernode>D:\bjpowernode;(导出数据库)
mysqldump bjpowernode emp>D:\bjpowernode;(导出表)
导入数据
create database bjpowernode;
use database bjpowernode;
source 路径

数据库设计三范式(重点内容)
什么是设计范式
设计表的依据,按照这三个范式
第一范式:每一行必须唯一,也就是每个必须有主键,这就是我们数据库设计的基本要求。
主要通常采用数值模型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。
第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不能产生部分依赖。
虽然确定了主键但是会出现冗余。
多对多?三张表,关系表两个外键。****表的设计关系
t_student 学生表
sno(pk) sname
1 张三
2 李四
3 王五

t_teacher 讲师表
tbo(pk) tname
1 王老师
2 张老师
3 李老师

t_STUDENT_TEACHER_RETION 学生讲师表
id(pd) sno(fk) tno(fk)
1 1 3
2 1 1
3 2 2

第三范式:建立在第二范式的基础之上,所有非主键字段不能产生传递依赖,不能传递传递依赖。
一对多 两张表加外键
班级 t_class

cno(pk) cname
1 a
2 b
学生t_studnet
sno(pk) sname classno(fk)

101 张1 1
101 张1 1
101 张1 1

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

一对一怎么设计:
两种方法:
主键共享
外键唯一
用户信息表。
t_user_login 用户登录表
id(pk) username password

t_user_detail 用户详细信息表
id(pk) realname tel userid(fk+unique)

ceiling 的作用
向上取整,ceil 函数一样效果哦

ceiling 的语法格式
CEILING(X)
CEIL(X)
语法格式说明
返回不小于X的最小整数值

小栗子
SELECT CEILING(1.23); # 2

SELECT CEIL(-1.23); # -1

悲观锁
在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

在数据库中,悲观锁的流程如下:

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。 set autocommit=0;

//0.开始事务

begin;/begin work;/start transaction; (三者选一就可以)

//1.查询出商品信息

select status from t_goods where id=1 for update;

//2.根据商品信息生成订单

insert into t_orders (id,goods_id) values (null,1);

//3.修改商品status为2

update t_goods set status=2;

//4.提交事务

commit;/commit work;

上面的查询语句中,我们使用了 select…for update 的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

上面我们提到,使用 select…for update 会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。

优点与不足

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。

乐观锁
在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。
使用版本号实现乐观锁

使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

1.查询出商品信息

select (status,status,version) from t_goods where id=#{id}

2.根据商品信息生成订单

3.修改商品status为2

update t_goods

set status=2,version=version+1

where id=#{id} and version=#{version};

优点与不足

乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。

看一下InnoDb的表的物理文件
每个表对用两个文件,frm是存储表结构,ibd是存储索引和数据

mysql面试:
mysql的数据是无序的凌乱在内存中
索引的基本原理:
索引用来快速地寻找那些具有特定值的记录,如果没有索引,一般来说执行查询的时候会进行全表扫描。
索引的原理,就是把无序的数据变成有序的查询
1、把创建了索引的列的内容进行排序。
2、对排序结果生成倒排表
3、在倒排表内容上拼上数据地址链
4、在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体的数据。
概念:
索引存储在内存中,为服务器存储引擎为了快速找到记录的一种数据结构。索引的主要作用是加快数据查找速度,提高数据库的性能。
优点:
(1) 创建唯一性索引,保证数据库表中每一行数据的唯一性
(2) 大大加快数据的检索速度,这也是创建索引的最主要的原因
(3) 加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
(4) 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

1、hash查找,把每个数据进行hash值,根据hashcode查询
2、bTree索引 存放的是地址,b-树所有节点存放了键值对,b+树非叶子节点只存键值,不存放数据,只在叶子节点存放了数据。

mysql聚族索引:

一、聚簇索引和非聚簇索引

1、聚簇索引和非聚簇索引:

我拿查字典做一个比喻,字典的页面就好比是物理排列顺序,物理排列顺序是固定的,查询的方式就好比是索引,
区别是聚簇索引就好比是拼音查询,每一个字母查询出来的页面顺序是跟你字母的顺序一致的,a字母查询出来的页面一定是在c字母查询出来的页面前面,
而非聚簇索引就好比是笔画查询,笔画少的查出来的页面不一定在笔画多的查出来的页面前面,也就是你通过笔画查询的顺序和页面的顺序并不是一致的。

再举一例:聚簇索引的顺序就是数据的物理存储顺序,而对非聚簇索引的索引顺序与数据物理排列顺序无关。
举例来说,你翻到新华字典的汉字“爬”那一页就是P开头的部分,这就是物理存储顺序(聚簇索引);而不用你到目录,找到汉字“爬”所在的页码,然后根据页码找到这个字(非聚簇索引)

索引的叶节点就是数据节点。非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块

简单的来说就是聚族索引叶子节点保存了索引跟数据,并且是有顺序的,找到了索引就找到了数据。
非聚族索引就是叶子节点不存放数据,每个叶子节点索引存放的不是数据而是数据的物理地址。
select id,name form where的时候
第二次查询name的时候聚族索引比非聚族索引快,因为name是根id在一起。
聚簇索引的唯一性
       正式聚簇索引的顺序就是数据的物理存储顺序,所以一个表最多只能有一个聚簇索引,因为物理存储只能有一个顺序。
正因为一个表最多只能有一个聚簇索引,所以它显得更为珍贵,一个表设置什么为聚簇索引对性能很关键。

优势:
聚簇索引的查找记录要比非聚簇索引块,因为聚簇索引查找到索引就查找到了数据位置,而非聚簇索引查找到索引之后,根据记录的数据地址,再去查找数据;

一个数据表只能有一个聚簇索引,但可以有多个非聚簇索引;

聚簇索引和非聚簇索引都可以加快查询速度,但同时也都对写入速度会有影响;聚簇索引对写入的速度影响更大一些;

聚族索引对于范围查询效率很高,因为其数据都是按大小排列的。
聚族索引使用在排序的场合,非聚族索引不合适。
劣势:1、维护索引很贵,特别是插入新行和更新的时候,建议在负载较低的时候,通过OPTIMZE TABLE优化表,因为必须被移动的行数据可能造成碎片,
使用独享表空间可以弱化碎片。
2、表因为使用UUID作为主键,使数据存储稀疏,就可能会出现聚族索引有可能比全表扫描更慢,所以建议使用int的auto_increment作为主键。
3、如果主键比较大的话,要辅助聚族索引将会变得更大,因为辅助索引的叶子存储的是主键值,过长的主键值,会导致非叶子节点占用更多的物理空间。

聚集索引,表中存储的数据按照索引的顺序存储,检索效率比普通索引高,但对数据新增/修改/删除的影响比较大
非聚集索引,不影响表中的数据存储顺序,检索效率比聚集索引低,对数据新增/修改/删除的影响很小

innoDB中一定有主键,主键一定是聚族索引,不收的设置,则会使用unique索引,没有unique索引,则会使用数据库内部的一个行的隐藏id
来当做主键索引。在聚族索引之上创建的索引称为辅助索引,辅助索引访问数据总是需要二次查找,非聚族索引都是辅助索引,像复合索引,前缀索引,唯一索引
,辅助索引叶子节点存储的不再是物理地址,而是主键值。
myISm使用的是非聚族索引,没有聚族索引,非聚族索引的两颗B+数看上去没有什么不同,节点的结构完全一致,只是存储的内容不同而已。
主键索引B+树的节点存储了主键,辅助索引B+树存储了辅助键,表数据存储在独立的地方,这两颗B+树的叶子节点,使用一个地址指向真正的表数据,对于表数据来说,这两个键没有
差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

两者使用场景

InnoDB的主键使用的都是聚簇索引,而MyASM无论是主键索引还是二级索引,使用的都是非聚簇索引。

  1. 索引结构
    索引是在Mysql的存储引擎(InnoDB,MyISAM)层中实现的, 而不是在服务层实现的. 所以每种存储引擎的索引都不一定完全相同, 也不是所有的存储引擎都支持所有的索引类型的, Mysql目前提供了以下4种索引:
    B+Tree 索引: 最常见的索引类型, 大部分索引都支持B+树索引.
    Hash 索引: 只有Memory引擎支持, 使用场景简单.
    R-Tree索引(空间索引): 空间索引是MyISAM引擎的一个特殊索引类型, 主要地理空间数据, 使用也很少.
    S-Full-text(全文索引): 全文索引也是MyISAM的一个特殊索引类型, 主要用于全文索引, InnoDB从Mysql5.6版本开始支持全文索引.
    BTree结构
    B+Tree是在BTree基础上进行演变的, 所以我们先来看看BTree, BTree又叫多路平衡搜索树, 一颗m叉BTree特性如下:
    (1) 树中每个节点最多包含m个孩子.
    (2) 除根节点与叶子节点外, 每个节点至少有[ceil(m/2)] 个孩子(ceil函数指向上取整).
    (3) 若根节点不是叶子节点, 则至少有两个孩子.
    (4) 每个非叶子节点由n个Key和n+1个指针组成, 其中 [ceil(m/2) -1 ] <= n <= m-1.
    以5叉BTree为例, key的数量: 公式推导 [ceil(m/2) -1 ] <= n <= m-1.
    所以 2 <= n <= 4, 中间节点分裂父节点,两边节点分裂.
    3.B+Tree 结构
    B+Tree为BTree的变种, B+Tree与BTree的区别:
    1.B+Tree的叶子节点保存所有的key信息, 依key大小顺序排列.
    2.B+Tree叶子节点元素维护了一个单项链表.
    所有的非叶子节点都可以看作是key的索引部分.
    由于B+Tree只有叶子节点保存key信息, 查询任何key都要从root走的叶子. 所以B+Tree查询效率更稳定.
    Mysql中的B+Tree
    MySql索引数据结构对经典的B+Tree进行了优化, 在原B+Tree的基础上, 增加了一个指向相邻叶子节点的链表指针, 就形成了带有顺序指针的B+Tree, 提高区间访问的性能.

hash索引:
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需要一次哈希算法可
立刻定位到响应的位置。速度非常快
lisi-》哈希值(物理地址)-》数据
如果是等值查询,那么哈希索引明星有绝对优势,前提是主键是唯一的,如果不是唯一的,就需要找到该键的位置,然后根据建表往后扫描,找对的数据。
如果是范围查询,哈希索引就没有用武之地了,因为原先有序的键值,警告哈希算法,就可能变成不连续的了,就没有办法利用索引完成范围查询减少。

在谷粒学院中给讲师名称加了索引,给父分类加了索引,给父章节加了索引,索引避免左边模糊匹配,加快查询的。
索引的设计原则:
1、适合索引的列是出现在where子句中的列,或者连接子句中指定的列。
2、基数较小的类,索引效果较差,没有必要在此列建立索引。
3、使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行
是否可能匹配。
4、不要过度索引,索引需要额外的磁盘空间,并降低写操作的性能,在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个事件就会越长,所以只保存需要的索引有利于查询即可。
5、定义有外键的数据列一定要建立索引。
6、更新频繁的索引字段不适合建立索引
7.若是不能有效区分数据的列不适合做索引比如性别,男女未知,就三种,区分度太低。
8、尽量的扩展索引,不要新建索引,比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
9、对于那些查询中很难设计到的列,重复值较多的列不要建立索引,
10、对于定义为text、image和bit的数据类型的列不要建立索引。

  1. 索引的分类(必会)
    (1) 普通索引:最基本的索引,它没有任何限制。
    (2) 唯一索引:与普通索引类似,不同的就是索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
    (3) 主键索引:它是一种特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用 primary key 来约束。
    (4) 联合索引(又叫复合索引):多个字段上建立的索引,能够加速复合查询条件的检索。
    (5) 全文索引:老版本 MySQL 自带的全文索引只能用于数据库引擎为 MyISAM 的数据表,新版本 MySQL 5.6 的 InnoDB 支持全文索引。默认 MySQL 不支持中文全文检索,可以通过扩展 MySQL,添加中文全文检索或为中文内容表提供一个对应的英文索引表的方式来支持中文。

  2. 如何避免索引失效(高薪常问)
    (1) 范围查询, 右边的列不能使用索引, 否则右边的索引也会失效.
    索引生效案例
    select * from tb_seller where name = “小米科技” and status = “1” and address = “北京市”;
    select * from tb_seller where name = “小米科技” and status >= “1” and address = “北京市”;
    索引失效案例
    select * from tb_seller where name = “小米科技” and status > “1” and address = “北京市”;
    address索引失效, 因为status是大于号, 范围查询.
    (2) 不要在索引上使用运算, 否则索引也会失效.
    比如在索引上使用切割函数, 就会使索引失效.
    select * from tb_seller where substring(name, 3, 2) = “科技”;
    (3) 字符串不加引号, 造成索引失效.
    如果索引列是字符串类型的整数, 条件查询的时候不加引号会造成索引失效. Mysql内置的优化会有隐式转换.
    索引失效案例
    select * from tb_seller where name = “小米科技” and status = 1
    (4) 尽量使用覆盖索引, 避免select *, 这样能提高查询效率.
    如果索引列完全包含查询列, 那么查询的时候把要查的列写出来, 不使用select *
    select sellerid, name, status from tb_seller where name = “小米科技” and staus = “1” and address = “西安市”;
    (5) or关键字连接
    用or分割开的条件, 如果or前面的列有索引, or后面的列没有索引, 那么查询的时候前后索引都会失效
    如果一定要用or查询, 可以考虑下or连接的条件列都加索引, 这样就不会失效了.
    • 索引失效案例:
    select * from tb_seller where name = “小米科技” or createTiem = “2018-01-01 00:00:00”;

数据库锁(高薪常问)
1.行锁和表锁
1.主要是针对锁粒度划分的,一般分为:行锁、表锁、库锁,页级锁,记录锁,间隙锁,临键锁。
基于锁的状态分类:意向共享锁,意向排他锁。

行锁:访问数据库的时候,锁定整个行数据,防止并发错误。
表锁:访问数据库的时候,锁定整个表数据,防止并发错误。
2.行锁 和 表锁 的区别:
表锁: 开销小,加锁快,不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
行锁: 开销大,加锁慢,会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
基于锁的分类:意向共享锁,意向排他锁。
共享锁(share lock):
共享锁又称读锁,简称S锁,当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。
共享锁的特性特性是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。
排他锁(exclusive lock):
排他锁又称写锁,简称写锁:当一个事务为数据加上写锁时,其他请求将不能再为数据添加任何锁,直到该锁释放之后,其他事务才能
对数据进行加锁,排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免了出现脏读的问题。
表锁:
表锁是指上锁的时候锁住的是整个表,当一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问。
特点:粒度大,加锁简单,容易冲突。
行锁:
行锁是指上锁的时候锁住的是表的一行或多行记录,其他事务访问同一张表的时候,只有锁住的记录不能访问,其他的记录可
正常访问。
特点:
粒度大,加锁比表锁麻烦,不容易冲突,相对于表锁支持的并发高。
记录锁:
记录锁也属于行锁的一种,只不过记录的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一行锁。
精准命中,并且命中的字段是唯一索引。
加了记录锁之后数据可以避免在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。
页锁:
页锁是mysql中粒度介于行级锁和表锁中间的一种锁,表级锁速度快,但冲突多,行级锁冲突少,但速度慢,所以取了折中的页级,
一次锁定相邻的一组记录。
特点:开销和加锁时间介于表锁和行锁之间,会出现死锁,锁定粒度界于表锁和行锁之间,并发度一般。
间隙锁(Gap lock)
属于行锁的一种,间隙锁是在事务加成后锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙会形成一个区域,遵循左开右闭的原则。
范围查询并且查询未命中记录,在查询条件必须命中索引,间隙锁只会出现在 REPEATABLE_READ(重复读)的事务级别中:
触发条件:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生一个问题:
在同一个事务里,A事务的两次查询结果会不一样。
比如表的数据ID,为1,4,5,7,10,那么就会形成以下几个间隙区间,-n-1区间,1-4区间,7-10区间,10-n区间
(-n代表负无穷大,n代表正无穷大)
临键锁(next-key Lcok)
也属于行锁的一种,并且它是InnoDB的行锁默认算法,总结来说它就是记录锁和间隙锁的结合,临建锁会把查询出来的记录
锁住,同时也会把该范围内的所有间隙空间也会锁住,再之会把下一个区间也会锁住。
触发条件:范围查询并命中,在查询了命中索引。
结合记录锁和间隙锁的特性,临键锁避免了在范围内出现脏读,重复读,幻读问题。
加了临键锁之后,在范围区间内数据不允许被修改和插入。

如果事务A加锁成功之后之后就设置一个状态告诉后面的人,已经有人对表里加了一个排他锁了,你们不能对整个表加共享锁或排他锁了,
那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁了,避免了队整个索引树的每个节点扫描是否加锁,而这个状态就是意向锁。
意向共享锁:
当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁。
意向排他锁
当一个事务试图对整个表进行加排他锁之前,首先需要获得这个表的意向排他锁。

2.悲观锁和乐观锁
(1)悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
(2)乐观锁: 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

按锁粒度从大到小分类:表锁,页锁和行锁;以及特殊场景下使用的全局锁

如果按锁级别分类则有:共享(读)锁、排他(写)锁、意向共享(读)锁、意向排他(写)锁;

以及Innodb引擎为解决幻读等并发场景下事务存在的数据问题,引入的Record Lock(行记录锁)、Gap Lock(间隙锁)、Next-key Lock(Record Lock + Gap Lock结合)等;

还有就是我们面向编程的两种锁思想:悲观锁、乐观锁。
重点:
innodb默认是行锁,没有myIsam默认是表锁。

mysql的sql执行计划详解
explain select * from A where X=? and Y=?

使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈。

explain执行计划包含的信息
这里写图片描述

其中最重要的字段为:id、type、key、rows、Extra

各字段详解
id
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
三种情况:
1、id相同:执行顺序由上至下
这里写图片描述

2、id不同:如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
这里写图片描述

3、id相同又不同(两种情况同时存在):id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
这里写图片描述

select_type
查询的类型,主要是用于区分普通查询、联合查询、子查询等复杂的查询

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
这里写图片描述

type
访问类型,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,遍历全表以找到匹配的行
这里写图片描述

possible_keys
查询涉及到的字段上存在索引,则该索引将被列出,但不一定被查询实际使用

key
实际使用的索引,如果为NULL,则没有使用索引。
查询中如果使用了覆盖索引,则该索引仅出现在key列表中
这里写图片描述
这里写图片描述

key_len
表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。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操作,在找到第一个匹配的元祖后即停止找同样值得动作

综合Case
这里写图片描述

执行顺序
1(id = 4)、【select id, name from t2】:select_type 为union,说明id=4的select是union里面的第二个select。

2(id = 3)、【select id, name from t1 where address = ‘11’】:因为是在from语句中包含的子查询所以被标记为DERIVED(衍生),where address = ‘11’ 通过复合索引idx_name_email_address就能检索到,所以type为index。

3(id = 2)、【select id from t3】:因为是在select中包含的子查询所以被标记为SUBQUERY。

4(id = 1)、【select d1.name, … d2 from … d1】:select_type为PRIMARY表示该查询为最外层查询,table列被标记为 “derived3”表示查询结果来自于一个衍生表(id = 3 的select结果)。

5(id = NULL)、【 … union … 】:代表从union的临时表中读取行的阶段,table列的 “union 1, 4”表示用id=1 和 id=4 的select结果进行union操作。

数据库事务(必会)
1.事务特性
原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
一致性:事务的执行使得数据库从一种正确状态转换成另一种正确状态
隔离性:在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
持久性:事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。
2.隔离级别
(1)读未提交(read Uncommited):
在该隔离级别,所有的事务都可以读取到别的事务中未提交的数据,会产生脏读问题,在项目中基本不怎么用, 安全性太差;
(2) 读已提交(read commited):
这是大多数数据库默认的隔离级别,但是不是MySQL的默认隔离级别;这个隔离级别满足了简单的隔离要求:一个事务只能看见已经提交事务所做的改变,所以会避免脏读问题;
由于一个事务可以看到别的事务已经提交的数据,于是随之而来产生了不可重复读和虚读等问题(下面详细介绍这种问题,结合问题来理解隔离级别的含义);
(3 ) 可重复读(Repeatable read):
这是MySQL的默认隔离级别,它确保了一个事务中多个实例在并发读取数据的时候会读取到一样的数据;不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
(4) 可串行化(serializable):
事物的最高级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争,一般为了提升程序的吞吐量不会采用这个;

ACID靠什么保证的?
原子性

原子性是由 undolog 日志来保存的,它记录了需要回滚的日志信息。
事务回滚时,撤销已经执行成功的 SQL 语句,什么意思?
我们做增、删、改这样一些 SQL 操作,它之前已经保留好一个历史版本数据了,而这个历史版本数据会存在于 undolog 中
我们写一条insert,就会记录一条delete
所以当你进行回滚的时候,它会找到你对应的一个历史版本数据
然后进行回写,把之前成功执行的 SQL 语句给你撤销掉,这个时候就完成了最基本的一个回滚操作,这是原子性对应的一个保证。
持久性

持久性是用什么来保证的?持久性由 redolog来进行保证
当我们要修改数据时,MySQL是先把这条记录所在的「页」(也就是B+树上的叶子节点)找到,然后把该页加载到内存中,在内存中进行修改。
还会写一份redo log,这份redo log记载着这次在某个页上做了什么修改、执行了什么sql。
即便MySQL在中途挂了,我们还可以根据redo log来对数据进行恢复。
隔离性

什么叫隔离性?
我们要保证我事务之间彼此是不会受相互打扰的,每个事务跟每个事务都是相互隔离的。
因此,这个时候需要通过 MVCC 技术来进行实现。
MVCC 是多版本并发控制,这种技术非常麻烦,它包含了非常多的信息。
隔离性是由 MVCC 来保证 -> 出现了RR、RC的隔离情况
一致性

一致性就是事务的目的所在
前面的保证原子性、持久化、隔离性都是为了保证一致性

什么是 MVCC ?
MVCC
MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
mvcc - @百度百科

MVCC 在 MySQL InnoDB 中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读

什么是当前读和快照读?
在学习 MVCC 多版本并发控制之前,我们必须先了解一下,什么是 MySQL InnoDB 下的当前读和快照读?

当前读
像 select lock in share mode (共享锁), select for update; update; insert; delete (排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁

快照读
像不加锁的 select 操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即 MVCC ,可以认为 MVCC 是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

说白了 MVCC 就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现

当前读,快照读和MVCC的关系
MVCC 多版本并发控制是 「维持一个数据的多个版本,使得读写操作没有冲突」 的概念,只是一个抽象概念,并非实现
因为 MVCC 只是一个抽象概念,要实现这么一个概念,MySQL 就需要提供具体的功能去实现它,「快照读就是 MySQL 实现 MVCC 理想模型的其中一个非阻塞读功能」。而相对而言,当前读就是悲观锁的具体功能实现
要说的再细致一些,快照读本身也是一个抽象概念,再深入研究。MVCC 模型在 MySQL 中的具体实现则是由 3 个隐式字段,undo 日志 ,Read View 等去完成的,具体可以看下面的 MVCC 实现原理
MVCC 能解决什么问题,好处是?
数据库并发场景有三种,分别为:

读-读:不存在任何问题,也不需要并发控制
读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失
MVCC 带来的好处是?
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以 MVCC 可以为数据库解决以下问题

在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题
小结一下咯
简而言之,MVCC 就是因为大佬们,不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,因为有了 MVCC,所以我们可以形成两个组合:
MVCC + 悲观锁
MVCC解决读写冲突,悲观锁解决写写冲突
MVCC + 乐观锁
MVCC 解决读写冲突,乐观锁解决写写冲突
这种组合的方式就可以最大程度的提高数据库并发性能,并解决读写冲突,和写写冲突导致的问题

MVCC 的实现原理
MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3个隐式字段,undo日志 ,Read View 来实现的。所以我们先来看看这个三个 point 的概念

隐式字段
每行记录除了我们自定义的字段外,还有数据库隐式定义的 DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID 等字段

DB_TRX_ID
6 byte,最近修改(修改/插入)事务 ID:记录创建这条记录/最后一次修改该记录的事务 ID
DB_ROLL_PTR
7 byte,回滚指针,指向这条记录的上一个版本(存储于 rollback segment 里)
DB_ROW_ID
6 byte,隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以DB_ROW_ID产生一个聚簇索引
实际还有一个删除 flag 隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除 flag 变了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值