数据库(Database, 简称 DB): 存储数据的仓库,数据是有组织的进行存储。
数据库管理系统(Database Management System, 简称 DBMS): 操作和管理数据库的大型软件。
SQL(Structured Query Language, 简称 SQL): 操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准。
主流的关系型数据库管理系统
MySQL 官方提供了两种不同的版本:
MySQL Community Server 下载地址
MySQL数据库的数据模型
关系型数库(Relational Database Management System,简称RDBMS):建立在关系模型基础上,由多张相互连接的二维表组成的数据库。
关系型数据库的特点
函数 是指一段可以直接被另一段程序调用的程序或代码。
函数分类
字符串函数
数值函数
日期函数
流程函数
约束是作用于表中字段上的规则,用于限制存储在表中的数据。
目的:保证数据库中的数据正确、有效性和完整性。
常见约束:
约束是作用于表中字段上的,可以在创建表/修改表的时候添加约束。
建表时,添加约束示例:
create table user (
id int primary key auto_increment comment "主键",
name varchar(10) not null unique comment "姓名",
age int check(age > 0 && age < 120) comment "年龄",
status char(1) default '1' comment "状态",
gender char(1) comment "性别"
) comment "用户表";
外键:用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
添加外键:
-- 新建表时
create table 表名 (
字段名 字段类型,
...
[constraint] [外键名称] foreign key (外键的字段名) references 主表(主表列名)
);
-- 修改表时
alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 主表(主表列名);
外键约束删除/更新行为:
指定外键约束删除/更新行为:
alter table 表名 add constraint 外键名称 foreign key (外键的字段名) references 主表(主表列名) on update cascade on delete cascade;
项目开发中,在进行数据库表设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表之间也存在各种联系,基本上分为三种:
多表查询是能从多张表中查询数据
笛卡尔积:笛卡尔乘积是指在数学中,两个集合A集合和B集合的所有组合情况。(在多表查询中需要消除无效的笛卡尔积)。
多表查询的分类:
内连接:
-- 隐式内连接
select 字段列表 from 表1,表2 where 条件;
-- 显式内连接
select 字段列表 from 表1 [inner] join 表2 on 连接条件;
外连接:
-- 左外连接
select 字段列表 from 表1 left [outer] join 表2 on 条件;
-- 右外连接
select 字段列表 from 表1 right [outer] join 表2 on 条件;
自连接:
select 字段列表 from 表A 别名A join 表A 别名B on 条件;
联合查询 union、union all:
对于 union 查询,就是把多次查询结果合并起来,形成一个新的查询结果集。
select 字段列表 from 表A ...
union [all]
select 字段列表 from 表B ...;
union all 是直接将查询结果合并,union 是将查询结果合并后去重。
对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
SQL 语句中嵌套 SELECT 语句,称为嵌套查询,又称子查询。
select * from t1 where col1 = (select column1 from t2);
子查询的外部语句可以是 INSERT/UPDATE/DELETE/SELECT 的任何一个。
根据子查询结果不同,分为:
根据子查询出现的位置,分为:
标量子查询: 子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式。
常用的操作符:=、<>、>、>=、<、<=
列子查询:子查询返回的结果是一列(可以是多行)。
常用操作符:
行子查询:子查询返回的结果是一行(可以是多列)。
常用操作符:=、<>、in、not in
表子查询:子查询返回的结果是多行多列。
常用操作符:in
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
查看/设置事务的提交方式:
select @@autocommit;
-- 0 是手动提交事务;1 是自动提交事务
set @@autocommit=0;
开启事务:
-- 方式一
start transaction;
-- 方式二
begin;
提交事务:
commit;
回滚事务:
rollback;
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted | ✔ | ✔ | ✔ |
read committed | ✖ | ✔ | ✔ |
repeattable read(默认) | ✖ | ✖ | ✔ |
serializable | ✖ | ✖ | ✖ |
查看事务隔离级别:
select @@transaction_isolation;
设置事务隔离级别:
set [session | global] transaction isolation level { read uncommitted | read committed | repeatable read | serializable}
存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于数据库的,所以存储引擎也可被称为表类型。
在建表时指定存储引擎:
create table 表名(
字段 字段类型 [comment 字段注释]
) engine = InnoDB [comment 表注释];
查看当前数据库支持的存储引擎:
show engines;
InnoDB 是一种兼顾了高可靠性和高性能的通用存储引擎,在 MySQL 5.5 之后,InnoDB 是默认的 MySQL 存储引擎。
InnoDB 特点:
InnoDB 文件:
xxx.ibd: xxx代表表名,innoDB引擎的每张表都会对应这样一个表空间文件,存储该表的表结构 (frm、sdi)、数据和索引。
参数:innodb_file_per_table:决定表空间中表的数量。
-- 如果值为 ON,则一张表对应一个表空间。
show variables like 'innodb_file_per_table';
# 查看 ibd 文件中的表结构
ibd2sdi xxx.ibd
MyISAM 是MySQL早期的默认存储引擎。
MyISAM 特点:
MyISAM 文件:
Memory 引擎的表数据是存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为临时表或缓存使用。
Memory 特点:
Memory 文件:
特点 | InnoDB | MyISAM | Memory |
---|---|---|---|
存储限制 | 64TB | 有 | 有 |
事务安全 | 支持 | ||
锁机制 | 行锁 | 表锁 | 表锁 |
B+tree 索引 | 支持 | 支持 | 支持 |
Hash 索引 | 支持 | ||
全文索引 | 支持(5.6版本之后) | 支持 | |
空间使用 | 高 | 低 | N/A |
内存使用 | 高 | 低 | 中等 |
批量插入速度 | 低 | 高 | 高 |
支持外键 | 支持 |
在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。
适用场景:
索引(index) 是帮助 MySQL 高效获取数据的数据结构(有序)。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
索引的优点:
索引的缺点:
MySQL 的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含以下几种:
索引类型在各个存储引擎中的支持情况:
索引 | InnoDB | MyISAM | Memory |
---|---|---|---|
B+tree 索引 | 支持 | 支持 | 支持 |
Hash 索引 | 不支持 | 不支持 | 支持 |
R-tree 索引 | 不支持 | 支持 | 不支持 |
Full-text | 5.6版本之后支持 | 支持 | 不支持 |
二叉树:顺序插入时,会形成一个链表,查询性能大大降低。大数据量情况下,层级较深,检索速度慢。
红黑树:大数据量情况下,层级较深,检索速度慢。
B-Tree (多路平衡查找树):
以一颗最大度数(max-degree)为 5(5阶) 的 b-tree 为例(每个节点最多存储4个key,5个指针):
树的度数指的是一个节点的子节点个数。
B+Tree:
以一颗最大度数(max-degree)为 4(4阶) 的 b+tree 为例:
B+Tree 相对于 B-Tree 的区别:
MySQL 中 B+Tree 的结构:
MySQL 索引数据结构对经典的 B+Tree 进行了优化。在原 B+Tree 的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的 B+Tree, 提高区间访问性能。
哈希索引就是采用一定的 hash 算法,将键值换算成新的 hash 值,映射到对应的槽位上,然后存储在 hash 表中。
Hash 索引的特点:
存储引擎支持:
在 MySQL 中,支持 Hash 索引的是 Memory 引擎,而 InnoDB 中具有自适应 hash 功能,hash 索引是存储引擎根据 B+Tree索引在指定条件下自动构建的。
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对表中主键创建的索引 | 默认自动创建,只能有一个 | PRIMARY |
唯一索引 | 避免同一表某数据列中的值重复 | 可以有多个 | UNIQUE |
常规索引 | 快速定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键字,而不是比较索引中的值 | 可以有多个 | FULLTEXT |
在 InnoDB 存储引擎中,根据索引的存储形式,又可以分为以下两种:
分类 | 含义 | 特点 |
---|---|---|
聚集索引 (Clustered Index) | 将数据存储和索引放到了一块,索引结构的叶子节点保存了行数据 | 必须有,而且只有一个 |
二级索引 (Secondary Index) | 将数据和索引分开存储,索引结构的叶子节点关联的是对应的主键 | 可以存在多个 |
聚集索引选取规则:
回表查询: 先查二级索引获取主键,再查聚集索引获取行数据。
创建索引:
create [UNIQUE | FULLTEXT] index index_name on table_name (index_col_name, ...);
查看索引:
show index from table_name;
删除索引:
drop index index_name on table_name;
MySQL 客户端连接成功后,通过 show[session|global] status 命令可以提供服务器的状态信息。通过如下指令,可以查看当前数据库的 INSERT、UPDATE、DELETE、SELECT的访问频次。
-- 查询SQL执行频率
show global status like 'Com_______';
慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位:秒,默认10秒)的所有SQL语句的日志。
-- 查询数据库是否开启慢查询日志
show VARIABLES like 'slow_query_log';
MySQL 的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
# 开启 MySQL 慢日志查询开关
slow_query_log=1
# 设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2;
配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息 /var/lib/mysql/localhost-slow.log
# 重启 MySQL 服务
systemctl restart mysqld.service
show profiles 能够在做 SQL 优化时帮助我们了解时间耗费到哪里去了,通过 have_profiling 参数,能够看到当前 MySQL 是否支持 profile 操作:
-- 查询是否支持 profile 详情
select @@have_profiling;
-- 查询 profiling 是否开启,1 开启;0 关闭;
select @@profiling;
-- 可以通过 set 语句在 session/global 级别开启 profiling
set progiling = 1;
-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定 query_id 的 SQL 语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定 query_id 的 SQL 语句 CPU 的使用情况
show profile cpu for query query_id;
explain 或者 DESC 命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
-- 直接在 select 语句之前加上 explain/desc;
explain select 字段列表 from 表面 where 条件;
Explain 执行计划各字段的含义:
最左前缀法则
如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。
如果跳跃某一列,索引将部分失效(后面的字段索引失效)。
范围查询
联合索引中,出现范围查询(>,<),范围查询右侧列索引失效。
索引列运算
不要在索引列上进行运算操作,索引将失效。
字符串不加引号
字符串类型字段使用时,不加引号,索引将失效。
模糊查询
如果仅仅是尾部模糊匹配,索引将不会失效。如果是头部模糊匹配。索引将失效。
or连接的条件
用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
数据分布影响
如果MySQL评估使用索引比全表更慢,则不使用索引。
SQL提示
SQL 提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
-- use index 建议使用的索引
explain select * from user use index(idx_user_name) where name = 'test';
-- ignore index 忽略索引
explain select * from user ignore index(idx_user_name) where name = 'test';
-- force index 强制使用的索引
explain sekect * from user force index(idx_user_name) where name = 'test';
覆盖索引
尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少 select *。
Extra字段值的含义:
前缀索引
当字段类型为字符串(varchar、text)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
-- 创建前缀索引的语法
create index idx_xxxx on table_name(column(n));
前缀长度:可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
select count(distinct email) / count(*) from user;
select count(distinct substring(email, 1, 5))/count(*) from user;
单列索引和联合索引
在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。
多条件联合查询时,MySQL 优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询。
索引的设计原则:
insert 优化:
-- 1. 批量插入
insert into user values(1, 'tom'),(2, 'cat'),(3, 'jerry');
-- 2. 手动事务提交
start transaction;
insert into user values(1, 'tom'),(2, 'cat'),(3, 'jerry');
insert into user values(4, 'tom1'),(5, 'cat1'),(6, 'jerry1');
commit;
-- 3.主键顺序插入 主键顺序插入性能高于乱序插入。
-- 主键乱序插入:8,1,9,23,2,7,67
-- 主键顺序插入:1,2,3,9,65,81
主键顺序插入性能高于乱序插入。
大批量插入数据
如果一次性需要插入大批量数据,使用 insert 语句插入性能较低,此时可以使用 MySQL 数据库提供的 load 指令进行插入。
sql.log 示例:
1,tom
2,cat
3,jerry
4,tom1
5,cat1
6,jerry1
# 客户端连接服务端时,加上参数 --local-infile
mysql --local-infile -u root -p
# 设置全局参数 local_infile 为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
# 切换到数据库
use databaseName;
# 执行 load 指令将准备好的数据,加载到表结构中。
load data local infile '/root/sql.log' into table 'user' fields terminated by ',' lines terminated by '\n';
数据的组织方式
在 InnoDB 存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表 (index organized table, 简称 IOT)。
页分裂
页可以为空,也可以填充一半,也可以填充 100%。每个页包含了 2-N 行数据(如果一行数据过大,会行溢出),根据主键排列。
主键乱序插入会导致页分裂。
页合并
当删除一行数据时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。
当页中删除的记录达到 MERGE_THRESHOLD (默认页的 50%),InnoDB 会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
MERGE_THRESHOLD:合并页的阀值,可以自己设置,在创建表或者创建索引时指定。
主键的设计原则:
排序的类型:
-- 根据 age, phone 进行排序一个升序,一个降序
explain select id, age, phone from user order by age asc, phone desc;
-- 创建索引 指定排序的索引优化
create index idx_user_age_phone on user(age asc, phone desc);
order by 优化的点:
一个常见又非常头疼的问题就是 limit 2000000,10, 此时需要 MySQL 排序前 2000010 记录,仅仅返回 2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大。
优化思路:一般分页查询时,通过创建覆盖索引能够比较好地提高性能,可以通过覆盖索引加子查询的形式进行优化。
explain select * from tb_sku t, (select id from tb_sku order by id limit 2000000, 10) a where t.id = a.id;
count() 是一个聚合函数,对于返回的结果集,一行行的判断,如果count函数的参数不是 null,累计值就加 1,否则不加,最后返回累计值。
explain select count(*) from tb_user;
优化思路:自己计数。可以使用内存型数据库存储表的记录数,如 redis
count的几种用法:
按照效率排序的话: count(字段) < count(主键id) < count(1) ≈ \approx ≈ count(*)。所以尽量使用 count(*);
InnoDB 的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从行级锁升级为表锁。
视图(View):是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。
通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。
语法:
-- 创建视图
create [or replace] view 视图名称[(列名列表)] as select语句 [with [cascaded | local ] check option]
-- 查询
-- 1. 查看创建视图的语句
show create view 视图名称;
-- 2. 查看视图的数据
select * from 视图名称...;
-- 修改
-- 方式一
create [or replace] view 视图名称[(列名列表)] as select语句 [with [cascaded | local ] check option]
-- 方式二
alter view 视图名称[(列名列表)] as select语句 [with [cascaded | local] check option]
-- 删除
drop view [if exists] 视图名称 [,视图名称]...
视图的检查选项:
当使用 with check option 子句创建视图时,MySQL 会通过视图检查正在更改的每个行,例如 插入、更新、删除,以使其符合视图的定义。MySQL 允许基于另一个视图创建视图,它还会检查依赖视图中的规则以保持一致性。为了确定检查范围,mysql 提供了两个选项:cascaded 和 local,默认值为 cascaded。
视图的更新:
要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。如果视图包含以下任何一项,则该视图不可更新:
视图作用:
存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
-- 创建
create procedure 存储过程名称([参数列表])
begin
-- sql 语句
end;
-- 调用
call 名称([参数])
-- 查看
-- 查询指定数据库 xxx 中的存储过程及状态信息
select * from information_schema.routines where routine_schema='xxx';
-- 查询某个存储过程的定义
show create procedure 存储过程名称;
-- 删除
drop procedure [if exists] 存储过程名称;
在命令行中,执行创建存储过程的 sql 时,需要通过关键字 delimiter 指定 sql 语句的结束符。
查看系统变量
-- 查看所有系统变量
show [session | global] variables;
-- 可以通过like模糊匹配方式查找变量
show [session | global] variables like 'xx';
-- 查看指定变量的值
select @@[session | global] 系统变量名;
设置系统变量
set [session | global] 系统变量名=值;
set @@[session | global]系统变量名=值;
如果没有指定 session/global 默认是 session,会话变量
mysql 服务重新启动后,所设置的全局参数就会失效,要想不失效,可以在 /etc/my.cnf 中配置
赋值用户定义变量
set @var_name = expr [,@var_name = expr]...;
set @var_name:=expr [,@var_name := expr]...;
select @var_name := expr [,@var_name := expr]...;
select 字段名 into @var_name from 表名;
使用用户定义变量
select @var_name;
用户定义的变量无需对其进行声明或初始化,只不过获取到的值为 null。
声明
declare 变量名 变量类型[default ...];
变量类型是数据库字段类型:int、bigint、char、varchar、date、time 等
赋值
set 变量名 = 值;
set 变量名 := 值;
select 字段名 into 变量名 from 表名;
if 语法
if 条件1: then
...
-- 可选
ELSEIF 条件2:then
...
-- 可选
else
...
end if;
类型 | 含义 | 备注 |
---|---|---|
IN | 该类参数作为输入,也就是需要调用时传入值 | 默认 |
out | 该类参数作为输出,也就是该参数可以作为返回值 | |
inout | 即可以作为输入参数,也可以作为输出参数 |
用法
create procedure 存储过程名称([in/out/inout 参数名 参数类型])
begin
-- sql语句
end;
语法一
case case_value
when when_value1 then statement_list1
[when when_value2 then statement_list2]..,
[else statement_list]
end case;
语法二
case
when search_condition1 then statement_list1
[when search_condition2 then statement_list2]
[else statement_list]
end case;
while 循环:有条件的循环控制语句。满足条件后,再执行循环体中的 sql。
-- 先判断逻辑,如果条件为 true,则执行逻辑,否则,不执行逻辑。
while 条件 DO
-- sql 逻辑
end while;
repeat 循环:是有条件的循环控制语句,当满足条件的时候退出循环。
-- 先执行一次逻辑,然后判定逻辑是否满足,如果满足,则退出,如果不满足,则继续下一次循环。
repeat
sql 逻辑
until 条件
end repeat;
loop 循环:实现简单的循环,如果不在 sql 逻辑中增加退出循环的条件,可以用其来实现简单的死循环。loop 可以配合以下两个语句使用:
[begin_label:] loop
sql 逻辑
end loop [end label];
-- 退出指定标记的循环体
leave label;
-- 直接进入下一次的循环
iterate label;
游标 (cursor) 是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明、open、fetch 和 close。
声明游标
declare 游标名称 cursor for 查询语句;
打开游标
open 游标名称;
获取游标记录
fetch 游标名称 into 变量[,变量];
关闭游标
close 游标名称;
条件处理程序 (handler) 可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。
declare handler_action handler for condition_value [,condition_value]... statement;
handler_action
condition_value
存储函数是有返回值的存储过程,存储函数的参数只能是 in 类型的。
create function 存储函数名称([参数列表])
returns type [characteristic ...]
begin
-- sql 语句
return ...;
end;
characteristic 说明
触发器是表有关的数据库对象,指在 insert/update/delete 之前或之后,触发并执行触发器中定义的 SQL 语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。
使用别名 old 和 new 来引用触发器中发生变化的记录内容,这与其他数据库是相似的。现在触发器还支持行级触发,不支持语句级出发。
触发器类型 | new 和 old |
---|---|
insert 型触发器 | new 表示将要或者已经新增的数据 |
update 型触发器 | old 表示修改之前的数据,new 表示将要或已经修改后的数据 |
delete 型触发器 | old 表示将要或者已经删除的数据 |
创建触发器
create trigger trigger_name
before/after insert/update/delete
on tbl_name for each row -- 行级触发器
begin
trigger_stmt;
end;
查看触发器
show triggers;
删除触发器
-- 如果没有指定 schema_name,默认为当前数据库。
drop trigger [schema_name] trigger_name;
锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源 (cpu、ram、i/o) 的争用外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更复杂。
MySQL 中的锁,按照锁的粒度,分为以下三类:
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的 DML 的写语句,DDL 语句,以及更新操作的事务提交语句都将被阻塞。
其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
-- 加全局锁
flush tables with read lock;
-- 数据库备份
mysqldump -uroot -p123456 dbname > dbname.sql
-- 解锁
unlock tables;
数据库中加全局锁,是一个比较重的操作,存在以下问题:
在 innoDB 引擎中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份。
# 通过快照
mysqldump --single-transaction -uroot -p123456 dbname > dbname.sql
表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在 MyISAM、InnoDB、BDB等存储引擎中。
对于表级锁,主要分为以下三类:
对于表锁,分为两类:
-- 加锁
lock tables 表名... read/write;
--解锁
unlock tables; -- 或者客户端断开连接
读锁不会阻塞其他客户端的读,但是会阻塞写。写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写。
元数据锁 (meta data lock,MDL): 加锁的过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。元数据锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。
为了避免 DML 与 DDL 冲突,保证读写的正确性。
在 MySQL 5.5 中引入了 MDL, 当对一张表进行增删改查的时候,加 MDL 读锁(共享);当对表结构进行变更操作时,加 MDL 写锁(排他)。
对应 SQL | 锁类型 | 说明 |
---|---|---|
lock tables xxx read/write | shared_read_only/shared_no_read_write | |
select、select … lock in mode | shared_read | 与 shared_read、shared_write兼容,与 exclusive 互斥 |
insert、update、delete、select … for update | shared_write | 与 shared_read、shared_write兼容,与 exclusive 互斥 |
alter table … | exclusive | 与其他的 MDL 互斥 |
-- 查看元数据锁
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks;
为了避免 DML 在执行时,加的行锁和表锁的冲突,在 InnoDB 中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。
意向锁的类型
意向锁和表锁的兼容情况
-- 查看意向锁及行锁的加锁情况
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.data_locks;
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在 InnoDB 存储引擎中。
InnoDB 的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:
InnoDB 实现了以下两种类型的行锁:
SQL | 行锁类型 | 说明 |
---|---|---|
insert … | 排他锁 | 自动加锁 |
update … | 排他锁 | 自动加锁 |
delete … | 排他锁 | 自动加锁 |
select (正常) | 不加任何锁 | |
select … lock in share mode | 共享锁 | 需要手动在 select 之后加 lock in share mode |
select … for update | 排他锁 | 需要手动在 select 之后加 for update |
默认情况下,InnoDB 在 repeatable read 事务隔离级别运行,InnoDB 使用 next-key 锁进行搜索和索引扫描,以防止幻读。
默认情况下,InnoDB 在 repeatable read 事务隔离级别运行,InnoDB 使用 next-key 锁进行搜索和索引扫描,以防止幻读。
间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。
MySQL 5.5 版本开始,默认使用 InnoDB 存储引擎,它擅长事务处理,具有奔溃恢复特性,在日常开发中使用非常广泛。下面是 InnoDB 架构图,左侧为 内存结构,右侧为磁盘结构。
Buffer pool: 缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘中加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘 IO,加快处理速度。
缓冲池以 page 页为单位,底层采用链表数据结构管理page。根据状态,将 page 分为三种类型:
Change Buffer:更改缓冲区(针对于非唯一二级索引页),在执行 DML 语句时,如果这些数据 Page 没有在 Buffer Pool 中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer 中,在未来数据被读取时,再将数据合并恢复到 Buffer pool 中,再将合并后的数据刷新到磁盘中。
Change Buffer 的意义是什么?
与聚集索引不同,二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引。同样,删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了Change Buffer 之后,我们可以在缓冲池中进行合并处理,减少磁盘IO。
Adaptive Hash Index: 自适应 hash 索引,用于优化对 Buffer Pool 数据的查询。InnoDB 存储引擎会监控对表上各索引页的查询,如果观察到hash索引可以提升速度,则建立hash索引,称之为自适应hash索引。
自适应哈希索引,无需人工干预,是系统根据情况自动完成的。
参数:adaptive_hash_index
Log Buffer: 日志缓冲区,用来保存要写入磁盘中的log日志数据(redo log、undo log),默认大小为 16 MB,日志缓冲区的日志会定期刷新到磁盘中,如果需要更新、插入或删除多行的事务,增加日志缓冲区的大小可以节省磁盘I/O。
参数:
System Tablespace: 系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建,它也肯能包含表和索引数据。(在 MySQL 5.X 版本中还包含 InnoDB 数据字典、undolog 等)
参数: innodb_data_file_path
File-Per-Table Tablespaces:每个表的文件表空间包含单个 InnoDB 表的数据和索引,并存储在文件系统上的单个数据文件中。
参数:innodb_file_per_table
General Tablespaces: 通用表空间,需要通过 create tablespace 语法创建通用表空间,在创建表时,可以指定该表空间。
-- 创建表空间
create tablespace xxx add datafile 'filename。ibd' engin=engin_name;
Undo Tablespaces: 撤销表空间,MySQL 实例在初始化时会自动创建两个默认的 undo 表空间(初始大小 16 M),用于存储 undo log 日志。
Temporary Tablespaces:InnoDB 使用会话临时表空间和全部临时表空间。存储用户创建的临时表等数据。
Doublewrite Buffer Files:双写缓冲区,innoDB 引擎将数据页从 Buffer Pool 刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据。
双写缓冲区文件
#ib_16384_0.dblwr
#ib_16384_1.dblwr
Redo log: 重做日志,是用来实现事务的持久性。该日志文件由两部分组成,重做日志缓冲区(redo log buffer)以及重做日志文件 (redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘时,发生错误时,进行数据恢复使用。
以循环的方式写入重做日志文件,涉及两个文件:
redo log 重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer) 以及 重做日志文件 (redo log file), 前者是在内存中,后者是在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。
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 in share mode(共享锁),select … for uodate、update、insert、delete(排他锁)都是一种当前读。
快照读:简单的 select (不加锁) 就是快照读,快照读,读取的记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
MVCC:全称 Multi-Version Concurrency Control, 多版本并发控制。指维护一个数据库的多个版本,使得读写操作没有冲突,快照读为 MySQL 实现 MVCC 提供了一个非阻塞读功能。MVCC 的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readview。
Undo Log 回滚日志,在 insert、update、delete 的时候产生的便于数据回滚的日志。
当 insert 的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被立即删除。
而 update、delete 的时候,产生的 undo log 日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。
undo log 版本链:不同事务或相同事务对同一条记录进行修改,会导致该记录的 undo log 生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧纪录。
Readview (读视图) 是快照读 SQL 执行时 MVCC 提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
Readview 中包含了四个核心字段:
版本链数据访问规则:trx_id 代表当前事务id
不同的隔离级别,生成 ReadView 的时机不同:
MySQL 数据库安装完成后,自带了以下四个数据库,具体作用如下:
日志分类:
错误日志,它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。
该日志是默认开启的,默认存放目录 /var/log/,默认的日志文件名为 mysqld.log。查看日志位置:
show variables like '%log_error%';
二进制日志 (BINLOG) 记录了所有的 DDL (数据定义语言) 语句 和 DML (数据操纵语言) 语句,但不包括数据查询 (select、show) 语句。
作用:
在MySQL8版本中,默认二进制日志是开启的。
show variables like '%log_bin%';
日志格式:
show variables like '%binlog_format%';
日志查看:由于日志是以二进制方式存储的,不能直接读取,需要通过二进制日志查询工具 mysqlbinlog 来查看。
mysqlbinlog [参数选项] logfilename
# -d 指数据库名称,只列出指定的数据库相关操作; -o 忽略掉日志中的前n行命令; -v 将行事件(数据变更)重构为SQL语句; -w 将行事件(数据变更)重构为SQL语句,并输出注释信息;
日志删除:对于比较繁忙的业务系统,每天生成的binlog数据巨大,如果长时间不清楚,将会占用大量磁盘空间。
也可以在 mysql 的配置文件中配置二进制日志的过期时间,设置了之后,二进制日志过期会自动删除。
show variables like '%binlog_expire_logs_seconds%';
查询日志中记录了客户端的所有操作语句,而二进制日志不包含查询数据的SQL语句。默认情况下,查询日志是未开启的。
show variables like 'general';
# 该选项用来开启查询日志,可选值 0 关闭;1 开启;
general_log = 1
# 设置日志的文件名,如果没有指定,默认的文件名未 host_name.log
general_log_file = mysql_query.log
慢查询日志记录了所有执行时间超过参数 long_query_time 设置值并且扫描记录数不小于 min_examined_row_limit 的所有的 SQL 语句的日志,默认未开启。long_query_time 默认为 10 秒,最小为 0,精度可以到微妙。
#慢查询日志开启
slow_query_log = 1
#执行时间参数
long_query_time = 2
默认情况下,不会记录管理语句,也不会记录不使用索引进行查找的查询。
#记录执行较慢的管理语句
log_slow_admin_statements=1
#记录执行较慢的未使用索引的语句
log_queries_not_indexes=1
主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。
MySQL 支持一台主库同时向多台从库进行复制,从库同时也可以作为其他从服务器的主库,实现链状复制。
MySQL 复制的优点主要包含以下三个方面:
**1. Master 主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
2. 从库读取主库的二进制日志文件 Binlog,写入到从库的中继日志 Relay log。
3. slave 重做中继日志中的事件,将改变反映它自己的数据。
准备两台服务器。分别安装MySQL,完成初始化。
Centos中MySQL安装教程(打开教程后直接跳到安装MySQL的部分)
5.0 版本需要手动开启 binlog
# my.cnf 添加
log_bin=ON
# 开放指定的3306端口号 或者 关闭服务器的防火墙
firewall-cmd --zone=public --add-port=3306/tcp -permanent
firewall-cmd -reload
# 或者
systemctl stop firewalld
systemctl disable firewalld
主库配置
# 1. 修改配置文件 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围:1-2^32-1,默认1。
server-id=1
# 是否只读,1代表只读,0代表读写
read-only=0
# 忽略的数据,指不需要同步的数据库
#binlog-ignore-db=mysql
# 指定同步的数据库
#binlog-do-db=db01
#2. 重启Mysql 服务
systemctl restart mysqld
-- 3. 登录 mysql,创建远程连接的账号,并授予主从复制的权限
-- 创建 mstest 用户,并设置密码,该用户可在任意主机连接该 MySQL 服务。
create user 'mstest'@'%' identified with mysql_native_password by 'Gjw%123456';
-- 为 'mstest'@'%' 用户分配主从复制权限
grant replication slave on *.* to 'mstest'@'%';
-- 4.通过指令,查看二进制日志的坐标
-- 字段含义, file 从哪个日志文件开始推送日志文件;position 从哪个位置开始推送日志;binlog_ignore_db 指定不需要同步的数据库。
show master status;
从库配置
# 1. 修改配置文件 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围:1-2^32-1,默认1。
server-id=2
# 是否只读,1代表只读,0代表读写
read-only=1
# 超级用户也是只读
#super-read-only=1
#2. 重启Mysql 服务
systemctl restart mysqld
-- 3. 登录 mysql,设置主库配置
-- mysql 版本是 8.0.23 中语法如下
change replication source to source_host='xxx',source_user='xxx',source_password='xxx',source_log_file='xxx',source_log_pos=xxx;
-- mysql 版本是 8.0.23之前的版本语法如下
change master to master_host='xxx',master_user='xxx',master_password='xxx',master_log_file='xxx',master_log_pos=xxx;
-- 4. 开启同步操作
-- 8.0.22 之后的语法
start replica;
-- 8.0.22 之前的语法
start slave;
-- 5. 查看主从同步状态
-- 8.0.22 之后的语法
show replica status;
-- 8.0.22 之前的语法
show slave status;
随着互联网及移动互联网的发展,应用系统的数据量也是成指数式增长的,若采用单数据库进行数据存储,存在以下性能瓶颈:
分库分表的中心思想都是将数据分散存储,使得单一数据库/表的数据量变小来缓解单一数据库性能的问题,从而达到提升数据库性能的目的。
垂直分库的特点:
垂直分表的特点:
水平分库:以字段为依据,按照一定策略,将一个库的数据拆分到多个库中。
水平分库的特点:
水平分表的特点:
Mycat 是开源的、活跃的、基于 Java 语言编写的 MySQL 数据库中间件。可以像使用 mysql 一样来使用 mycat,对于开发人员来说根本感觉不到 mycat 的存在。
Mycat 优势:
Mycat 安装:MyCat 支持 Windows 和 Linux 运行环境,我们需要在准备好的服务器上安装如下软件。
服务器 | 安装软件 | 说明 |
---|---|---|
server-1 | jdk、Mycat、MySQL | MyCat中间件服务器、分片服务器 |
server-2 | MySQL | 分片服务器 |
server-3 | MySQL | 分片服务器 |
# 下载 MyCat Linux 版本,在 centos7 安装
wget https://github.com/MyCATApache/Mycat-Server/releases/download/Mycat-server-1675-release/Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
# 解压 MyCat 压缩包到 /usr/local/
tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /usr/local/
需求:
由于 tb_order 表中数据量很大,磁盘IO及容量都到达了瓶颈,现在需要对 tb_order 表进行数据分片,分为三个数据节点,每一个节点主机位于不同的服务器上,具体结构。参考下图:
vim /usr/local/mycat/conf/schema.xml
# 切换目录到 /usr/local/mycat/
cd /usr/local/mycat/
#启动
bin/mycat start
#停止
bin/mycat stop
#查看服务是否启动成功
tail -f wrapper.log
Mycat 启动之后,占用端口号 8066;
分片测试:
# 连接并登录 Mycat
mysql -h 192.168.3.27 -P 8066 -u root -p123456
schema.xml 作为 MyCat 中最重要的配置文件之一,涵盖了 MyCat 的逻辑库、逻辑表、分片规则、分片节点及数据源的配置。
主要包含以下三组标签:
schema 标签:用于定义 MyCat 实例中的逻辑库,一个 MyCat 实例,可以有多个逻辑库,可以通过 schema 标签来划分不同的逻辑库。
MyCat 中的逻辑库的概念,等同于 MySQL 中的 database 概念,需要操作某个逻辑库下的表时,也需要切换逻辑库 (use xxx);
schema核心属性:
schema 标签(table): 定义了 MyCat 中逻辑库 schema 下的逻辑表,所有需要拆分的表都需要在 table 标签中定义。
schema 下 table 核心属性:
dataNode 标签: 定义了 MyCat 中的数据节点,也就是我们通常说的数据分片。一个 dataNode 标签就是一个独立的数据分片。
dataNode 核心属性:
dataHost标签:在 MyCat 逻辑库中作为底层标签存在,直接定义了具体的数据库实例、读写分离、心跳语句。
dataHost 核心属性:
rule.xml 中定义所有拆分表的规则,在使用过程中可以灵活的使用分片算法,或者对同一个分片算法使用不同的参数,它让分片过程可配置化。主要包含两类标签:
server.xml 配置文件包含了 MyCat 的系统配置信息,主要有两个重要的标签:system、user
全局表配置:对于省、市、区表是属于数据字典表,在多个业务模块中都可能会遇到,可以将其设置为全局表,利于业务操作。
分片规则:
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
<property name="startIndex">0property>
<property name="size">2property>
<property name="partitionCount">3property>
<property name="defaultPartition">2property>
function>
<function name="sharding-by-long-hash" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">2,1property>
<property name="partitionLength">256,512property>
function>
<function name="sharding-by-stringhash" class="io.mycat.route.function.PartitionByString">
<property name="partitionLength">512property>
<property name="partitionCount">2property>
<property name="hashSlice">0:2property>
function>
Mycat 默认开通2个端口,可以在 server.xml 中进行修改。
mysql -h 192.168.3.27 -P 9066 -u root -p123456
Mycat-eye: Mycat-web(Mycat-eye) 是对 mycat-server 提供监控服务,功能不局限于对 mycat-server 使用,他通过 JDBC 连接对 Mycat、MySQL 监控,监控远程服务器(目前仅限于Linux 系统)的cpu、内存、网络、磁盘。
Mycat-eye 运行过程中需要依赖 zookeeper。因此需要先安装 zookeeper。
# zookeeper 安装
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.3/apache-zookeeper-3.8.3-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.3-bin.tar.gz -C /usr/local/
mkdir /usr/local/apache-zookeeper-3.8.3-bin/data
bin/zkServer.sh start
bin/zkServer.sh status
# mycat-web 安装 需要先获取 MyCatWeb 压缩包
tar -zxvf Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz -C /usr/local/
cd /usr/local/mycat-web/
sh start.sh
# 访问 localhost:8082/mycat 访问
读写分离,简单地说是把对数据库的读和写操作分开,以对应不同的数据库服务器。主数据库提供写操作,从数据库提供读操作,这样能有效地减轻单台数据库的压力。
通过 MyCat 即可轻易实现上述功能,不仅可以支持 MySQL,也可以支持 Oracle 和 SQL Server。
MyCat 控制后台数据库的读写分离和负载均衡由 schema.xml 文件 datahost 标签的 balance 属性控制。
<schema name="DB_RW" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
schema>
<dataNode name="dn1" dataHost="dhost1" database="testdb"/>
<dataHost name="dhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="jdbc">
<heartbeat>select user()heartbeat>
<writeHost host="master" url="jdbc:mysql://192.168.3.27:3306?useSSL=false" user="root" password="1234">
<readHost host="slave" url="jdbc:mysql://192.168.3.28:3306?useSSL=false" user="root" password="1234"/>
writeHost>
dataHost>
<user name="root" defaultAccount="true">
<property name="password">123456property>
<property name="schema">DB_RWproperty>
user>
负载均衡 balance 取值的含义:
问题: 主节点 Master 宕机之后,业务系统就只能够读,而不能写入数据了。
双主双从,一个主机 Master1 用于处理所有写请求,它的从机 slave1 和另一台主机 Master2 还有它的从机 slave2 负责所有读请求。当 Master1 主机宕机后,Master2 主机负责写请求,Master1 和 Master2 互为备机。
主库配置 master1:
#修改 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围 1-2^32-1,默认为1.
server-id=1
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
主库配置 master2:
#修改 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围 1-2^32-1,默认为1.
server-id=3
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
两台主库创建账户并授权:
-- 创建 test 用户,并设置密码,该用户可在任意主机连接该 MySQL 服务
create user 'test'@'%' identified with mysql_native_password by '1123';
-- 为 test 用户分配主从复制权限
grant replication slave on *.* to 'test'@'%';
-- 查看两台主库的二进制日志坐标
show master status;
从库配置 slave1:
#修改 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围 1-2^32-1,默认为1.
server-id=2
从库配置 slave2:
#修改 /etc/my.cnf
# mysql 服务id,保证整个集群环境中唯一,取值范围 1-2^32-1,默认为1.
server-id=4
两台从库配置关联的主库:
需要注意 slave1 对应的是 master1,slave2 对应的是 master2
-- mysql 版本是 8.0.23 中语法如下
change replication source to source_host='xxx',source_user='xxx',source_password='xxx',source_log_file='xxx',source_log_pos=xxx;
-- mysql 版本是 8.0.23之前的版本语法如下
change master to master_host='xxx',master_user='xxx',master_password='xxx',master_log_file='xxx',master_log_pos=xxx;
-- 开启同步操作
-- 8.0.22 之后的语法
start replica;
-- 8.0.22 之前的语法
start slave;
-- 5. 查看主从同步状态
-- 8.0.22 之后的语法
show replica status\G;
-- 8.0.22 之前的语法
show slave status\G;
两台主库相互复制:Master2 复制 Master1,Master1 复制 Master2
-- mysql 版本是 8.0.23 中语法如下
change replication source to source_host='xxx',source_user='xxx',source_password='xxx',source_log_file='xxx',source_log_pos=xxx;
-- mysql 版本是 8.0.23之前的版本语法如下
change master to master_host='xxx',master_user='xxx',master_password='xxx',master_log_file='xxx',master_log_pos=xxx;
-- 开启同步操作
-- 8.0.22 之后的语法
start replica;
-- 8.0.22 之前的语法
start slave;
-- 5. 查看主从同步状态
-- 8.0.22 之后的语法
show replica status\G;
-- 8.0.22 之前的语法
show slave status\G;
双主双从的读写分离:MyCat 控制后台数据库的读写分离和负载均衡由 schema 标签的 balance 属性控制,通过 writeType 及 switchType 来完成失败自动切换。
<schema name="DB_RW" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
schema>
<dataNode name="dn1" dataHost="dhost1" database="testdb"/>
<dataHost name="dhost1" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1" dbType="mysql" dbDriver="jdbc" slaveThreahold="100">
<heartbeat>select user()heartbeat>
<writeHost host="master1" url="jdbc:mysql://192.168.3.27:3306?useSSL=false" user="root" password="1234">
<readHost host="slave1" url="jdbc:mysql://192.168.3.28:3306?useSSL=false" user="root" password="1234"/>
writeHost>
<writeHost host="master2" url="jdbc:mysql://192.168.3.27:3306?useSSL=false" user="root" password="1234">
<readHost host="slave2" url="jdbc:mysql://192.168.3.28:3306?useSSL=false" user="root" password="1234"/>
writeHost>
dataHost>
<user name="root" defaultAccount="true">
<property name="password">123456property>
<property name="schema">DB_RWproperty>
user>
balance=“1”: 代表全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2),并且M1和M2互为主备。正常情况下,M2、S1、S2都参与 select 语句的负载均衡。
writeType:
switchType:
为什么InnoDB存储引擎选择使用B+Tree索引结构
相对于二叉树,层级更少,搜索效率高
相对于 B-Tree, 无论叶子节点还是非叶子节点,都会保存数据,这样导致页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低。
相对于 Hash 索引, B+Tree 支持范围匹配和排序操作。
一张表,有四个字段(id、username、password、status),由于数据量大,需要对以下SQL语句进行优化,该如何进行才是最优方案:
-- username\password 建立联合索引
select id,username,password from user where username = 'test';
黑马程序员
MySQl 官方网站
可视化数据结构演示
MySQL doc
Mycat开源项目