一、基础篇
1.MySQL概述
数据库:database
数据库管理系统:DBMS,操作和管理数据库
SQL:操作关系型数据库的编程语言
连接
- 使用MySQL提供的客户端命令行工具
- cmd mysql -u root -p
关系型数据库
建立在关系模型基础上,由多张相互连接的二维表组成的数据库。
A. 使用表存储数据,格式统一,便于维护。
B. 使用SQL语言操作,标准统一,使用方便。
2.SQL
结构化查询语言。定义操作关系型数据库统一标准。
DDL数据定义语言
数据库结构
创建数据库:creat database if not exists 数据库名 default charset 字符集 collate 排序规则;
删除数据库:drop database if exists 数据库名;
查询数据库:show databases;
切换数据库:use 数据库名;
查询当前数据库:select database();
表结构:
创建:
create table tb_user(
id int comment '编号',
`name varchar(50) comment '姓名'
) comment '用户表';
展示表:show tables;
查看表结构:desc 表名;
查看建表语句:show create table 表名;
表操作:
添加:alter table 表名 add 字段名 类型 comment 注释 约束;
修改:数据类型:alter table 表名 modify 字段名 新类型;
字段名和字段类型:alter table 表名 change 旧字段名 新字段名 类型 注释 约束;
删除:alter table 表名 drop 字段名;
修改表名:alter table 表名 rename to新表名
表删除:drop table if exists 表名
DML数据操作语言
对数据库中表的数据记录进行增、删、改操作。
添加:insert into 表名 values (3,'3','韦一笑','男',58),(第二条记录),……;
更改:update 表名 set 修改项 = 修改内容 where 条件;
删除:delete from 表名 where 条件;
DQL数据查询语言
数据查询语言,用来查询数据库中表的记录。
基本查询
查询字段:select 字段名,字段名 from 表名;
查询设置别名:select 字段名 别名 from 表名;
查询去重:select distinct 字段名 from 表名;
条件查询
select 字段名 from 表名 where 条件列表;
多个条件用逻辑运算符连接。
常用< ,>,>=,<=,=,!=,between...and...,in(a,b,c)
like(模糊匹配,代表一个字符,%任意个字符),is null,and,or,not;
聚合函数
某一列作为整体,纵向计算
select 聚合函数(字段列表)from 表名;
常用函数:count,max,min,avg,sum。注意,null不参与运算。
分组查询
select 字段列表 from 表名 where 条件 group by 分组字段名 having 分组后过滤条件
where与having区别
- 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组
之后对结果进行过滤。
- 判断条件不同:where不能对聚合函数进行判断,而having可以。
排序查询
select 字段列表 from 表名 order by 字段1 排序方式,字段2,排序方式;
ASC升序,desc降序
分页查询
select 字段列表 from 表名 limit 查询页码-1(索引),每页显示数。
执行顺序以及查询语法总结
DCL数据控制语言
管理数据库用户、控制数据库的访问权限
用户管理
查询用户:select * from mysql.user
新建用户:create user '用户名'@'主机名' identified by '密码';
改密码:alter user '用户名'@'主机名' identified with mysql_native_password by'新密码';
删除用户:drop user '用户名'@'主机名';
权限管理
显示权限:show grants for '用户名'@'主机名';
授予权限:grant 权限 on 数据库.表名 to '用户名'@'主机名';
撤销权限:revoke 权限 on 数据库.表名 from '用户名'@'主机名';
3.函数
字符串函数
concat(s1,s2...)拼接
lower(s)转小写
upper(s)转大写
lpad(s,n,t)左填充,到n位,填充t
rpad(s,n,t)右填充
trim去首尾空格
substring(s,begin,end)取子串
数值函数
ceil()上取整
floor()下取整
mod(x,y)
rand()0-1随机数
round(x,y)x四舍五入保留y位小数
日期函数
curdata()当前日期
curtime()当前时间
now()日期+时间
year(date)
mouth(date)
day(date)
data_add(date,interval x day(mouth,year))日期date增加x天/月/年
datediff(date1,date2) date1-date2
流程函数
if(value,t,f)如果value是true,返回t,否则返回f
ifnull(value1,value2)value1不为空就返回,否则返回value2
case when val1 then res1 ...else default end val1为真返回res1,否则返回default默认值
case expr when val1 then res1 ...else default end expr==val1返回res1否则default
4.约束
概述
于表中字段上的规则,用于限制存储在表中的数据。
目的:保证数据库中数据的正确、有效性和完整性。
约束演示
非空约束:not null
唯一约束:unique
主键约束:一行数据唯一标识,非空且唯一primary key
默认约束:default
检查约束:check
外键约束:foreign key
建表的时候,在字段类型之后加入。
datagrip中就是default项
外键约束
用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
5.多表查询
内连接
查两个表的交集
隐式内连接:select 字段列表 form 表1,表2 where 条件;
显式内连接:select 字段列表 from 表1 join 表2 on 条件;
注意可以添加别名简化书写,添加别名之后字段列表和条件都只能使用别名;
区分字段列表用表名.字段名的方法;
外连接
左表/右表以及两个表的交集
select 字段列表 from 表1 left join 表2 on条件;
查询表1的所有数据,也包含表2中的交集信息
自连接
把自己这张表查询多次。这个注意要起别名。
select 字段列表 from 表 别名 join 表 别名 on 条件。
联合查询
多次查询的结果合并起来。字段列表要求一致,要去重的话删除all.
select 字段列表 from 表 where ...
union all
select 字段列表 from 表 where ...。
子查询
可以选择分步思考操作
1.标量子查询:子查询返回来的是一个值
select 字段列表 from 表名 where 条件(关系)select字段列表 from 表名 where 条件
2.列子查询:子查询返回的是一列。
常用操作,in在指定范围中。not in 不在指定范围中。
any,some满足任意一个条件。all满足所有条件
eg:
3.行子查询
eg
4.表子查询
常用操作符:in
eg:
6.事务
一组操作,一气呵成,不可分割
控制事务
- 提交方式设置为手动
select @@autocommit; set @@autocommit = 0; 这是事务 commit; - 正确就提交 rollback; - 不正确就回滚
- bagin
start transaction 或者 begin; 这是事务 commit; rollback;
四大特性
原子性
一致性:执行完成后,所有数据保持一致
隔离性:不受外界影响
持久性:对数据的改变是永久的
并发事务问题
脏读:读还没提交的数据
不可重复读:一个事务先后读取的同一记录数据不同
幻读:查询没有,但是插入时候发现又有了。
事务隔离级别
- 读未提交(read uncommitted),指一个事务还没提交时,它做的变更就能被其他事务看到;
- 读提交(read committed),指一个事务提交之后,它做的变更才能被其他事务看到;
- 可重复读(repeatable read),指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别;
- 串行化(serializable);会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行;
二、进阶篇
1.存储引擎
是mysql数据库的核心,是存储数据、建立索引、更新/查询数据等技术的实现方式。
存储引擎是基于表的。
逻辑存储结构:表空间--段--区(1M)--页(16K)--行
存储引擎对比:
总结:InnoDB:支持事务,行锁,外键:遵循ACID
2.索引
帮助MySQL高效获取数据的数据结构(有序)。
概述
优点:提高检索效率,降低数据库IO成本,通过索引对数据排序,降低数据排序成本
缺点:存储索引占用空间,降低更新表的速度(比如增删数据)
索引结构
一般默认的索引结构:B+树
二叉树:退化成单向链表。大数据量情况下,层级较深,检索速度慢。
B树:
B+树的非叶子节点不存放实际的记录数据,仅存放索引,所以检索会比较快。
B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。(内存中一页可以放更多的索引)
B+树增删更快:B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
叶子结点之间局部性比较好:B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。
MySQL的B+树优化:
在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,利于排序。(叶子结点前后可以互相访问)
哈希
通常一次检索,效率高
不支持范围查询
不能通过索引完成排序操作
分类
聚集索引:索引结构的叶子结点是行数据,必须有,只有一个(主键,unique,默认生成)
二级索引:索引结构的叶子结点存放的是对应的主键。(回表查询)
索引语法
创建索引:create [unique/fulltext] index 索引名 on 表名 (字段名);
查看索引:show index from 表名;
删除索引:drop index 索引名 on 表名;
索引名一般为:idx_字段名
SQL性能分析
查看增删改查次数:show global status like 'com';
慢查询日志:定位哪些SQL语句执行效率比较低
Profile
设置profile打开:set profiling = 1;
查看SQL耗时情况:show profiles;
各个阶段耗时情况:show profile for query_id;
CPU使用情况:show profile cpu for query_id;
explan
获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序.
索引使用
建立索引之后,查询效率大大提高
最左前缀法则:联合索引最左边的字段要存在,索引才会生效,但是与其在where中位置无关。跳过某列,则联合索引部分生效。此外范围查询>,<查询右侧的索引失效,但是<=,>=不影响。
索引失效
- 在索引上运行
- 字符串不加引号
- 模糊查询%加在关键字之前
- 使用or连接,只有两个都有索引,索引才会生效
- 数据分布:MySQL评估全表扫描比索引快
- 联合索引不符合最左前缀
SQL提示
让MySQL使用固定的索引,使用/忽略/强制使用某索引。
explain select * from 表名 use/ignore/force index(索引名) where...;
使用规则
- 覆盖索引:减少select * 的使用,多使用覆盖索引。有时候就不需要回表。
- 前缀索引:抽取字符串的一部分前缀,建立索引。
- create index 索引名 on 表名(数据项名(前缀个数))
- 查看索引选择性:
select count(distinct substring(数据项名,起始位,尾位))/count(*) from 表名
- 单列索引和联合索引:存在多个查询条件,可以使用联合索引,避免回表。
设计原则
- 数据量大,查询频繁
- where,order by,group by条件的字段
- 区分度高的列为索引
- 字符太长可以前缀索引
- 尽量使用联合索引
- 索引并不多多益善,维护不便
- 如果索引不存储NULL,创建时用NOT NULL约束
3.SQL优化
插入优化
- 批量插入:insert into 表名 values()、()...
- 手动提交;start transaction; 批量插入 ; commit;
- 主键顺序插入
- 大批量使用load本地导入
- 连接服务器:mysql --local-infile -u root -p
- 设置参数:set global local_infile = 1;
- 加载数据:load data local infile '本地位置' into table 表名 field terminated by ',' lines terminated by '\n';
主键优化
主键按序插入:本质就是为了防止插入删除记录时候出现的频繁页分裂合并也就是B+树的调整
- 降低主键长度
- 顺序插入,可使用aoto_increment自增主键
- 业务修改避免修改主键
- 避免使用自然主键,比如身份证号
order by优化
排序方式:
- Using filesort:全表扫描/通过索引扫描,排序缓冲区排序,不能通过索引直接返回排序结果
- Using index:通过有序索引顺序扫描返回有序数据,不需要额外排序
解决:创建索引,可以指定索引升序降序的。默认升序的。
体会
- 根据排序字段建立合适的索引,多字段排序遵循最左前缀法则
- 尽量使用覆盖索引
- 按需要指定升序降序
- filesort,增大排序缓冲区的大小
group by
和order by有点类似的
- 也可以使用索引
- 分组操作,索引满足最左前缀法则
limit
进行limit分页查询,在查询时,越往后,分页查询效率越低
优化:子查询,覆盖索引
Count
count(字段) < count(主键 id) < count(1) ≈ count(※),所以尽量使用 count(※)。
updata优化
加了索引就是行锁,不加就是表锁,并发性能降低。
4.视图、存储过程、触发器
视图
视图只保存了查询的SQL逻辑,不保存查询结果。
语法
- 创建:creare or replace view 视图名 as 查询语句
- 查询
- 查看视图语句:show create view 视图名称;
- 查询视图数据:show * from 视图名;
- 修改和创建一样
- 删除:drop view 视图名称;
检查选项
语法:创建视图之后加上 with cascaded/local check option;
cascaded要检查关联视图
local不检查关联视图
视图更新:一定要和原来的表中数据一对一
作用
- 简化操作,常用查询可以定义为视图、简化一些多对多关系的表
- 安全,一些用户只通过视图查询修改所见
- 数据独立,屏蔽真正表结构带来的影响
存储过程
介绍
把多条SQL语句封装在一起,减少网络交互,提升效率,还可复用
语法
- 创建
create procedure 存储过程名(参数列表) begin -- sql语句 end;
- 调用:call 名称(参数)
- 查看
变量
系统变量:全局变量(针对所有会话)、会话变量(针对单个会话)
用户自定义变量:不用声明,用的时候直接@变量名;set @变量名 := 变量值;用的时候select @变量名;
局部变量:声明:declare 变量名 类型;复制set 变量名 := 值;select 字段 into 变量名from 表名;
if
if 条件 then ...; elseif 条件 then ...; else ...; end if;
参数
创建进程传递参数;in , out, inout; in/out/inout+参数名+参数类型
case
case when 条件 then ...; when 条件 then ...; else ...; end case;
while
while 条件 do ...; end while;
repeat
repeat ...; until 条件 end repeat;
游标
存储查询结果集
存储函数
有返回值的存储过程,参数只能是IN类型
create function 函数名(n int) return int [特征] begin ...; return ...; end; 查询:select 函数名(参数)
触发器
在insert/update/delete之前(BEFORE)或之后(AFTER),触发并执行触发器中定义的SQL语句集合。
//创建 create trigger trigger_name before/after INSERT/UPDATE/DELETE ON tbl_name FOR EACH ROW -- 行级触发器 BEGIN trigger_stmt ;//在日志表中插入数据 END; //查看 show triggers; //删除 drop trigger trigger_name;
5.锁
全局锁
数据库进行进行逻辑备份
加锁: flush tables with read lock; 数据备份: mysqldump -uroot -p1234 itcast > itcast.sql; 释放锁: unlock tables;
表级锁
表锁
- 读锁:可同时读,不可同时写
- 写锁:不可读写
元数据锁
某一张表涉及到未提交的事务时,是不能够修改这张表的表结构的
意向锁
避免行锁与表锁的冲突,意向锁使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。
加了行锁之后自动加意向锁
行级锁
- 行锁:对单个记录的锁,防止其他事务对此进行update和delete
- 共享锁:允许一个事务读一行,阻止其他事务获取排他锁
- 排他锁:允许排他锁事务更新数据,阻止其他事务获得共享锁、排他锁
- 间隙锁:索引记录之间的间隙不变,防止在间隙插入
- 临键锁:行锁和间隙锁的组合
6.InnoDB引擎
1.逻辑存储结构
表-段-区1M-页16KB-行
2.架构
内存机构
三、运维篇
1.日志
1.1 错误日志
当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志.
该日志是默认开启的,默认存放目录 /var/log/,默认的日志文件名为 mysqld.log
查看日志位置:show variables like ‘%log_error%’;
1.2 二进制日志
记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,不包括查询
作用:a.灾难时的数据恢复;b.MySQL的主从复制。
show variables like ‘%log_bin%’;
- log_bin_basename:当前数据库服务器的binlog日志的基础名称(前缀),具体的binlog文件名需要再该basename的基础上加上编号(编号从000001开始)。
- log_bin_index:binlog的索引文件,里面记录了当前服务器关联的binlog文件有哪些。
格式show variables like ‘%binlog_format%’;
- STATEMENT:对数据修改的SQL语句
- ROW:每一行的数据变更,默认
- MIXED:混合两种
查看
mysqlbinlog 参数选项 logfilename
参数:-d指定数据库,-o忽略前n行命令,-v行事件重构为SQL语句,-vv重构并输出注释信息
删除binlog
reset master删除全部binlog
purge master logs to 'binlog.*'删除✳之前的
purge master logs before 'yyyy-mm-dd hh24:mi:ss':删除日期之前的
1.3 查询日志
记录所有操作语句,默认关闭
开启:修改 /etc/my.cnf
# 开启 general_log = 1 # 设置日志文件名,若不设置,文件名:host_name.log general_log_file = mysql_query.log
可在/var/lib/mysql/目录下找到查询日志。
1.4 慢查询
所有执行时间超过参数 long_query_time 设置值并且扫描记录数不小min_examined_row_limit 的所有的SQL语句的日志。
开启:在MySQL的配置文件:/etc/my.cnf
# 慢查询日志 slow_query_log=1 # 执行时间参数 long_query_time=2
默认情况下,不会记录管理语句,也不会记录不使用索引进行查找的查询。如需使用,设置参数,重启生效。
# 记录执行较慢的管理语句 log_slow_admin_statements = 1 # 记录执行较慢的未使用索引的语句 log_queries_not_using_index = 1
2.主从复制
2.1 概述
主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步
MySQL 复制的优点主要包含以下三个方面:
- 主库出现问题,可以快速切换到从库提供服务。
- 实现读写分离,降低主库的访问压力。
- 可以在从库中执行备份,以避免备份期间影响主库服务
2.2 原理
从上图来看,复制分成三步:
- Master 主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
- 从库IOthread读取主库的二进制日志文件 Binlog ,写入到从库的中继日志 Relay Log 。
- slaveThread重做中继日志中的事件,将改变反映它自己的数据
2.3 搭建
主库配置
修改配置文件/etc/my.cnf
# mysql服务ID,集群环境中唯一 sever-id = 1 # 只读 read-only = 0 #忽略的数据 binlog-ignore-db = mysql #指定同步数据库 binlog-do-db = db01
重启MySQL服务器systemctl restart mysqld
登录MySQL,创建远程连接账号,赋予主从复制权限
#创建itcast用户,并设置密码,该用户可在任意主机连接该MySQL服务 CREATE USER 'itcast'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123456'; #为 'itcast'@'%' 用户分配主从复制权限 GRANT REPLICATION SLAVE ON *.* TO 'itcast'@'%';
从库配置
修改配置文件/etc/my.cnf
# mysql服务ID,集群环境中唯一 sever-id = 1 # 只读 read-only = 1
重启MySQL服务器systemctl restart mysqld
登录mysql,设置主库配置
CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.200.200', SOURCE_USER='itcast', SOURCE_PASSWORD='Root@123456', SOURCE_LOG_FILE='binlog.000004', SOURCE_LOG_POS=663
开启同步:start slave;
查看主从状态:show slave status;