笔记开始日期:2023年12月1日 笔记最新更新日期:2024年1月25日 笔记更新状态:MySQL基础和MySQL进阶已完结,MySQL运维待日后择期更新。
你好:
首先感谢你使用这份笔记手册,一起学习,一起进步,本学习笔记是我在自学过程(网课视频在下方链接)中的随手笔记,可能出现遗漏,顺序错误或语法,单词等错误,你可以在自己的学习过程中对这份笔记更正即可。
学习参考网课资料资料:https://www.bilibili.com/video/BV1Kr4y1i7ru/ 相关资料可在黑马程序员官网或视频下方评论区下载
本笔记文档所用到的软件 MySQL版本:8.0.35 MySQL Community server-GPL 可视化开发工具:DataGrip-2023.3.2 MySQL官方说明文档:MySQL :: MySQL Documentation
由于图片路径问题,笔记中的图片可能出现无法正常显示得到问题,请谅解。
说明到此结束下面是正文内容 :
待补充
云服务器或者虚拟机都可以;
Linux的版本为 CentOS7;
虚拟机安装linux系统方法可自行搜索。
https://downloads.mysql.com/archives/community/
xxxxxxxxxx
31mkdir mysql
2192.168.237.129
3tar -xvf mysql-8.0.26-1.el7.x86_64.rpm-bundle.tar -C mysql
xxxxxxxxxx
201cd mysql
2
3rpm -ivh mysql-community-common-8.0.26-1.el7.x86_64.rpm
4
5rpm -ivh mysql-community-client-plugins-8.0.26-1.el7.x86_64.rpm
6
7rpm -ivh mysql-community-libs-8.0.26-1.el7.x86_64.rpm
8若提示mariadb-libs 被 mysql-community-libs-8.0.26-1.el7.x86_64 取代
9执行yum remove mysql-libs
10
11rpm -ivh mysql-community-libs-compat-8.0.26-1.el7.x86_64.rpm
12
13yum install openssl-devel
14
15rpm -ivh mysql-community-devel-8.0.26-1.el7.x86_64.rpm
16
17rpm -ivh mysql-community-client-8.0.26-1.el7.x86_64.rpm
18
19rpm -ivh mysql-community-server-8.0.26-1.el7.x86_64.rpm
20
xxxxxxxxxx
11systemctl start mysqld
xxxxxxxxxx
11systemctl restart mysqld
xxxxxxxxxx
11systemctl stop mysqld
xxxxxxxxxx
11grep 'temporary password' /var/log/mysqld.log
命令行执行指令 :
xxxxxxxxxx
11mysql -u root -p
然后输入上述查询到的自动生成的密码, 完成登录 .
登录到MySQL之后,需要将自动生成的不便记忆的密码修改了,修改成自己熟悉的便于记忆的密码。
xxxxxxxxxx
11ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
执行上述的SQL会报错,原因是因为设置的密码太简单,密码复杂度不够。我们可以设置密码的复杂度为简单类型,密码长度为4。
xxxxxxxxxx
21set global validate_password.policy = 0;
2set global validate_password.length = 6;
降低密码的校验规则之后,再次执行上述修改密码的指令。
默认的root用户只能当前节点localhost访问,是无法远程访问的,我们还需要创建一个root账户,用户远程访问
xxxxxxxxxx
11create user 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
xxxxxxxxxx
11grant all on *.* to 'root'@'%';
xxxxxxxxxx
11mysql -u root -p
然后输入密码
专业版收费,社区版免费
如需安装激活,请自行百度激活码和激活工具
单行注释:--注释内容或#注释内容
多行注释:/注释内容/
DDL
DMI
DQL
DCL
方法1: WIN+R打开运行,输入services.msc,找到MySQL80,选择启动或停止
方法2: 打开命令行(cmd),输入下面的指令 启动:net start mysql80 停止:net stop mysql80
方法1:使用MySQL提供的客户端命令行工具
方法2:使用windows的命令行工具连接 打开CMD控制台:输入mysql [-h 127.0.0.1] [-p 3306] -u root -p
[-h 127.0.0.1] [-p 3306]可以省略
关系型数据库(RDBMS): 概念:建立在关系模型基础上的,由多张相互连接的二维表组成的数据库;
特点:
使用表存储数据,格式统一,便于维护。
使用SQL语言操作,标准统一,使用方便。
查询所有数据库:
xxxxxxxxxx
11SHOW DATABASES;
查询当前数据库:
xxxxxxxxxx
11SELECT DATABASE();
xxxxxxxxxx
11CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则]
xxxxxxxxxx
11DROP DATABASE[IF EXISTS]数据库名;
xxxxxxxxxx
11USE 数据库名;
xxxxxxxxxx
81CREATE TABLE 表名{
2字段1 字段类型[COMMENT 字段1注释],
3字段2 字段类型[COMMENT 字段2注释],
4字段3 字段类型[COMMENT 字段3注释],
5......
6字段n 字段类型[COMMENT 字段n注释]
7}[COMMENT 表注释];
8#最后一个不要加,
例如:创建一个员工信息表
xxxxxxxxxx
81create table emp{
2id int comment '编号',
3name varchar(10) comment '姓名',
4genner char(1) comment '年龄',
5age tinyint unsined comment '年龄',
6idcard char(18) comment '身份证号',
7entrydate date comment '入职时间'
8}comment '员工表’;
添加字段
xxxxxxxxxx
11alter table 表名 add 字段名 类型(长度) [comment 注释][约束];
修改数据类型
xxxxxxxxxx
11alter table 表名 modify 字段名 新数据类型(长度);
修改字段名和字段类型
xxxxxxxxxx
11alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释][约束];
案例:
xxxxxxxxxx
11alter table emp change nickname username varchhar(30) comment'昵称'
删除字段:
xxxxxxxxxx
11alter table 表名 drop 字段名;
案例:删除emp中的username
xxxxxxxxxx
11alter table emp drop username;
修改表名:
xxxxxxxxxx
11alter table 表名 rename 新表名;
案例:
xxxxxxxxxx
11alter table emp rename to employee;
删除表:
xxxxxxxxxx
41#方法1:删除表(常用这个)
2drop table [if exists]表名;
3#方法2:删除指定表,并重新创建该表;
4truncate table 表名;
数值类型:
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 Bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 Bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
字符串类型:
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255 bytes | 定长字符串 |
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
日期类型:
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59' | YYYY-MM-DD hh:mm:ss | 混合日期和时间值 |
TIMESTAMP | 4 | '1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYY-MM-DD hh:mm:ss | 混合日期和时间值,时间戳 |
xxxxxxxxxx
101#查询表中前三条数据
2
3select * from 表名 limit 3;
4
5#查询表中从第二条数据开始,向后数3条
6
7select * from student limit 1,3;
8
9#查询所有数据
10select * from 表名;
给指定字段添加数据
xxxxxxxxxx
11insert into(字段1,字段2,....) values (值1,值2,...)
给全部字段添加数据
xxxxxxxxxx
11insert into 表名 values(值1,值2,...)
批量添加数据
xxxxxxxxxx
11insert into 表名(字段1,字段2,...) values(值1,值2,...),(值1,值2,...),(值1,值2,...)
xxxxxxxxxx
11insert into 表名 values()(值1,值2,...),(值1,值2,...),(值1,值2,...)
xxxxxxxxxx
11update 表名 set 字段名1 = 值1,字段名2=值2,...[where 条件];
xxxxxxxxxx
11delete from 表名 where 条件
xxxxxxxxxx
71select #字段列表
2from #表名
3where #条件列表
4group by #分组字典列表
5having #分组后条件列表
6order by #排序字段列表
7limit #分页参数
xxxxxxxxxx
81#查询多个字段
2select 字段1,字段2,字段n from 表名;
3select * from 表名; #查询全部数据
4#查询某个字段并为其起一个别名
5select 字段1 as 'name' from 表名;
6select 字段1 'name' from 表名;
7#去除重复数据查询
8select distinct 字段1 from 表名;
基本语法:
xxxxxxxxxx
11select 字段列表 from 表名 where 条件;
条件:
比较运算符 | 功能 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
= | 等于 |
<>或!= | 不等于 |
between...and... | 在某个范围内(包含最小值和最大值) |
in(...) | 在in之后的列表中的值,多选1 |
like 占位符 | 模糊匹配(_匹配单个字符,%匹配任意个字符) |
is null | 是null |
逻辑运算符 | 功能 |
---|---|
and或&& | 并且(多个条件同时成立) |
or或|| | 或者(多个条件任意一个成立) |
not或! | 非,不是 |
xxxxxxxxxx
171#案例
2-- 查询年龄为20岁的人
3select * from user where age = 20;
4-- 查询年龄小于20岁的人
5select * from user where age < 20;
6-- 查询没有身份证号的人
7select * from user where idcard is null;
8-- 查询年龄在15-20岁的人
9select * from user where age >=15 && age <=20;
10select * from user where age >=15 and age <=20;
11select * from user where between 15 and 20;
12-- 身份证号最后一位为X的人
13select * from user where idcard like '%X';
14-- 查询姓名为2个字符的人
15select * from user where name like '__';
16-- 查询姓名为3个字符的人
17select * from user where name like '___';
常见的聚合函数
函数 | 功能 |
---|---|
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
xxxxxxxxxx
121# 聚合函数案例
2# 注意 所有null不参与聚合函数的运算
3-- 1.统计员工数量
4select count(*) from user;
5-- 2.统计平均年龄
6select avg(age) from user;
7-- 3.统计最大年龄
8select max(age) from user;
9-- 4.统计最小年龄
10select min(age) from user;
11-- 5.统计员工年龄之和
12select count(age) from user;
语法:
xxxxxxxxxx
21#分组查询的基本语法
2select 字段列表 from 表名[where 条件] group by 分组字段名 [having 分组后过滤条件];
where 和 having 的区别
执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对分组结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以;
xxxxxxxxxx
61# 根据性别分组 统计男员工和女员工的数量
2select genner,count(*) from emp group by genner;
3# 根据性别分组 统计男性员工和女性员工平均年龄
4select genner,avg(age) from emp group by genner;
5# 查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址;
6select * from emp where age<45 group by workaddress having count(*)>=3;
基本语法
xxxxxxxxxx
11select 字段列表 from 表名 order by 字段1 排序方式1,字段2 排序方式2; # (支持多字段排序)
排序方式
ASC:升序;(默认)
DESC:降序
注意:!若多字段排序,第一个字段值相同时,才会根据第二个字段排序
xxxxxxxxxx
21# 根据年龄排序,若年龄相同 则按照入职时间进行降序排序
2select * from users order by age asc, joindate desc;
xxxxxxxxxx
21# 基本语法
2select 字段列表 from 表名 limit 起始索引,查询记录数;
注意:
起始索引是从0开始的,起始索引=(页码-1)*每页显示记录数
分页查询时数据库的方言,不同数据库有不同的语法,MySQL是limit
如果查询的是第一页的数据,起始索引可以省略,直接写limit 10;
xxxxxxxxxx
61# 查询前三条数据
2select * from 表名 limit 3;
3# 查询第一页的数据,每页展示10条
4select * from 表名 limit 0,10;
5# 查询第2页的数据,每页展示10条
6select * from 表名 limit 10,10;
from→where→group by→select→order by→limit
xxxxxxxxxx
101# 查询员工年龄为20 21 22 23岁的女员工信息
2select * from users where genner ='女' and in(20,21,22,23);
3# 查询性别为男,并且年龄再20-40岁的姓名为3个字的员工
4select * from users where age between 20 and 40 && genner = '男' and name like '___'
5# 统计表中年龄小于60的男员工和女员工的人数
6select genner, count(*) from users where age <= 60 group by genner ;
7# 查询所有年龄小于等于35岁的员工的姓名和年龄,并对查询结果按年龄升序排序,如果年龄相同按入职时间降序排序。
8select name,age from users order by age asc, joindate desc;
9#查询性别为男,且年龄在20-40岁以内的前五个员工信息,对查询的结果按年龄升序排序,年龄相同按入职时间升序排序。
10select * from users where genner = '男' and age between 20 and 40 order by age,joindate desc limit 5;
查询用户
xxxxxxxxxx
21use mysql;
2select * from users;
创建用户
xxxxxxxxxx
11create users '用户名'@'主机名' identified by '密码';
修改用户密码
xxxxxxxxxx
11alter users '用户名'@'主机名' identified with musql_password by '新密码';
删除用户
xxxxxxxxxx
11drop users '用户名'@'主机名';
函数 | 功能 |
---|---|
concat(s1,s2,......,sn) | 字符串拼接,把s1,s2,......,sn拼接成字符串 |
lower(str) | 把字符串str全部转换为小写 |
upper(str) | 把字符串str全部转换为大写 |
lpad(str,n,pad) | 左填充,用字符串pad对str的左边进行填充,达到N个字符串长度 |
rpad(str,n,pad) | 右填充,用字符串pad对str的右边进行填充,达到N个字符串长度 |
trim(str) | 去掉字符串头部和尾部的空格 |
substring(str,start,len) | 返回从字符串str位置起的len个长度的字符串 |
使用语法:
xxxxxxxxxx
11select 函数(参数);
xxxxxxxxxx
21-- 业务变更,修改企业员工工号长度为5位,不足五位的在前面补0
2update 表名 set workno = lpad(workno,5,'0')
函数 | 功能 |
---|---|
ceil(x) | 向上取整 |
floor(x) | 向下取整 |
mod(x,y) | 返回x/y模(取余数) |
rand() | 返回0-1内的随机数 |
round(x,y) | 求参数x的四舍五入的值,保留Y位小数 |
xxxxxxxxxx
11select 函数(参数);
xxxxxxxxxx
21-- 生成6位随机数
2select lpad(ceil(rand()*1000000),6,'0')
函数 | 功能 |
---|---|
curdate() | 返回当前日期 |
curtime() | 返回当前时间 |
now() | 返回当前时间和日期 |
year(date) | 返回date的年份 |
month(date) | 返回date的月份 |
day(date) | 返回date的日期 |
date_add(date,interval expr type) | 返回一个日期/时间值加上一个时间间隔后的时间值 |
datediff(date1,date2) | 返回起始时间date1和终止时间date2之间的天数(date1-date2) |
xxxxxxxxxx
31# date_add(date,interval expr type)语法应用
2select date_add(now(),interval 70 day)
3# 从今天往后推70天的日期
案例
xxxxxxxxxx
21# 查询所有员工的入职天数,并进行倒序排序
2select name,datediff(curdate(),joindate) from users other by datediff(curdate(),joindate) desc;
函数 | 功能 |
---|---|
if(value,t,f) | 如果值为value返回t否则返回f |
ifnull(value1,value2) | 如果value1不为空返回value1,狗则返回value2 |
case when [val1] then [res1] ...else [default] end | 如果val1为true,返回res1,...否则返回default默认值 |
case [expr] when [val1] then [res1] ...[else] [default] end | 如果expr的值等于val1,返回res1,...否则返回default默认值 |
xxxxxxxxxx
41select
2 name,
3 (case genner when '男' then '男孩子' else '女孩子' end )as sex
4from user order by sex desc ;
案例
学生成绩表
id | name | math | chinese | english |
---|---|---|---|---|
2101 | 张三 | 21 | 99 | 55 |
2102 | 李四 | 60 | 74 | 43 |
2103 | 王五 | 87 | 34 | 98 |
2104 | 赵六 | 50 | 33 | 65 |
xxxxxxxxxx
61# 查询学生成绩,80分以上为优秀,60以上及格,60以下为不及格
2select id, name,
3 (case when math>=80 then '优秀' when math>=60 then '及格' else '不及格' end) as '数学',
4 (case when chinese>=80 then '优秀' when chinese>=60 then '及格' else '不及格' end) as '语文',
5 (case when english>=80 then '优秀' when english>=60 then '及格' else '不及格' end) as '英语'
6 from user;
一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性。MySQL数据库通过约束(constraints)防止无效的数据进入到表中,以保护数据的实体完整性。
约束 | 描述 | 关键字 |
---|---|---|
非空约束 | 限制该字段的数据不能为空 | not null |
唯一约束 | 保证该字段的所有数据都是唯一的,不重复的 | unique |
主键约束 | 主键是一行数据的唯一标识,非空且唯一 | primary key |
默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 | default key |
检查约束 | 保证字段满足某一条件 | check |
外键约束 | 让两张表的数据时间建立连接,保证数据一致性和完整性 | foreign key |
根据下面的条件创建一张表
字段名 | 字段含义 | 字段类型 | 约束条件 | 约束关键字 |
---|---|---|---|---|
id | id唯一标识 | int | 主键,自动增长 | primary key,auto_increment |
name | 姓名 | varchar(10) | 不为空且唯一 | not null,unique |
age | 年龄 | int | 大于0,小于120 | check |
status | 状态 | char(1) | 若没有该值,默认为1 | default |
genner | 性别 | char(1) | 无 |
xxxxxxxxxx
81# 根据约束创建一个新表
2create table users(
3 id int primary key auto_increment comment '主键',
4 name varchar(10) not null unique comment '姓名',
5 age int check (age >0&&age<=120 ) comment '年龄',
6 status char(1) default (1) comment '状态',
7 genner char(1) comment '性别'
8) comment '用户表';
外键相关语法
添加外键
xxxxxxxxxx
81# 方法1 创建表时添加
2create table 表名(
3字段名 数据类型,
4......
5[constraint] [外键名称] foreign key(外键字段名) references 主表(主表列名);
6);
7# 方法2 表创建完成后追加
8alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名);
删除外键
xxxxxxxxxx
11alter table 表名 drop foreign key 外键名称;
外键删除/更新行为
行为 | 说明 |
---|---|
no action | 当父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 |
restrict | 当父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 |
cascade | 当父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录 |
set null | 当父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键的值为Null |
set default | 父表有变更时,子表将外键设置成一个默认的值(innodb不支持)。 |
语法
xxxxxxxxxx
11alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名) on update cascade on delete cascade;
表1:员工表(a1)(子表)
name | bumen_id |
---|---|
name1 | 4 |
name2 | 3 |
name3 | 2 |
name4 | 1 |
name5 | 5 |
表2:部门表(a2)(父表)
id | bumen |
---|---|
1 | 后勤部门 |
2 | 设计部门 |
3 | 策划部门 |
4 | 营销部门 |
5 | 管理部门 |
xxxxxxxxxx
11alter table a1 add constraint fk_a1_a2_id foreign key(bumen_id) references a2(bumen);
一对多(多对一),多对多,一对一。
1.概述:从多张表中查询数据。
2.笛卡尔积:AB两个集合的所有组合情况。(在多表查询中,需要消除无效的笛卡尔积) 如何消除笛卡尔积:
学生表(users)
id | name | age | class_choose | genner |
---|---|---|---|---|
1 | 张三 | 12 | 1 | 男 |
2 | 李四 | 12 | 1 | 女 |
3 | 王五 | 12 | 2 | 男 |
4 | 赵六 | 12 | 2 | 女 |
课程编号表(class)
class_id | class_name |
---|---|
1 | 语文 |
2 | 数学 |
xxxxxxxxxx
31select * from 表1,表2 where 字段1=字段2;
2-- 例如在两个表中查询学生选课情况
3select id, name, genner, class_name from users,class where users.class_choose= class.class_id;
3.分类:
连接查询 内连接:相当于查询A、B交集部分数据。
外连接:
左外连接,查询左表所有数据,以及两张表交集部分数据。
右外连接,查询右表所有数据,以及两张表交集部分数据。
自连接:当前表与自身的连接查询,自连接必须使用表别名。
隐式内连接
xxxxxxxxxx
41select 字段列表 from 表1,表2 where 条件......;
2-- 案例
3select id, name, genner, class_name from users,class where users.class_choose=class.class_id;
4
显式内连接
xxxxxxxxxx
41select 字段列表 from 表1 inner[可省略] join 表2 on 连接条件;
2-- 案例
3select id, name, genner, class_name from users inner join class on users.class_choose=class.class_id;
4
左外连接
xxxxxxxxxx
11select 字段列表 from 表1 left outer join 表2 on 条件...;
右外连接
xxxxxxxxxx
11select 字段列表 from 表1 right outer join 表2 on 条件...;
案例
xxxxxxxxxx
41# 外连接(左)
2select id, name, genner, class_name from users left join class on users.class_choose=class.class_id;
3# 外连接(右)
4select id, name, genner, class_name from users right outer join class on users.class_choose=class.class_id;
自连接查询语法
xxxxxxxxxx
11select 字段列表 from 表A 别名a join 表B 别名b on 条件...;
自连接查询可以是内连接查询,也可以是外连接查询。
查询员工及其所属领导的姓名
xxxxxxxxxx
11select a.name,b.name from 表1 a join 表1 b on a.mangerid= b.id
概念:在SQL语句中嵌套select语句。
语法
xxxxxxxxxx
11select * from 表A where 字段1 = (select 字段2 from 表B);
子查询中,外部语句可以是增(insert)删(delete)改(update)查(select)的任何一个;
子查询类型 标量子查询(子查询结果为单个值) 列子查询(子查询结果为一列) 行子查询(子查询结果为一行) 表子查询(子查询结果为多行多列)
常用操作符:= ,<> ,> ,< ,>= ,<=
常用操作符:in , not in , any , some ,all
操作符 | 描述 |
---|---|
in | 在指定的集合内,多选1 |
not in | 不在指定的集合范围内 |
any | 子查询返回的列表中,有任意一个满足即可 |
some | 与any等同,使用some的地方都可以使用any |
all | 子查询返回列表中的所有这些值必须都满足 |
常用操作符:=,<>,in,not in
常用操作符:in
xxxxxxxxxx
11select * from 表A where (字段1,字段2) in (子查询);
xxxxxxxxxx
41-- 子查询
2select users.money, age from users where name='李丽丽' or name='张丁丁';
3-- 查询表
4select * from users where (money,age) in (select users.money, age from users where name='李丽丽' or name='张丁丁');
xxxxxxxxxx
71-- 联合查询语法
2select 字段列表 from 表A...
3union[all]
4select 字段列表 from 表B...;
5-- union all和union的区别
6union all -- 直接将两次结果合并
7union -- 将两次结果去重后再进行合并
联合查询注意事项:! 多张表列数必须相同,字段数据类型也必须相同
union all -- 直接将两次结果合并,union -- 将两次结果去重后再进行合并
根据需求,编写SQL语句
查询员工的姓名、年龄、职位、部门信息。
查询年龄小于30岁的员工姓名、年龄、职位、部门信息。
查询拥有员工的部门ID、部门名称。
查询所有年龄大于40岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来。
查询所有员工的工资等级。
查询“研发部”所有员工的信息及工资等级。
查询“研发部”员工的平均工资。
查询工资比“灭绝”高的员工信息。
查询比平均薪资高的员工信息。
查询低于本部门平均工资的员工信息。
查询所有的部门信息,并统计部门的员工人数。
查询所有学生的选课情况,展示出学生名称,学号,课程名称
员工表(emp)
name | age | money | work | wkbm_id |
---|---|---|---|---|
张三 | 33 | 7000 | 经理 | 1 |
李莉 | 23 | 3000 | 销售 | 5 |
李斯 | 34 | 4000 | 销售 | 5 |
王刚 | 24 | 5000 | 研发 | 2 |
刘畅 | 36 | 2000 | 设计 | 3 |
王丽丽 | 37 | 3970 | 设计 | 3 |
黄旭 | 28 | 3330 | 生产 | 4 |
吴凡范 | 26 | 4350 | 生产 | 4 |
蔡徐坤 | 43 | 5700 | 生产 | 4 |
部门表(work_ids)
ids | bumem |
---|---|
1 | 财管部 |
2 | 研发部 |
3 | 设计部 |
4 | 生产部 |
5 | 销售部 |
6 | 公关部 |
工资等级表(salgarde)
grade | losal | hisal |
---|---|---|
1 | 0 | 1000 |
2 | 1001 | 2000 |
3 | 2001 | 3000 |
4 | 3001 | 4000 |
5 | 4001 | 5000 |
6 | 5001 | 6000 |
7 | 6001 | 7000 |
8 | 7001 | 8000 |
xxxxxxxxxx
241-- 1. 查询员工的姓名、年龄、职位、部门信息。
2select name,age,work,bumen from emp e, work_ids w where e.wkbm_id = w.ids;
3-- 2. 查询年龄小于30岁的员工姓名、年龄、职位、部门信息。
4select name,age,work,bumen where from emp,work_ids age<30 and e.wkbm_id = w.ids;
5-- 3. 查询拥有员工的部门ID、部门名称。
6
7-- 4. 查询所有年龄大于40岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来。
8
9-- 5. 查询所有员工的工资等级。
10
11-- 6. 查询“研发部”所有员工的信息及工资等级。
12
13-- 7. 查询“研发部”员工的平均工资。
14
15-- 8. 查询工资比“灭绝”高的员工信息。
16
17-- 9. 查询比平均薪资高的员工信息。
18
19-- 10. 查询低于本部门平均工资的员工信息。
20
21-- 11. 查询所有的部门信息,并统计部门的员工人数。
22
23-- 12. 查询所有学生的选课情况,展示出学生名称,学号,课程名称
24
事务:是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
查询、设置事务提交方式
xxxxxxxxxx
61-- 查看设置事务提交方式
2-- 查询
3select @@autocommit;
4-- 设置
5set @@autocommit=0;
6-- 0为手动提交,1为自动提交
提交事务
xxxxxxxxxx
21-- 若为手动提交,需执行以下指令提交事务
2commit;
回滚事务
xxxxxxxxxx
21-- 数据出现异常时回滚事务
2rollback;
开启事务
xxxxxxxxxx
31start transaction
2--或
3begin
表名:account
id | name | money |
---|---|---|
1 | 张三 | 2000 |
2 | 李四 | 2000 |
完成张三为李四转账的操作:
xxxxxxxxxx
221-- 1.查询张三余额
2select * from account where name='张三';
3-- 2.把张三余额-1000
4update account set money = money-1000 where name='张三';
5-- 3.把李四余额+1000
6update account set money = money+1000 where name='李四';
7
8
9
10-- 使用事务控制实现
11start transaction ;
12-- 1.查询张三余额
13select * from account where name='张三';
14-- 2.把张三余额-1000
15update account set money = money-1000 where name='张三';
16-- 3.把李四余额+1000
17update account set money = money+1000 where name='李四';
18-- 手动提交事务
19commit;
20-- 数据出现异常时回滚事务
21rollback;
22
原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
一致性(Consistency):事务完成时,必须使所有数据都保持一致状态。
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
问题 | 描述 |
---|---|
脏读 | 一个事务读到另外一个事务还没有提交的数据。 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 |
幻读 | 一个事务按条件查询数据时,没有对应的数据行,但在插入数据时,又发现这行数据已经存在了,好像出现了’幻影‘。 |
不可重复读
事务A第一步查询后,事务B将数据进行了修改,此时事务A第三步再次查询时,与第一步查询得到的数据不同!称之为不可重复读。
不同隔离级别下,会出现的并发事务问题
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted(读未提交) | √ | √ | √ |
read committed(读已提交) | × | √ | √ |
repeatable read(默认)(可重复读) | × | × | √ |
serializable(串行化) | × | × | × |
注意:!表中,事务隔离级别从上到下依次升高,事务隔离级别越高,数据安全性越高,但性能越低。
查看和设置事务隔离级别
xxxxxxxxxx
51-- 查看事务隔离级别
2select @@transaction_isolation;
3-- 设置事务隔离级别
4set [session|global] transaction isolation level {(事务隔离等级)read uncommitted|read committed|repeatable read|serializable};
5-- session :只对当前会话生效 | global :对所有会话生效;
serializable(串行化):在并发事务操作时,只允许一个事务执行。
学习过程
存储引擎就是存储数据,建立索引,更新查询数据等技术的实现方式。存储引擎是基于数据库的表的,而不是基于数据库的,所以存储引擎也被称为表类型。
在创建表时,指定存储引擎的方式:
xxxxxxxxxx
51create table 表名(
2 字段1.....
3 字段2.....
4
5)engine = innodb comment'注释';
查询当前数据库支持的存储引擎
xxxxxxxxxx
11show engines;
介绍:
Innodb引擎是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL5.5以后,Innodb是MySQL的默认存储引擎
特点:
DML操作遵循ACID模型,支持事务;
行级锁,提高并发访问性能;
支持外键约束,保证数据的完整性和正确性;
文件:
XXX.ibd:xxx为表名,Innodb引擎的每张表都会对应这样一个表空间文件,存储该表的结构(frm,sdi)、数据、索引
参数:Innodb_file_per_table
逻辑存储结构
tablespece:表空间
segment:段
extent:区
page:页
row:行
介绍:
MyISAM引擎是MySQL早期的默认存储引擎。
特点:
不支持事务,不支持外键;
支持行锁,不支持表锁;
访问速度快;
文件:
xxx.sdi:存储表结构信息;
xxx.MYD:存储数据;
xxx.MYI:存储索引;
介绍:
Memory引擎的表数据存储在内存中,由于受到硬件或断电的影响,只能将这些表作为临时表或缓存来使用。
特点:
内存存放(访问速度快)
hash索引(默认)
文件:
xxx.sdi:存储表结构信息
特点 | innodb | myisam | memory |
---|---|---|---|
存储限制 | 64TB | 有 | 有 |
事务安全 | 支持 | - | - |
锁机制 | 行锁 | 表锁 | 表锁 |
B+tree索引 | 支持 | 支持 | 支持 |
Hash索引 | - | - | 支持 |
全文索引 | 支持(5.6版本之后) | 支持 | - |
空间使用 | 高 | 低 | N/A |
内存使用 | 高 | 低 | 中等 |
批量插入速度 | 低 | 高 | 高 |
支持外键 | 支持 | - | - |
存储引擎没有好坏之分,在选择存储引擎时,应根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。
InnoDB:是Mysql的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。
MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。
MEMORY:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就叫索引
在无索引时,通过全表扫描进行查询,效率极低
在有索引时,通过对应的数据结构进行查询,更加高效。
索引的优缺点:
优点:
提高数据检索的效率,降低数据库的IO成本
通过索引列对数据进行排序,降低数据排序成本,降低CPU消耗。
缺点
索引列也要占用空间
索引大大提高了查询效率,同时也降低了更新表的速度,如对表进行insert,update,delete时,效率降低。
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含以下几种:
索引结构 | 描述 |
---|---|
B+tree索引 | 最常见的索引类型,大部分引擎都支持B+tree索引 |
hash索引 | 底层数据结构是用哈希表实现的,只有精确匹配索引的查询才有效,不支持范围查询。 |
r-tree(空间索引) | 空间索引是Myisam引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少。 |
full-text(全文索引) | 是一种通过建立倒排索引,快速匹配文档的方式,类似于Lucene,solr,es |
不同索引结构在不同存储引擎中的支持情况
索引 | INNODB | myisam | memory |
---|---|---|---|
B+Tree | YES | YES | YES |
Hash | NO | NO | YES |
R-Tree | NO | YES | NO |
Full-text | 5.6版本后支持 | YES | NO |
B-tree(多路平衡查找树)
以一颗最大度数(max-degree)为5(5阶)的b-tree为例(每个节点最多存储四个KEY,5个指针):
当key数量大于4时,中间元素向上分裂。
B-tree数据结构可视化网站:https://www.cs.usfca.edu/~galles/visualization/BTree.html
树的度数:一个节点最多子节点个数。
B+Tree
以一颗最大度数为4的B+tree为例:
B+tree与 B-tree不同的是:
所有元素数据都会出现在叶子节点,非叶子节点起索引作用
所有叶子节点之间形成单向链表
B+tree图形化页面:https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
MySQL中B+Tree索引结构
mysql索引数据结构对经典的B+Tree进行了优化。在原B+Tree基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高了区间访问的性能。
Hash索引
哈希索引就是采用一定是的哈希算法,将键值换算成新的hash值,映射到对应的槽位上,然后储存在hash表中。
如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突,也称hash碰撞,可以通过链表来解决。
hash索引的特点
hash索引只能用于对等比较(=,in),不支持范围查询(between,>,<,......)
无法利用索引完成排序操作。
查询效率高,通常只需要一次检索就可以,效率通常高于B+tree索引。
hash在存储引擎支持情况
在MySQL中,支持hash索引的是memory引擎,而innodb中具有自适应hash功能,hash索引是存储引擎根据B+tree索引在指定条件下自动构建的。
问题思考
为什么innodb选择B+tree
相对于二叉树,层级更少,搜索效率更高。
对于B+tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低。
相对Hash索引,B+tree支持范围匹配及排序操作。
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对于表主键创建的索引 | 默认自动创建,只能有一个 | primary |
唯一索引 | 避免同一个表中某列数据中的值重复 | 可以有多个 | unique |
常规索引 | 快速定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键字,而不是比较索引的值 | 可以有多个 | fulltext |
在innodb存储引擎中,根据索引储存的形式,又可以分为以下两种 :
分类 | 含义 | 特点 |
---|---|---|
聚集索引(clustered index) | 将数据与索引存储到一起,索引结构的叶子节点保存了行数据。 | 必须有,且只有一个 |
二级索引(secondary index) | 将数据与索引分开存储,索引结构的叶子节点关联对应的主键。 | 可以存多个 |
聚集索引选取规则:
如果存在主键,逐渐就是聚集索引。
如果不存在主键,将使用第一个唯一索引作为聚集索引。
如果表没有主键,或没有合适的唯一索引,则innodb会自动生成一个rowid作为隐藏的聚集索引。
聚集索引叶子节点挂的是这个索引对应的一行的数据
二级索引挂的是这一行对应的id数据,而非全部数据。
创建索引
索引名命名:idx_ 表名 _字段名
xxxxxxxxxx
11create [unique|fulltext] index index_name on table_name (字段名1,...);
查看索引
xxxxxxxxxx
11show index from 表名;
删除索引
xxxxxxxxxx
11drop index 索引名 on 表名;
查看和分析SQL性能的四种方式:
查询SQL执行频率
在MySQL客户端连接成功后,通过show [global | session] status 指令可以提供服务器状态信息。通过如下指令,可以查询当前数据库insert,update,delete,select的访问频次。
xxxxxxxxxx
11show [global | session] status like 'com_____'
慢查询日志
慢查询日记录了所有执行时间超过指定参数(long_query_time,单位:s,默认10s)的所有SQL语句的日志,MySQL的慢查询日志默认是没有开启的,需要在MySQL配置文件/etc/my.cnf中配置如下信息。
xxxxxxxxxx
41# 开启MySQL慢日志查询开关
2show_query_log = 1
3#设置慢日志的时间为2s,SQL语句执行超过2s就会被是为慢查询,记录在慢查询日志中
4long_query_time=2
xxxxxxxxxx
21-- 查询慢查询日志开启或关闭状态
2show variables like 'slow_query_log'
方法:
打开linux控制台,修改文件:vi /etc/my.cnf
插入:show_query_log = 1和long_query_time=2
在/var/lib/mysql目录下可以看到localhost-slow.log
查看日志:cat localhost-slow.log
profile详情
使用 show profile 能够在做SQL优化时帮助我们了解时间都耗费在了哪里,通过have_profiling参数,能看到当前mysql是否支持。
profile操作:
xxxxxxxxxx
11select @@have_profiling;
profiling默认是关闭状态,可以通过set语句在session/global级别开启profiling
xxxxxxxxxx
41-- 查询profiling开关状态,0为关闭,1为开启;
2select @@profiling;
3-- 设置profiling打开
4set profiling=1;
执行一系列SQL操作,然后通过下面的指令查看指令的耗时情况。
xxxxxxxxxx
61-- 查看每条SQL的耗时基本情况
2show profiles;
3-- 查看指定query_id的SQL语句各个阶段的耗时情况。
4show profile for query query_id;
5-- 查看指定query_id的SQL语句CPU使用情况
6show profile cpu for query query_id;
explain执行计划
explain或者desc指令获取MySQL如何执行select语句信息,包括selectTV据执行过程中表如何连接和连接顺序。
xxxxxxxxxx
21-- 直接在select语句前加上关键字explain/desc
2explain select......
explain执行计划各字段的含义:
id select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,id值越大,越先执行。)
select_type 表示select类型,常见的取值有simple(简单表,即不是用表连接或子链接)、primary(主查询,即外层的查询)、union(union中的第二个或者后面的查询语句)、subquery(select/where之后包含了子查询)等。
type ⭐ 表示连接类型,性能由好到差连接类型为NULL、system,const、eq_ref、ref、range、index、all 使用唯一性索引时,会出现const,使用非唯一性索引时,会出现ref。
possible_key ⭐
显示可能应用在这张表上的索引,一个或多个。
key ⭐
实际使用的索引,如果为Null,则没有使用索引。
key_len ⭐ 表示使用到的索引的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。
rows MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。
filtered 表示返回结果的行数占所需读取行数的百分比,filltered值越大越好,性能越高。
extra 展示前面没有展示出来的信息。
最左前缀法则
如果索引了多列(联合索引),要遵循最左前缀法则。最左前缀法则指的是!:查询从索引最左列开始,并且不跳过索引中的列。
如果在查询时,跳过了某一列,索引将部分失效(跳过列后面的字段索引失效),如果没有最左侧列,索引全部失效。
索引列运算 不要在索引列上进行运算操作,否则索引将失效。
字符串不加引号 字符串类型的字段在使用时,不加引号,索引将会失效
模糊查询 如果仅仅在尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
or连接的条件 用or分开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会用到。
数据分布影响 如果MySQL评估使用索引比全表扫描还慢,则不使用索引。
sql提示:
SQL提示,是优化数据库的重要手段,简单来说,就是在SQL语法中加入一些人为的提示来达到优化操作的目的。
语法:
xxxxxxxxxx
61-- use indexc ——使用该索引(建议)
2select * from 表名 use index(索引名) where 条件;
3-- ignore index ——不要使用该索引
4select * from 表名 ignore index(索引名) where 条件;
5-- force index --必须使用该索引(强制)
6select * from 表名 force index(索引名) where 条件;
覆盖索引 尽量使用覆盖索引(查询使用了索引,并且需要返回的列,该索引中已经全部能找到),减少select *。
extra中显示的信息的含义 user index condition:查找使用索引,但需要回表查询数据。
user where,using index:查找使用了索引,但是需要的诗句在索引列中能够找到,所以不需要回表查询。
前缀索引 当字段类型为字符串(varchar,text等)时,有时候需要索引长度很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘io,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
xxxxxxxxxx
21-- 创建前缀索引语法
2create index 索引名 on 表名(字段名(n));
前缀长度如何选择: 可以根据索引选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高,则查询效率越高 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
xxxxxxxxxx
31-- 求取字段的选择性数值方法:
2select count(distinct 字段名1) /count(*) from 表名;
3-- 该数值越大,性能则越好
单列索引与联合索引 在业务场景中,如果存在多个查询条件,针对查询字段建立索引时,建议建立联合索引,而非单列索引。
针对于数据量较大,且查询比较频繁的表建立索引。
针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。
insert优化
批量插入(批量插入时,建议不要超过1000条),如果需要插入大量数据,可以分割成多次。;
手动提交事务。(执行完多条插入语句后统一提交事务。);
主键顺序插入;
大批量插入数据 如果一次性插入大批量数据时,使用insert语句插入性能较低,可以使用MySQL提供的load指令进行插入,操作如下:
xxxxxxxxxx
61# 客户端连接服务端时,加上参数 --local-infile
2mysql --local-infile -u root -p
3# 设置全局参数 local_infile为1,开启本地加载文件导入数据的开关。
4set global local_infile = 1;
5# 执行load 指令将准备好的数据,加载到表结构中。
6load data local infile '/root/sql1.log(要加载的文件)' into table '表名' fields terminated by ',(每个数据分隔符)' lines teminated by '\n(每行数据分割符)'
数据组织方式 在innodb存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表。
页分裂 页可以为空,也可以填充一半,也可以填充满。 每个页包含了2——N行数据(如果一行数据太大,会出现行溢出),根据主键排序。 在主键乱序插入时,可能会出现页分裂。 页分裂:page1←→page3←→page2,而不是按顺序进行排列的。
页合并 当删除一行数据时,实际上记录并没有被物理删除,只是被标记为删除,并且它们的空间变得允许被其他记录声明使用。 当页中记录删除达到merge_threshold(默认为页的50%),innodb会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
注意:页合并的阈值merge_threshold是可以自己设置的,在创建表或索引时指定。
主键设计原则
满足业务条件情况下,尽量减少主键长度。
插入数据时,尽量选择顺序插入,尽量选择自增主键。
尽量不要用uuid做主键,或者其他自然主键,如身份证号码等。
在业务操作时,尽量避免主键修改。
using filesort:通过全表扫描或表的索引,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫filesort排序。
using index:通过有序索引顺序扫描直接返回有序数据,这种情况为using index,不需要额外排序,效率较高
xxxxxxxxxx
131# 没有创建索引时,根据age,phone进行排序
2explain select id,age,phone from tb_user order by age,phone;
3
4# 创建索引
5create index idx_user_age_phone_aa on tb_user(age,phone);
6
7# 创建索引后,根据age,phone进行升序排序
8explain select id,age,phone from tb_user order by age,phone;
9
10# 创建索引后,根据age,phone进行降序排序
11explain select id,age,phone from tb_user order by age desc,phone desc;
12
13# 此时创建的索引在使用时,两个条件必须相同,全部为升序或者全部为降序,若一个为升序,一个为降序,则会出现using filesort问题
此时,就需要针对这些字段单独创建索引
xxxxxxxxxx
81# 根据age,phone进行降序一个升序,一个降序
2explain select id,age,phone from tb_user order by age asc, phone desc;
3
4# 创建索引
5create index idx user age phone ad on tb_user(age asc,phone desc);
6
7# 根据age, phone进行降序一个升序,一个降序
8explain select id,age,phone from tb_user order by age asc,phone desc;
注意:
根据排序字段建立合适的索引。
尽量使用覆盖索引。
多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(asc/desc)。
如果不可避免的出现filesort,大数据量排序是,可以适当增加排序缓冲区(sort_buffer_size)大小。(默认为256K)
在进行分组操作时,可以通过建立索引提高效率。
在分子操作时,索引的使用也是满足最左前缀法则。
一个常见的问题,当limit 2000000,10时,此时需要MySQL排序前2000010记录,仅仅返回2000000-2000010的记录,其他记录则被丢弃了,查询排序的代价非常大。 优化思路: 一般分页查询时,可以通过创建覆盖索引能够比较好的提高性能,可以通过覆盖索引加子查询的形式进行优化。
xxxxxxxxxx
11select * from 表1 t1,(select id from 表1 order by id limit 2000000,10) t2 where t1.id=t2.id;
当获取大量数据的总行数时:
myisam引擎把一个表的总行数存在了磁盘上,在执行count(*)时,直接返回这个数,效率高。 innodb引擎在执行count(*)时,需要一行行从引擎中读出来,在累计计数,效率较低。
优化思路:自己计数;
暂无较好的优化方式。
count的几种用法
count()是一个聚合函数,对于返回的结果集,一行行的判断,如果不是NULL就为累计值+1,否则不加,最后返回累计值。
用法:count(*)、count(主键)、count(字段)、count(1)
几种count方式的特点:
count(主键)
InnoDB引擎会遍历整张表,把每一行的主键id值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加(主键不可能为null)。
count(字段)
没有not null 约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,服务层判断是否为null,不为null,计数累加。
有not null约束:InnoDB引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行进行累加。
count(1)
InnoDB引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加。
count(*)
InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。
执行效率:
count(*)≈count(1)>count(主键id)>count(字段)
update语句注意事项:
在使用update时,尽量使用带索引的字段作为条件,不带索引的尽量创建索引。
innodb的行锁是针对索引加的锁,不是针对记录加的锁,并且索引不能失效,否则行锁会升级为表锁,并发性能降低。
什么是视图? 视图(view)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。
视图中只保存了查询SQL的逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在了这条SQL查询语句上。
创建视图
xxxxxxxxxx
11create [or replace 替换] view 视图名称[列名列表] as select语句 [with[ caseaded | local ] check option]
查询视图
xxxxxxxxxx
41-- 查询创建视图语句
2show create view 视图名称;
3-- 查看视图数据
4select * from 视图名称....;
修改视图
xxxxxxxxxx
41-- 方法1
2create or replace view 视图名称[列名列表] as select语句 [with[ caseaded | local ] check option]
3-- 方法2
4alter view 视图名称[列名列表] as select语句 [with[ caseaded | local ] check option]
删除视图
xxxxxxxxxx
11drop view [if exists] 视图名称
视图检查选项 当使用with check option 子句创建视图时,MySQL会通过视图检查正在进行更改的每个行,例如插入,更新,删除,以使其符合视图的定义。MySQL允许基于另一个视图创建视图,它还会检查依赖视图中的规则以保持一致性。为了确定检查范围,MySQL提供了以下两个选项。 cascaded和local,默认为cascaded。
cascaded:
cascaded检查属性会向上传递;
local:
local检查属性不会向上传递;
视图中同样可以进行增删改查操作,但是由于视图中不存储数据,在增删改时,修改的时原表中的数据。
视图更新 要使视图可以更新,视图中的行与基础表中的行之间必须存在一对一关系。 如果视图包含以下任何一项,则该视图不可更新!
聚合函数或窗口函数(sum(),min(),max(),count()等)
distinct
group by
having
union 或者 union all
视图作用
简单 视图不仅可以简化用户对数据的理解,也可以简化用户的操作。一些经常被使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件。
安全 数据库可以授权,但不能授权到数据库特定行和特定列上。通过视图用户只能查询和修改他们所能够看到的数据。
数据独立 试图可以帮助用户屏蔽真实表结构带来的影响。
存储过程介绍 存储过程时事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少市局在数据库和应用服务器之间的传输,可以提高数据处理效率。 存储过程,就是数据库SQL语言层面的代码封装与重用。
特点
封装,复用
可以接受参数,也可以返回数据
减少网络交互,提升效率
创建存储过程
xxxxxxxxxx
41create procedure 存储过程名称([参数列表])
2begin
3sql语句
4end;
调用存储过程
xxxxxxxxxx
11call 名称([参数]);
查看
xxxxxxxxxx
41-- 查看指定数据库的存储过程及状态信息
2select * from information_schema.routines where routine_schema='表名';
3-- 查询某个存储过程的定义
4show create procedure 存储过程名称;
删除
xxxxxxxxxx
11drop procedure [if exists]存储过程名称;
小提示:在命令行中创建存储过程使用分号时,可能会出错,因此需要使用 delimiter + 自定义结束符 修改结束符。
变量
系统变量:MySQL服务器提供,不是用户定义的,属于服务器层面。分为全局变量(global),会话变量(session)。
查看系统变量
xxxxxxxxxx
61-- 查看所有系统变量;
2show [session | global] variables;
3
4show [session | global] variables like '...';
5
6select @@[session | global]系统变量名;
设置系统变量
xxxxxxxxxx
31set [session | global] 系统变量名=值;
2set @@[session | global] 系统变量名=值;
3-- 设置的参数在数据库服务器重启后会恢复为默认值,如需永久修改参数,需要修改配置文件
用户定义变量 用户根据自己需要定义的变量,用户变量不用提前声明,在用的时候直接用‘@变量名’使用就可以。其作用域为当前连接。
赋值
xxxxxxxxxx
61set @变量名 = 值 [,@ 变量名 =值]...;
2set @变量名:= 值 [,@ 变量名:=值]...;
3
4select @变量名 :=值[,@变量名 :=值]...;
5-- 将查询出来的数据赋给这个变量;
6select 字段名 into @变量名 from 表名;
使用
xxxxxxxxxx
11select @变量名
局部变量 根据需要定义的在局部生效的变量,访问之前,需要declare声明。可用作存储过程内的局部变量和输入参数,局部变量的范围是在其内声明的begin...end块。超出这个范围后,局部变量将不可用。
声明
xxxxxxxxxx
21declare 变量名 变量类型 [default ...];
2-- 变量类型就是数据库字段类型:int,bigint,char,carchar,date,time
if条件 语法:
xxxxxxxxxx
71if 条件1 then
2 ...
3elseif 条件2 then -- 可选
4 ...
5else -- 可选
6 ...
7end if;
参数
类型 | 含义 | 备注 |
---|---|---|
in | 该类参数作为输入,也就是需要调用时传入值 | 默认 |
out | 该类参数作为输出,也就是该参数可以作为返回值 | |
inout | 既可以作为输入参数,也可以作为输出参数。 |
用法:
xxxxxxxxxx
41create procedure 存储过程名称([in/out/inout 参数名 参数类型])
2begin
3 -- sql语句
4end;
例如:判断员工的工资水平等级
xxxxxxxxxx
181create procedure p2(in moneys int,out shuiping varchar(10))
2begin
3 -- declare shuiping varchar(10);
4 -- declare moneys int;
5
6 if moneys>1200 && moneys<=1400 then
7 set shuiping :='三等';
8 elseif moneys>1400 && moneys<1600 then
9 set shuiping := '二等';
10 elseif moneys<=1200 then
11 set shuiping :='四等';
12 elseif moneys>=1600 then
13 set shuiping := '一等';
14 end if;
15
16end;
17call p2(1199,@r);
18select @r;
case
语法1
xxxxxxxxxx
71case 条件表达式
2 when 值1 then SQL语句1
3 when 值2 then SQL语句2
4 when 值3 then SQL语句3
5 ......
6 else sql语句
7end case;
语法2
xxxxxxxxxx
61case
2 when 条件表达式 then SQL语句1
3 when 条件表达式 then SQL语句2
4 when 条件表达式 then SQL语句3
5 else sql语句
6end case;
实例
xxxxxxxxxx
421-- 根据传入的月份,判断对应的季度
2create procedure check_month(in months int)
3begin
4 declare jidu varchar(20);
5 case
6 when months >= 1 and months <= 3 then
7 set jidu :='第一季度';
8 when months >= 4 and months <= 6 then
9 set jidu :='第二季度';
10 when months >=7 and months <= 9 then
11 set jidu :='第三季度';
12 when months >= 10 and months <= 12 then
13 set jidu :='第四季度';
14 else
15 set jidu :='参数错误';
16end case;
17 select concat('你输入的月份:',months,',当前季度为:',jidu);
18
19end;
20set @months =7;
21call check_month(@months);
22
23-- 判断星期几
24create procedure check_week(in week int)
25begin
26 declare week_str varchar(20);
27 case week
28 when 1 then set week_str:='星期一';
29 when 2 then set week_str:='星期二';
30 when 3 then set week_str:='星期三';
31 when 4 then set week_str:='星期四';
32 when 5 then set week_str:='星期五';
33 when 6 then set week_str:='星期六';
34 when (0, 7) then set week_str := '星期日';
35
36 else set week_str:='参数错误';
37
38 end case;
39
40 select week_str;
41end;
42
while循环
while循环是有条件的循环控制语句。满足条件后,在执行循环体中的SQL语句,否则不执行;
xxxxxxxxxx
161-- 基本语法
2while 条件 do
3 sql语句...
4end while;
5-- 小案例:计算1累加到n
6create procedure add_num(in n int)
7begin
8 declare sum int default 0;
9 while n>0 do
10 set sum := sum+n;
11 set n:=n-1;
12 end while;
13 select sum;
14end;
15
16call add_num(88);
repeat循环 repeat是有条件的循环控制语句,当满足条件后,退出循环; 在此循环中,不管满不满足条件,都会先执行一次,如果满足条件退出,如果不满足条件继续循环;
xxxxxxxxxx
181-- 语法结构
2repeat
3 sql语句
4 until 条件 -- 一直循环直到满足此条件退出
5end repeat;
6-- 小案例:计算1累加到n
7create procedure add_num(in n int)
8begin
9 declare sum int default 0;
10 repeat
11 set sum := sum+n;
12 set n:=n-1;
13 until n<=0;
14 end repeat;
15 select sum;
16end;
17
18call add_num(88);
loop循环 loop实现简单的循环,如果不在SQL逻辑中增加循环退出条件,可以用其来实现简单的死循环。loop可以配合以下两个语句使用:
leave:配合循环使用,退出循环。
iterate:必须用在循环中,跳过当前循环剩下的语句,直接进入下次循环。
xxxxxxxxxx
211[begin_label:(自己定义的标记)]loop
2 sql语句...
3 leave lable; -- 结束循环
4 iterate label; -- 退出当前循环
5end loop[end label];
6
7
8-- 小案例:计算1累加到n
9create procedure add_num(in n int)
10begin
11 declare sum int default 0;
12 sums:loop
13 if n<=0 then
14 leave sums
15 end if;
16 set sum := sum+n;
17 set n:=n-1;
18
19 end loop sums;
20 select sum;
21end;
游标(cursor) 游标:是用来存储查询结果集 的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括:游标的声明,open,fetch,close,其语法如下:
xxxxxxxxxx
351-- 声明游标
2declare 游标名称 cursor for 查询语句;
3-- 打开游标
4open 游标名称;
5-- 获取游标记录赋值给变量;
6fetch 游标名称 into 变量[,变量2];
7-- 关闭游标
8close 游标名称;
9
10-- 小案例:输入一个条件,将一个表中的数据按条件筛选出来创建一个新表并将数据存储到新表中
11create procedure shaixuan(in ages int)
12begin
13 -- 定义变量存储游标数据
14 declare uname varchar(100);
15 declare umoney int;
16 -- 定义游标
17 declare cur_stu cursor for select name,money from student where student.age>=ages;
18
19 drop table if exists new_stu;
20 create table if not exists new_stu(
21 id int auto_increment primary key comment 'id',
22 name varchar(100) comment '姓名',
23 money int comment '金额'
24 )comment '筛选的新表';
25 open cur_stu;
26 while true do
27 fetch cur_stu into uname,umoney ;
28 insert into new_stu(name, money) VALUEs (uname,umoney);
29 end while;
30 close cur_stu;
31
32end;
33call shaixuan(19);
34
35
注意!:游标声明和普通变量的声明事由先后顺序的!要先声明普通变量,再声明游标。
条件处理程序
条件处理程序(handler)可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。
语法:
xxxxxxxxxx
461declare handler_action(执行的操作) handler for condition_value(判断的条件)[,condition_value]... statement(结束后执行的sql语句);
2-- 关键字的属性:
3handler_action
4 continue: -- 继续执行当前程序
5 exit: -- 终止执行当前程序
6
7condition_value
8 sqlstate sqlstate_value: -- 状态码,如02000
9 sqlwarning:-- 所有以01开头的sqlstate代码的简写
10 not found:-- 所有以02开头的sqlstate代码的简写
11 sqlexception:-- 所有没有被sqlwarning或not found捕获的sqlstate代码的简写
12
13-- (完善)小案例:输入一个条件,将一个表中的数据按条件筛选出来创建一个新表并将数据存储到新表中
14create procedure shaixuan(in ages int)
15begin
16 -- 定义变量存储游标数据
17 declare uname varchar(100);
18 declare umoney int;
19 -- 定义游标
20 declare cur_stu cursor for select name,money from student where student.age>=ages;
21
22 -- 声明一个条件处理程序;
23 declare exit handler for sqlstate '02000' close cur_stu;
24 drop table if exists new_stu;
25 create table if not exists new_stu(
26 id int auto_increment primary key comment 'id',
27 name varchar(100) comment '姓名',
28 money int comment '金额'
29 )comment '筛选的新表';
30 open cur_stu;
31 while true do
32 fetch cur_stu into uname,umoney ;
33 insert into new_stu(name, money) VALUES (uname,umoney);
34 end while;
35 close cur_stu;
36
37end;
38call shaixuan(22);
39
40
41-- 条件处理程序还可写为
42declare exit handler for sqlstate '02000' close cur_stu;
43while not done do
44 fetch cur_stu into uname, umoney;
45 insert into new_stu(name, money) values (uname, umoney);
46end while;
存储函数就是有返回值的存储过程,存储函数的参数只能是in类型的。 语法如下:
xxxxxxxxxx
251create function 存储函数名称([参数列表 数据类型])
2returns type(返回值类型int,char 等) [characteristic]
3begin
4 -- sql语句
5 return...;
6end;
7characteristic(当前存储参数的特性,可选参数,可不写,但mysql8.0后默认开启binary logging,需要加上此参数)说明:
8
9deterministicL:相同的输入参数总是产生相同的结果;
10no sql:不包含SQL语句
11reads sql data:包含读取数据的语句,但不包含写入数据的语句
12
13-- 小案例:使用存储函数计算从1到n的值;
14create function sums (n int)
15returns int deterministic
16begin
17 declare sum int default 0;
18 while n>0 do
19 set sum:=sum+n;
20 set n:=n-1;
21 end while;
22 return sum;
23end;
24
25select sums(100);
存储函数使用较少,存储函数能实现的功能在存储过程中也可以实现,存储函数存在弊端,必须有返回值;
什么是触发器 触发器是与数据库表有关的数据库对象,指在insert/update/delete之前或之后,出发并执行触发器中的sql语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。 使用别名OLD(引用原来的记录内容)和new(引用新的记录内容)来引用触发器中发生变化的记录内容,这与其他数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。
触发器类型 | OLD/NEW |
---|---|
insert型触发器 | new表示将要或已经新增的数据。 |
update型触发器 | old表示修改之前的数据,new表示将要修改或修改之后的数据 |
delete型触发器 | old表示将要或已经删除的数据 |
触发器的语法
创建
xxxxxxxxxx
61create trigger 触发器名称;
2before/after inster/update/delete
3on 表名 for each row -- 行级触发器
4begin
5 触发器执行的sql语句
6end;
查看
xxxxxxxxxx
11show triggers;
删除
xxxxxxxxxx
11drop trigger [数据库名(不指定为当前数据库)] 触发器名
案例:使用触发器记录表的变更日志;
xxxxxxxxxx
181-- 创建日志表;
2create table user_logs(
3 id int(11) not null auto_increment,
4 operation varchar(20) not null comment '操作类型, insert/update/delete',
5 operate_time datetime not null comment '操作时间',
6 operate_id int(11) not null comment '操作的ID',
7 operate_params varchar(500) comment '操作参数',
8 primary key(`id`)
9)engine=innodb default charset=utf8;
10
11-- 定义触发器
12create trigger user_insert_log
13 after insert/update/delete on 触发的表名 for each row
14begin
15 insert into user_logs
16 (id, operation, operate_time, operate_id, operate_params) values (null,'insert',now(),new.id,concat('字符串拼接插入内容:'));
17end;
18
锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除了传统的计算资源(CPU,RAM,IO)的争用意外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须和解决的一个问题,锁冲突也是影响数据库并发访问性能的重要因素。从这个角度来说,锁对数据库而言是尤其重要的,也更加复杂。
锁的分类
全局锁:锁定数据库中的所有表
表级锁:每次操作锁住整张表
行级锁:每次操作锁定对应的行数据
介绍 全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,ddl语句,以及更新操作的事务提交语句都将被阻塞。 其典型的应用场景就是做全库的逻辑备份,对所有的表进行锁定,从而获取一致的视图,保证数据的完整性。
xxxxxxxxxx
41-- 为当前实例添加全局锁
2flush tables with read lock;
3-- 解除全局锁
4unlock tables;
执行数据备份方法
xxxxxxxxxx
11mysqlbump -uroot -p123456 想要备份的数据库名>备份数据存到的文件.sql
简介 每次操作锁住整张表。锁定力度大,发生锁冲突的概率最高,并发度最低,应用在myisam、innodb、bdb等存储引擎中。
表级锁分类
表锁
表共享读锁(read lock)
表独占写锁(write lock) 当添加了写锁狗,当前客户端可读可写,其他客户端不可读不可写。
语法
xxxxxxxxxx
41-- 加锁
2lock tables 表名(可同时锁定多张表) read/write;
3-- 释放锁
4unlock tables 或关闭客户端
元数据锁(meta data lock) MDL加锁过程是系统自动控制的,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。
意向锁 为了避免MDL在执行时,加的行级锁与表锁冲突,在innodb中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。
介绍 每次操作锁住对应的行数据。锁定力度最小,发生锁冲突的概率最低,并发度最高。应用在innodb存储引擎中。 innodb的数据是基于索引组织的,行锁是通过对索引上的索引项加锁实现的,而不是对记录加锁。对于行级锁,有以下三种:
行锁(record lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC,RR隔离级别下都支持。
共享锁(s):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(x):允许获取排他锁的事务更新数据,阻止其他事务获得相同的数据集的共享锁和排他锁。
间隙锁(gap lock):锁定索引记录间隙(不包含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读,在RR隔离级别支持。
默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用 next-key锁进行搜索和索引扫描,以防止幻读。
1.索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
2.索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next—key lock 退化为间隙锁。
3.索引上的范围查询(唯一索引)——会访问到不满足条件的第一个值为止。
临键锁(next-key lock):同时锁住数据和间隙。在RR隔离级别下支持。
sql | 锁类型 | 说明 |
---|---|---|
insert/update/delete | 排他锁 | 自动加锁 |
select(什么也不加) | 不加任何锁 | |
select...lock in share mode | 共享锁 | 手动加 |
select... for update | 排他锁 | 手动加 |
表空间:(ibd文件),一个MySQL实例可以对应多个表空间,用于存储记录、索引等数据。
段:分为数据段、索引段、回滚段,innodb是索引组织表,数据段就是B+tree的叶子节点,索引段即为B+tree的非叶子节点。段用来管理多个区。
区:表空间的单位结构,每个区的大小为1M。默认情况下innodb存储引擎大小为16K,即一个区有64个连续的页。
页:是innodb存储引擎磁盘管理的最小单元,每个页默认大小为16K.为了保证页的连续性,innodb引擎每次从磁盘申请4-5个区;
行:在innodb存储引擎中,数据是按行存放的。
innodb存储引擎架构图
show variables like '%参数';
内存结构:
Buffer poll-缓冲池:缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查时,先操作缓冲池中的数据(若缓冲池中没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,减少磁盘IO,加快处理速度。
缓冲池是以页为单位的,底层采用链表数据结构管理page根据状态,将page分为三种类型
free page:空闲page,未被使用。
clean page :被使用的page,数据未被修改过。
dirty page:脏页,被使用的page,数据被修改过,其中的数据与磁盘的数据产生了不一致。
change buffer-更改缓冲区:(针对非唯一二索引级索引页),在执行DML语句时,如果这些数据page没有在Buffer pool中,不会直接操作磁盘,而会将数据变更存在变更缓冲区中,在未来数据被读取时,在将数据合并恢复到buffer pool,再将个合并后的数据刷新到磁盘中。
change buffer 存在的意义: 与聚集索引不同,二级索引通常是非唯一索引,并且一向对随机的顺序插入二级索引。同样,删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了change buffer后,可以在缓冲池中将数据进行合并处理,减少磁盘IO。
log buffer-日志缓冲区:用来保存要写入到磁盘中的log日志数据(redo log、undo log),默认大小为16MB,日志缓冲区的日志会定期刷新到磁盘中。如需要插入、更新或删除许多行事务,日志缓冲区可以节省磁盘IO。
参数:
innodb_log_buffer_size:设置缓冲区大小 innodb_flush_log_at_trx_commit:日志刷新到磁盘的时机。
adaptive hash index-自适应哈希索引:用于优化对buffer pool数据的查询。innodb存储引擎会监控对标上个索引页的查询,如果观察到哈希索引可以提高速度,则建立hash索引,称之为自适应Hash索引。 自适应哈希索引无语人工干预,由系统根据情况自动完成。 参数:adaptive_hash_index
磁盘结构
system tablespace-系统表空间:更改缓冲区的储存区域。如果表是在系统空间而不是每个表文件或通用空间中创建的,它也可能包含表和索引数据。 参数:innodb_data_file_path
file-per-table tablespaces:每个表的文件表空间包含单个innodb表的数据和索引,并存储在文件系统上的单个数据文件中。 参数:innodb_file_per_table
general tablespaces:通用表空间,需要通过create tablespace语法创建通用表空间,在创建表时,可以指定该表空间。
undo tablespaces:撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(默认大小为16MB),用于存放undo log日志。
temporary tablespaces:临时表空间,innodb 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。
doublewrite buffer files:双写缓冲区,innodb引擎将数据页从buffer pool刷新到磁盘前,先将数据页写入到双写缓冲区文件中,便于系统异常时恢复数据,保证文件的安全性。
redo log:重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)、重做日志文件(redo log),前者是在内存中,后者在硬盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。
后台线程 将innodb引擎缓冲池中的数据刷新到磁盘中。
分类:
master thread 核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中,保持数据的一致性,还包括脏页的刷新、合并插入缓存、undo页的回收。
IO thread 在 innodb存储引擎中大量使用了AIO来处理IO请求,这样可以将极大地提高数据库的性能,而IO thread主要负责这些IO请求的回调。
线程类型 | 默认个数 | 职责 |
---|---|---|
read thread | 4 | 负责读操作 |
write thread | 4 | 负责写操作 |
log thread | 1 | 负责将日志缓冲区刷新到磁盘 |
insert buffer thread | 1 | 负责将缓冲区内容刷新到磁盘 |
purge thread 主要用于回收事务已经提交的undo log,在事务提交之后,undo log可能不用了,就用它来回收。
page cleaner thread 协助master thread刷新脏页到磁盘的线程,它可以减轻master thread的工作压力,减少阻塞。
redo log(解决事务持久性)
重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)、重做日志文件(redo log),前者是在内存中,后者在硬盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。
undo log(解决事务原子性)
回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚和MVCC(多版本并发控制)。
undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时, undo log中会记录一条对应的insert记录,反之 亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
Undo log销毁: undo log在事务执行时产生,事务提交时,并不会立即删除undo log,因为这些日志可能还用于MVCC。
Undo log存储: undo log采用段的方式进行管理和记录,存放在前面介绍的rollback segment 回滚段中,内部包含1024个undo log segment。
基本概念
当前读 读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select...lock share mode(共享锁),select ...for update/insert/delete(排他锁)都是一种当前读。
快照读
简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
Read Committed:每次select,都生成一个快照读。
Repeatable Read:开启事务后第一个select语句才是快照读的地方。
Serializable:快照读会退化为当前读。
MVCC Multi-Version Concurrency Control,即多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL是实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log,readview。
MVCC隐藏字段
隐藏字段 | 含义 |
---|---|
DB_TRX_ID | 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID |
DB_ROLL_PTR | 回滚指针指向这条记录的上一个版本,用于配合undo log,指向上一个版本。 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将生成该隐藏字段。 |
查看ibd文件指令:ibd2sdi xxx.ibd
undo log 回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。 当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。 update、delete的时候、产生的undo log日志不仅在回滚时余姚,在快照读时也需要,不会立即删除。
undo log版本链 不同事务或相同事务对同一条记录进行修改,会导致该纪录的undo log生成一条记录版本链表,链表的头部是最新的旧纪录,尾部是最早的旧纪录。
read view(读视图)
是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)ID。 read view四个核心的字段
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,(当前事务ID+1:因为事务ID是自增的) |
creator_trx_id | read view创建者的事务ID |
原理分析-RC级(读已提交)
在RC隔离级别下,在事务每一次执行快照读时生成read view。
原理分析-RR级 在RR隔离级别下,仅在事务第一次执行快照读时生成readview,后续复用readview。
在MySQL安装完成后,自带的数据库。
数据库 | |
---|---|
mysql | 存储MySQL服务器正常运行所需要的各种信息(时区、主从、用户、权限等) |
information_schema | 提供了访问数据库元数据的各种表和视图,包含数据库、表、字段类型及访问权限等。 |
performance_schema | 为MySQL服务器运行时状态提供了一个底层监控功能,主要用于数据库服务器性能参数。 |
sys | 包含了一系列方便DBA和开发人员利用performance_schema性能数据库进行调优和诊断的视图。 |
mysql 该MySQL不是指mysql服务,而是MySQL的客户端工具。
xxxxxxxxxx
111语法:
2mysql [选项] [数据库]
3选项:
4-u,--user=name #指定用户名
5-p,--password[=name] #指定密码
6-h,--host=name #指定服务器IP或域名
7-P,--port=port #指定端口号、
8-e,-execute=name #执行SQL语法并退出
9
10-e可以在mysql客户端执行sql语句,而不用连接到mysql数据库再执行
11实例:mysql -uroot -p123456 datebasename -e'select * from student';
mysqladmin 一个执行管理操作的客户端程序。可以用它检查服务器的配置和当前状态、创建删除数据库等。
xxxxxxxxxx
41使用帮助文档查看选项
2mysqladmin --help
3示例:
4mysqladmin -uroot -p123456 drop learn
mysqlbinlog 由于服务器生成的二进制日志文件以二进制格式保存,所以如果想检查这些文本的文本格式,就要使用到mysqlbinlog日志管理工具。
xxxxxxxxxx
91语法:
2mysqlbinlog [options] log-files1 log-files2...
3options:
4-d,--datebase=name #指定数据库名称,只列出指定的数据库相关操作
5-o,--offset=# #忽略掉日志文件中的前N行
6-r,--result-file=name #将输出的文本格式日志输出到指定文件
7-s,--short-form #显示简单格式,省略一些信息
8--start-datatime=date1 --stop-datatime=date2 #指定日期间隔内的所有日志
9--start-position=pos1 --stop-position=pos2 #指定位置间隔内的所有日志
mysqlshow 客户端对象查找工具,用来很快地查找存在哪些数据库、数据库中的表、表中的列或索引。
xxxxxxxxxx
131语法
2mysqlshow [options] [datebase_name] [table_name[columns_name]]
3options:
4--count #显示数据库及表的统计信息
5-i #显示指定数据库或者指定表的状态信息
6示例:
7#查询每个数据库的表的数量及表中记录的数量
8mysqlshow-uroot-p2143--count
9#查询test库中每个表中的字段书,及行数
10mysqlshow-uroot-p2143 test--count
11#查询test库中book表的详细情况
12mysqlshow-uroot-p2143 test book--count
13
mysqldump 客户端工具用来备份数据库或在不同数据库之间进行数据迁移。备份内容包含创建表及插入表的SQL语句。
xxxxxxxxxx
181语法:
2mysqldump [options] db_name [tables]
3mysqldump [options] --database/-B db1 [db2 db3...]
4mysqldump [options]--all-databases/-A
5连接选项:
6-u,--user=name #指定用户名
7-p,--password[=name] #指定密码
8-h,--host=name #指定服务器ip或域名
9-P,--port=# #指定连接端口
10输出选项:
11--add-drop-database #在每个数据库创建语句前加上drop database 语句
12--add-drop-table #在每个表创建语句前加上drop table语句,默认开启;
13不开启(--skip-add-drop-table)
14-n,--no-create-db #不包含数据库的创建语句
15-t,--no-create-info #不包含数据表的创建语句
16-d--no-data #不包含数据
17-T,--tab=name #自动生成两个文件:一个.sql文件,创建表结构的语句;
18一个.txt文件,数据文件
mysqlimport/source 客户端数据导入工具,用来导入mysqldump加-T参数导出的文本文件
xxxxxxxxxx
21语法:
2mysqlimport [options] datebase_name textfile1 [textfile2];
如果要导入sql文件,可以使用MySQL中的source指令:
xxxxxxxxxx
11source xxx.sql;
本笔记到此结束... 下面的内容日后在进行更新!
暂不更新.....待日后补充