Mysql学习
1 Mysql的介绍
MySQL是一个关系型数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL是开源的。
MySql支持大型的数据库,可以处理拥有成千上万条记录的大型数据库。
MySql支持标准的SQL数据语言形式。
MySql可以允许在多个系统上,并且支持多种语言。
MySql对PHP有很好的支持。
MySql支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB
MySql是可以定制的,采用了GPL协议。
2 mysql语言类型及介绍
2.1 DCL
DCL 数据控制语言 (Data Control Language ) 在SQL语言中,是一种可对数据访问权进行控制的指令,它可以控制特定用户账户对数据表、查看表、存储程序、用户自定义函数等数据库对象的控制权,由 GRANT 和 REVOKE 两个指令组成。(主要是对用户层面的权限管理以及用户账号管理)
用户
2.1.1 创建用户
create user '用户名'@'IP地址' identified WITH mysql_native_password by '密码';
flush privileges;
具体例子:
CREATE USER 'alian'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;
2.1.2 修改用户名
rename user '用户名'@'IP地址' to '新用户名'@'IP地址';
2.1.3 修改密码
#切换到mysql库
use mysql;
#更新密码
UPDATE user SET password=password('新密码') WHERE user='用户名' AND host='IP地址';
#刷新权限
FLUSH PRIVILEGES;
或者
ALTER USER '用户名'@'IP地址' IDENTIFIED WITH mysql_native_password BY '新密码';
flush privileges;
或者
#普通用户登录后
SET PASSWORD=password('新密码');
FLUSH PRIVILEGES;
2.1.4 删除用户
#注意这里的IP地址,一个用户可能会有多个
drop user '用户名'@'IP地址';
#比如
drop user 'Alian'@'192.168.0.100';
权限管理
2.1.5 授权
grant 权限1, 权限2, 权限3,… ,权限n on 数据库名.表名 to 用户名@地址;
关于 数据库名.表名 的说明:
. 表示任意库的任意表(不建议)
mysql.* 表示mysql库的任意表
mysql.user 表示mysql库的user表
关于 用户名@地址 的说明(这里都是英文的单引号):
’alian’@‘localhost’ :表示只允许本机登录
’alian’@’%’ :表示任意地址登录
’alian’@'192.168.0.100’ :表示只允许ip为192.168.0.100的地址登录
’alian’@‘192.168..’ :表示只允许ip为192.168网段的地址登录
把数据库的所有库的所有权限都给alian,并且可以指定ip地址
#把数据库的所有库的所有权限都给alian,并且是任意ip地址都可以操作
grant all privileges on *.* to 'alian'@'%';
flush privileges;
把mysql数据库的所有权限都给alian
#把mysql数据库的所有权限都给alian,并且是任意ip地址都可以操作
grant all privileges on mysql.* to 'alian'@'%';
flush privileges;
把mysql数据库的user表的所有权限都给alian,并且是任意ip地址都可以操作
#把mysql数据库的user表的所有权限都给alian,并且是只能通过192.138.0.10才可以操作
grant all privileges on mysql.user to 'alian'@'192.138.0.10';
flush privileges;
把mysql数据库的user表的(查询,插入,更新,删除)的权限都给alian,并且是任意ip地址都可以操作
#把mysql数据库的user表的(查询,插入,更新,删除)的权限都给alian,并且是任意ip地址都可以操作
grant SELECT, INSERT, UPDATE, DELETE on mysql.user to 'alian'@'%';
flush privileges;
2.1.5 产看权限
show grants for 'alian'@'%';
2.1.6 回收权限
revoke 权限1, 权限2…权限n on 数据库名.表名 from 用户名@地址;
收回部分权限
#回收用户的更新和删除mysql(默认的库)数据库的权限
revoke update,delete on mysql.user from 'alian'@'%';
2.2 DDL
DDL (Data Definition Language)数据定义语言,适用范围:对数据库中的某些对象(例如,database,TABLE)进行管理,如Create,ALTER和Drop, DDL 操作是隐性提交的,不能rollback!
数据库操作
2.2.1创建数据库
简单写法,采用数据库的默认设置
CREATE DATABASE 数据库名;
推荐写法,设置 基字符集 和 数据库排序规则 ,数据库的名称不能更改
CREATE DATABASE IF NOT EXISTS 数据库名
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_general_ci;
2.2.2显示数据库
show databases; #记得是databases
2.2.3选择数据库
USE 数据库名
2.2.4修改数据库
修改数据库一般修改的字符集,排序规则。数据库的表名一般不能直接修改,修改方式为:迁移出表数据新建新库导入;或者直接同步原表到新表;
Alter DATABASE 数据库名 CHARACTER SET 字符集;
2.2.5删除数据库
DROP DATABASE 数据库名;
DROP DATABASE IF EXISTS 数据库名;
table操作
2.2.6创建表
CREATE TABLE 表名(); # 创建数据库
CREATE TABLE IF NOT EXISTS 表名(); # 如果数据库不存在则创建数据库
CREATE TABLE 表名 AS (查询语句); # 基于现有的表复制成一个新表,同时导入查出的数据
创建表的格式:
CREATE TABLE `user` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` INT UNSIGNED NOT NULL DEFAULT '1000' COMMENT '学生编号',
`user_name` VARCHAR(10) NOT NULL DEFAULT '' COMMENT '学生姓名',
`gender` CHAR(1) NOT NULL DEFAULT '1' COMMENT '性别',
`birthday` DATE NOT NULL DEFAULT '1970-01-01' COMMENT '生日',
`home_address` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '家庭住址',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_id` (`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学生信息表';
注意事项:
- mysql创建表尽量保留一个自增长的id,并且设置为 UNSIGNED
- 字段的命名要有意义,结合编程语言可以把驼峰模式改为 下划线 分割会自动映射
- 字段的类型一定要合理,并且设置合适的长度,建议加上字段说明 COMMENT
- 设置任意一个字段一定要设置默认值,尽量避免值为 NULL 的情况
- create_time 和 update_time 一般业务表都会有的,一个是创建的时间,然后都不会变,一个是随着数据改变,时间也会表,非常的实用
- 根据情况设置索引,索引的命名规范(主键索引: pk_ 即primary key;唯一索引: uk_ 即 unique key;普通索引: idx_ 即index的简称)
- 业务表引擎一般是InnoDB,因为它支持事务
- 表的字符集设置为 utf8mb4 ,排序规则 utf8mb4_general_ci
- 最后记得加上表的注释 COMMENT
2.2.7查看表
查看所有表
show TABLEs;
查看表结构
desc 数据库的表名;
显示建表语句
show create TABLE 数据库的表名;
2.2.8修改表
修改表名或注释
ALTER TABLE 原数据库表名 rename to 新数据库表名;
ALTER TABLE 数据库表名 COMMENT='这是表的注释';
修改字段
添加一个字段,默认添加再最后一个。
ALTER TABLE 表名 ADD [COLUMN] 字段名 数据类型 [first|after 字段名];
修改一个字段:数据类型、长度、默认值
ALTER TABLE 表名 MODIFY 字段名 数据类型;
重命名一个字段
ALTER TABLE 表名 CHANGE 旧字段 新字段 数据类型;
删除一个字段
ALTER TABLE 表名 DROP COLUMN 字段名
ALTER TABLE 数据库表名 add 要添加的字段名 数据类型 约束条件 字段说明 after 字段名;
#比如在student表最后添加一个age字段
ALTER TABLE student add `age` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '年龄';
#比如在student表中的gender字段后添加一个age字段
ALTER TABLE student add `age` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '年龄' after gender;
#如果是在student表中的gender字段前添加一个age字段
ALTER TABLE student add `age` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '年龄' before gender;
2.2.9删除表
三种方式
1. truncate table
truncate table 表名
注意:
不能与where一起使用。
truncate删除数据后是不可以rollback的。
truncate删除数据后会重置Identity(标识列、自增字段),相当于自增列会被置为初始值,又重新从1开始记录,而不是接着原来的ID数。
truncate删除数据后不写服务器log,整体删除速度快。
truncate删除数据后不激活trigger(触发器)。
2. drop table
drop table 表名;
#或者是
drop table if exists 表名;
注意:
truncate只会清除表数据,drop不光清除表数据还要删除表结构。
3. delete
delete from 表名 where id='1';
#或者是
delete from 表名;
注意:
- delete含义:你要删除哪张表的数据 ?你要删掉哪些行 ?
- delete可以删除一行,也可以删除多行;
- 如果不加where条件,则是删除表所有的数据,这是很危险的!不建议这样做!
注意事项:
1、当你不再需要该表时, 用 drop;
2、当你仍要保留该表,但要删除所有数据表记录时, 用 truncate;
3、当你要删除部分记录或者有可能会后悔的话, 用 delete。
索引操作
2.2.10 主键
添加主键
ALTER TABLE 数据库的表名 ADD PRIMARY KEY(字段名称);
添加复合主键
ALTER TABLE 数据库的表名 ADD PRIMARY KEY(字段名称1,字段名称2,...);
删除主键
ALTER TABLE 数据库的表名 DROP PRIMARY KEY;
例外:如果是自增长的主键需要先移除自增长设置
#用MODIFY删除自增长属性,注意MODIFY不能去掉主键属性
ALTER TABLE student MODIFY id INT UNSIGNED NOT NULL COMMENT '主键';
#删除主键
ALTER TABLE student DROP PRIMARY KEY;
创建唯一索引
CREATE UNIQUE INDEX 索引名称 ON 表名称(表字段)
添加唯一索引
ALTER TABLE 数据库的表名 ADD UNIQUE 索引名称(字段名称);
#比如给student的user_id字段添加索引,索引名称为idx_user_id
ALTER TABLE student ADD UNIQUE uk_user_id(user_id);
创建普通索引
#此处length表示字段的前多少位,也就是短索引
CREATE INDEX 索引名称 ON 数据库的表名(字段名称(length))
添加普通索引
ALTER TABLE 数据库的表名 add INDEX 索引名称(字段名称);
#比如给student的user_name字段添加索引,索引名称为idx_user_name
ALTER TABLE student ADD INDEX idx_user_name(user_name);
查看表的索引
SHOW INDEX FROM 数据库的表名;
删除索引
#删除索引
ALTER TABLE 数据库的表名 DROP UNIQUE 索引名称;
#比如删除student表上user_name字段上的索引
ALTER TABLE student DROP INDEX idx_user_name;
或者
#或者
DROP INDEX 索引名称 on 数据库的表名;
#比如删除student表上user_name字段上的索引
DROP INDEX idx_user_name on student;
2.3 DML
数据操纵语言(Data Manipulation Language, DML)是用于数据库操作,对数据库其中的对象和数据运行访问工作的编程语句,通常是数据库专用编程语言之中的一个子集,例如在信息软件产业通行标准的SQL语言中,以INSERT、UPDATE、DELETE三种指令为核心,分别代表插入(意指新增或创建)、更新(修改)与删除(销毁)。
2.3.1新增
插入单条
INSERT INTO 数据库表名
SET
field1= value1, field2= value2, ..., fieldN=valueN;
或者
INSERT INTO 数据库表名
SET
field1= value1, field2= value2, ..., fieldN=valueN;
插入多条
INSERT INTO 数据库表名
(field1, field2,...fieldN)
VALUES
(valuek1, valuek2,...valuekN),
(valuem1, valuem2,...valuemN),
(valuen1, valuen2,...valuenN),
...
(valuep1, valuep2,...valuepN);
或者
INSERT INTO 要插入的数据库表名
(field1, field2,...fieldN)
SELECT
(fieldk1, fieldk2,...fieldkN)
FROM
被查询的数据库表名
2.3.2修改
UPDATE 数据库表名
SET field1 = newValue1, field2 = newValue2
WHERE 条件
2.3.3删除
DELETE FROM 数据库表名 WHERE 条件
2.4 DQL
数据查询语言,用来查询数据库中表的记录(数据)
单表查询
2.4.1 简单查询
-
基本语法:
select 字段名 from 表名;
-
as关键字可以给查询的列起别名,将显示的查询结果列名显示为别名。as可以省略为空格。
select class_code as '班级编号', user_code as '学号', user_name as '姓名', birthday as '出生年月', home_address as '家庭地址' from tb_student;
-
字段名可以使用数学表达式:
select 字段名*5 from 表名;
-
结果集
#字段1 和 字段2 必须是 查询语句的查出来的列名 select 字段1,字段2 from (子查询语句) as 结果集的别名;
2.4.2 条件查询
where关键字后面可以添加一下查询条件:
= 等于
<> 或 != 不等于
< 小于
> 大于
between … and … 在两个值之间,等同于 >= and <=
is null 为null(is not null 不为空)
and 并且
or 或者
in (value1,value2)包括,相当于多个or(not in 不在这个范围中)
not 可以取非,主要用在is或in中
like 模糊查询,%代表任意多个字符,_表示任意一个字符
#比如我们查询姓“张”的学生的学号和姓名
select user_code, user_name from tb_student where user_name like '张%';
#比如我们查询名字中第三个字是“雨”的学生的学号和姓名
select user_code, user_name from tb_student where user_name like '__雨';
#比如我们查询名字中第二个字是“雨”的学生的学号和姓名
select user_code, user_name from tb_student where user_name like '_雨_';
#家庭地址第四到第六位是"观光路"的学生的学号,姓名和具体地址
SELECT user_code, user_name,home_address FROM tb_student where home_address like '___观光路%';
分组查询
在一条select 语句当中,如果有group by语句的话,select后面只能跟分组字段或者分组函数。
select ... from ... where ... group by ... order by [字段1],[字段2]
按照两个字段分组
分组完后可以使用having进行条件判断
select ... from ... where ... group by ... having ...
having后面只能跟聚合函数和分组条件,并且having中可以使用别名。
只有mysql中允许没有group by单独使用having,所以不要这样使用。
如果过滤条件中使用聚合函数,则此过滤条件必须声明在HAVING中。
2.4.3 排序
order by [字段]
按照[字段]排序,默认升序。
order by [字段] desc
按照[字段]排序,指定降序
order by [字段] asc
按照[字段]排序,指定升序
order by [字段1] asc,[字段2] asc
先按照[字段1]升序排序,[字段1]相同按照字段2升序排序
order by 2
按照查询结果的第二列排序
单表查询关键字执行顺序
多表查询
select 字段1,字段2... from 表1,表2... [where 条件]
2.4.4 笛卡尔积
当两张表连接进行查询时,没有任何条件限制会发生笛卡尔积现象。即一张表中的每一条数据都和另一张表每个字段匹配。
# 也叫交叉连接
select * from 表1,表2;
select * from 表1 CROSS JOIN 表2; # sql99
2.4.5 内连接
两个表都是主表,只匹配上都有的字段
select 别名1.字段,别名2.字段 from 表1 别名1 inner join 表1 别名1 on 别名1.字段=别名2.字段;
如果用*代替查询字段,则会查出双倍表1字段,相同的字段名会用【字段1】显示
2.4.6 外连接
左外连接:
将join关键字左边的表看成主表,关键字右边看成附表。 将主表数据都查出来,主表符合条件的字段将附表字段也查出来。不符合条件的则附表字段显示为null。
select * from 表1 left JOIN 表2 on 表1.字段 = 表2.字段 # 99 语法
右外连接:
将join关键字右边的表看成主表,关键字左边看成附表。 将主表数据都查出来,主表符合条件的字段将附表字段也查出来。不符合条件的则附表字段显示为null。
select * from 表1 right outer JOIN 表2 on 表1.字段 = 表2.字段
2.4.7等值连接
select * from 表1,表2 where 表1.字段 = 表2.字段 # 92的语法,where时添加条件。
select * from 表1 inner join 表2 on 表1.字段 = 表2.字段 # 99 语法
2.4.8非等值连接
select * from 表1,表2 where 表1.字段 between 表2.字段 and 表2.字段 # 92 语法
select * from 表1 inner join 表2 on 表1.字段 >= 表2.字段 # 99 语法
2.4.9全连接
全连接就是左右两张表都是主表,都查出来。
select * from 表1 FULL outer JOIN 表2 on 表1.字段 = 表2.字段 # 99 语法,MYSQL不支持
结果是表1表2的所有数据
子查询
某些情况下,当进行一个查询时,需要的条件或数据要用另外一个 select 语句的结果,这个时候,就要用到子查询。
可以加入的位置
1、where型子查询
#查询比“孙红雷”的工资高的员工编号
SELECT * FROM t_salary
WHERE basic_salary > (SELECT basic_salary FROM t_employee INNER JOIN t_salary ON t_employee.eid=t_salary.eid WHERE t_employee.ename='孙红雷');
#查询和孙红雷,李晨在同一个部门的员工
SELECT * FROM t_employee
WHERE dept_id IN(SELECT dept_id FROM t_employee WHERE ename='孙红雷' OR ename = '李晨');
SELECT * FROM t_employee
WHERE dept_id = ANY(SELECT dept_id FROM t_employee WHERE ename='孙红雷' OR ename = '李晨');
#查询全公司工资最高的员工编号,基本工资
SELECT eid,basic_salary FROM t_salary
WHERE basic_salary = (SELECT MAX(basic_salary) FROM t_salary);
SELECT eid,basic_salary FROM t_salary
WHERE basic_salary >= ALL(SELECT basic_salary FROM t_salary);
2、from型子查询
#找出比部门平均工资高的员工编号,基本工资
SELECT t_employee.eid,basic_salary
FROM t_salary INNER JOIN t_employee INNER JOIN (
SELECT emp.dept_id AS did,AVG(s.basic_salary) AS avg_salary
FROM t_employee AS emp,t_salary AS s
WHERE emp.eid = s.eid
GROUP BY emp.dept_id) AS temp
ON t_salary.eid = t_employee.eid AND t_employee.dept_id = temp.did
WHERE t_salary.basic_salary > temp.avg_salary;
3、exists型子查询
SELECT * FROM t_department
WHERE EXISTS (SELECT * FROM t_employee WHERE t_employee.dept_id = t_department.did);
3.mysql存储引擎
4.mysql索引
5.mysql
2.5常用函数
流程控制函数
IF(VALUE,VALUE1,VALUE2) # 如果VLAUE为真,则输出VALUE1,否则输出VALUE2。
IFNULL(VALUE,VALUE1) # 如果value不为null,则为value,否则为value1。
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 ELSE 结果3 END # 相当于if else if else if else
CASE expr WHEN 常量1 THEN 值1 WHEN 常量值2 THEN 值2 ELSE 值n END # 相当于switch ... case...
字符串函数
ASCLL(S) # 返回字符串s中的第一个字符的ASCII码值
CHAR_LENGTH(s) # 返回字符串s的字符数,s为null则返回为null
LENGTH(s) # 返回字符串s的字节数
concat(string1,string2....) # 字符串拼接
concat_ws(x,s1,s2....sn) # 同concat(string1,string2....) 函数,但是每个字符串之间都要加上x
INSERT(str,idx,len,replacestr) # 将字符串str从第idx位置开始,len个字符长的字串替换为字符串replacestr,字符串索引从1开始。
REPLACE(str,a,b) # 用字符串b替换字符串str中所有出现的字符串a
upper(s) # 转大写
lower (s) # 转小写
LEFT(str,n) # 返回字符串str最左边的n个字符
RIGHT(str,n) # 返回字符串str最右边的n个字符
TRIM(s) # 去掉字符串s开始和结尾的空格
TRIM(s1 FROM s) # 去掉字符串s开始与结尾的s1
TRIM(LEADING s1 FROM s) # 去掉字符串s开始处的s1
TRIM(TRAILING s1 FROM s) # 去掉字符串s结尾处的s1
LTRIM(s) # 去掉字符串s左侧的空格
RTRIM(s) # 去掉字符串s右侧的空格
repeat(n) # 返回str重复n次的结果
space(n) # 返回n个空格
strcmp(s1,s2) # 比较字符串s1,s2的ASCII码值的大小
SUBSTR(s,index,len) # 返回字符串s的index位置其len个字符,作用同SUBSTRING(s,n,len)、MID(s,n,len)相同
LOCATE(substr,str) # 返回字符串substr在字符串str中首次出现的位置,作用于POSITION(substr IN str)、INSTR(str,substr)相同。未找到,返回0。
ELT(m,s1,s2,....,sn) # 返回指定位置的字符串,如果m = 1;则返回s1,如果m=n,则返回sn
FIELD(s,s1,s2,s3) # 返回s在字符串列表中第一次出现的位置
FIND_IN_SET(s1,s2) # 返回字符串s1在字符串s2中出现的位置。其中字符串s2是一个以逗号分隔的字符串
数字函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MTBCVx9F-1668006561186)(C:\Users\mingqiu.qing\AppData\Roaming\Typora\typora-user-images\image-20221105202408443.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IFgxGmf-1668006561187)(C:\Users\mingqiu.qing\AppData\Roaming\Typora\typora-user-images\image-20221105202425706.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BqB9dugx-1668006561188)(C:\Users\mingqiu.qing\AppData\Roaming\Typora\typora-user-images\image-20221105202441256.png)]
随机数:
#得到一个随机数
SELECT rand();
日期函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTAIhECM-1668006561188)(C:\Users\mingqiu.qing\AppData\Roaming\Typora\typora-user-images\image-20221105202607378.png)]
3 数据类型
3.1数值类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ihFxqv2-1668006561188)(C:\Users\mingqiu.qing\Desktop\image-20221106192448699.png)]
3.2日期和时间类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGr77ZKz-1668006561189)(C:\Users\mingqiu.qing\Desktop\image-20221106192527771.png)]
3.3字符串类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4L8IXEJK-1668006561189)(C:\Users\mingqiu.qing\Desktop\image-20221106192556629.png)]
注意点
- 如果一个字段设置了无符号和填充零属性,那么无论这个字段存储什么数值,数值的长度都会与设置的显示宽度一致,比如插入1,显示为00000000001,左边补了 10 个零直至长度达到 11 位
- 设置字段的显示宽度并不限制字段存储值的范围,如果你设置int(6),但是仍然可以存储99999999
- 设置的字符宽度只对数值长度不满足宽度时有效,比如设置int(6),插入1时,长度不足6,因此在左边补充5个零,如果你插入888888888,那个显示宽度就不起作用了
4 存储引擎
MySQL5.5.5之后默认采用Innodb作为默认存储引擎,InnoDB 事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。
MyISAM 是基于 ISAM 的存储引擎,并对其进行扩展,是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事务。
4.1InnoDB
是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。
实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。
主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。
内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。
支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。
4.2MyISAM
设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。
提供了大量的特性,包括压缩表、空间数据索引等。
不支持事务。
不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。
可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。
如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。
4.3比较
- 事务: InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。
- 并发: MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
- 外键: InnoDB 支持外键。
- 备份: InnoDB 支持在线热备份。
- 崩溃恢复: MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
- 其它特性: MyISAM 支持压缩表和空间数据索引。
InnoDB | MyISAM |
---|---|
适合于大量修改操作 | 适合于大量查询操作 |
行锁 | 表锁 |
支持外键 | 不支持外键 |
支持事务 | 不支持事务 |
使用聚集索引 | 使用非聚集索引 |
不支持全文索引 | 支持全文索引 |
5 索引
索引( index )是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。 总结:索引就是数据结构,索引的作用是高效获取数据。
5.1索引的优缺点
优点
- 加快了数据检索速率,降低了数据库的IO成本
- 通过索引列对数据进行排序,有利于范围查询
缺点
- 占据物理存储空间
- 在更新时需要维护对应的索引
5.2 索引的基本原理
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理很简单,就是把无序的数据变成有序的查询
(1)把创建了索引的列的内容进行排序
(2)对排序结果生成倒排表
(3)在倒排表内容上拼上数据地址链
(4)在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
5.3索引类型
主索引(聚簇索引):
主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
辅助索引(非聚簇索引)
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
哈希索引
哈希索引能以 O(1) 时间进行查找,但是失去了有序性,它具有以下限制:
- 无法用于排序与分组;
- 只支持精确查找,无法用于部分查找和范围查找。
InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NihMkg6o-1668006561190)(C:\Users\mingqiu.qing\Desktop\image-20221106195739247.png)]
全文索引
MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
全文索引一般使用倒排索引实现,它记录着关键词到其所在文档的映射。
InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。
单列索引
由单个字段组成
Where条件中的字段查询时可以应用到索引
alter table product add index idx_orderno(orderno);
组合索引
由多个字段组成
alter table product add index idx_orderno_createtime(orderno,createtime);
前缀索引
语法:index(field(10)),使用字段值的前10个字符建立索引,默认是使用字段的全部内容建立索引。
前提:前缀的标识度高。比如密码就适合建立前缀索引,因为密码几乎各不相同。
实操的难度:在于前缀截取的长度。
我们可以利用select count(*)/count(distinct left(password,prefixLen));,通过从调整prefixLen的值(从1自增)查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前prefixLen个字符几乎能确定唯一一条记录)
索引覆盖
索引包含所有需要查询的字段的值。
具有以下优点:
- 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。
- 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。
- 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。
5.4 索引相关条件
创建索引规范:
(1)单张表中索引数量不超过5个。
(2)单个索引中的字段数不超过5个。
(3)索引名必须全部使用小写。
(4)非唯一索引按照“idx_字段名称[_字段名称]”进行命名。例如idx_age_name。
(5)唯一索引按照“uniq_字段名称[_字段名称]”进行命名。例如uniq_age_name。
(6)组合索引建议包含所有字段名,过长的字段名可以采用缩写形式。例如idx_age_name_add。
(7)表必须有主键,推荐使用UNSIGNED自增列作为主键。
(8)唯一键由3个以下字段组成,并且字段都是整形时,可使用唯一键作为主键。其他情况下,建议使用自增列或发号器作主键。
(9)禁止冗余索引。
(10)禁止重复索引。
(11)禁止使用外键。
(12)联表查询时JOIN列的数据类型必须相同,并且要建立索引。
(13)不在低基数列上建立索引,例如“性别”。
(14)选择区分度大的列建立索引。组合索引中,区分度大的字段放在最前。
(15)对字符串使用前缀索引,前缀索引长度建议不超过8个字符,需要根据业务实际需求确定。
(16)不对过长的VARCHAR字段建立索引。建议优先考虑前缀索引,或添加CRC32或MD5伪列并建立索引。
(17)合理创建联合索引,(a,b,c)相当于(a).(a,b). (a,b,c)。
(18)合理使用覆盖索引减少IO,避免排序。
(19)注意最左匹配原则
失效场景
(1) where条件中没有内容
(2)否定条件:<> , not in , not exists
(3)join中连接字段类型(或字符集)不一致
(4)扫描内容超过全表的20% -
(5)where条件的字段存在函数运算- like ‘%name’
(6)出现隐式字符类型转换
6 性能优化
explain大法
-
id:表示被操作的顺序;id值大,先被执行,若id值相同,执行顺序从上到下
-
select_type:查询中每个select子句的类型
- SIMPLE:简单查询,不包含 UNION 或者子查询
- PRIMARY:查询中如果包含子查询或其他部分,外层的 SELECT 将被标记为 PRIMARY
- SUBQUERY:子查询中的第一个 SELECT
- UNION:在 UNION 语句中,UNION 之后出现的 SELECT
- DERIVED:在 FROM 中出现的子查询将被标记为 DERIVED
- UNION RESULT:UNION 查询的结果
-
table:被操作对象的名字,通常是表名
-
partitions:匹配分区信息(非分区表为NULL)
-
type:查询执行的类型,描述了查询是如何执行的
- const:表中最多只有一行匹配的记录,常用于使用主键或唯一索引的所有字段作为查询条件
- eq_ref:当连表查询时,前一张表的行在当前这张表中只有一行与之对应。是除了 system 与 const 之外最好的 join 方式,常用于使用主键或唯一索引的所有字段作为连表条件
- ref:使用普通索引作为查询条件,查询结果可能找到多个符合条件的行
- index_merge:当查询条件使用了多个索引时,表示开启了 Index Merge 优化,此时执行计划中的key 列列出了使用到的索引
- range:对索引列进行范围查询,执行计划中的 key 列表示哪个索引被使用了
- index:全索引扫描,与 ALL 类似,只不过扫描的是索引,而索引一般在内存中,速度更快。
- ALL:全表扫描
所有值的顺序从最优到最差排序为:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
-
possible_keys:可能被使用的索引
-
key:真实使用的索引
-
key_len:索引键长度,单位字节
-
ref:表示本行被操作对象的参考对象
-
rows:扫描的行数(估计值)
-
filtered:符合过滤条件数据的占比
-
Extra:重要的补充信息
- Using filesort :使用文件完成排序
- Using index:可直接在索引中获取需要的信息。若同时出现Using where表明索引还被用来过滤筛选;没有出现,表明只是用来了读取数据
- Using index condition:尝试只使用索引来获取数据,即能用索引就用
- Using index for group-by:使用索引优化GROUPBY或者DISTINCT操作,避免额外的磁盘操作
- Using temporary:用临时表存储中间结果,常用于 GROUP BY或者 ORDER BY操作
- Using where:使用了where条件
- Using join buffer (Block Nested Loop):连表查询的方式,表示当被驱动表没有使用索引的时候,MySQL 会先将驱动表读出来放到 join buffer 中,再遍历被驱动表与驱动表进行查询。
7 分库分表
分库分表方案是对关系型数据库数据存储和访问机制的一种补充。
分库:将一个库的数据拆分到多个相同的库中,访问的时候访问一个库
分表:把一个表的数据放到多个表中,操作对应的某个表就行
垂直拆分:
垂直拆分特点
1.每个库(表)的结构都不一样
2.每个库(表)的数据至少一列一样
3.每个库(表)的并集是全量数据
垂直拆分优缺点
优点:
1.拆分后业务清晰(专库专用按业务拆分)
2.数据维护简单,按业务不同,业务放到不同机器上
缺点:
1.如果单表的数据量,写读压力大
2.受某种业务决定,或者被限制,也就是说一个业务往往会影响到数据库的瓶颈(性能问题,如双十一抢购)
3.部分业务无法关联join,只能通过java程序接口去调用,提高了开发复杂度
库:
表:
水平拆分:
水平拆分的其他方式
range来分,每个库一段连续的数据,这个一般是按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了,优点:扩容的时候,就很容易,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了 缺点:大部分的 请求,都是访问最新的数据。实际生产用range,要看场景,你的用户不是仅仅访问最新的数据,而是均匀的访问现在的数据以及历史的数据
hash分发,优点:可以平均分配每个库的数据量和请求压力 缺点:扩容起来比较麻烦,会有一个数据迁移的这么一个过程
水平拆分特点
1.每个库(表)的结构都一样
2.每个库(表)的数据都不一样
3.每个库(表)的并集是全量数据
水平拆分优缺点
优点:
1.单库/单表的数据保持在一定量(减少),有助于性能提高
2.提高了系统的稳定性和负载能力
3.拆分表的结构相同,程序改造较少。
缺点:
1.数据的扩容很有难度维护量大
2.拆分规则很难抽象出来
3.分片事务的一致性问题部分业务无法关联join,只能通过java程序接口去调用
库:
表:
8 主从复制与读写分离
主从分离
主要涉及三个线程: binlog 线程、I/O 线程和 SQL 线程。
- binlog 线程 : 负责将主服务器上的数据更改写入二进制日志中。
- I/O 线程 : 负责从主服务器上读取二进制日志,并写入从服务器的中继日志中。
- SQL 线程 : 负责读取中继日志并重放其中的 SQL 语句。
- Master 主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
- 从库读取主库的二进制日志文件 Binlog ,写入到从库的中继日志 Relay Log 。
- slave重做(对这些日志重新执行)中继日志中的事件,从而使得从库和主库的数据保持同步。
复制方式:
1、异步复制
主库执行完提交事务后,立刻异步执行将结果返给给客户端,并不关心从库是否收到并处理。如果出现从库并未收到处理的情况,还是会有主从数据不一致的问题。期MySQL(5.5以前)仅仅支持异步复制。并且早期支持 myisam引擎。
2、半同步复制
主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到 relay log 中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟。
半同步复制的出现,就是为了保证在任何时刻主备数据一致的问题。相对于异步复制,半同步复制要求执行的每一个事务,都要求至少有一个备库成功接收后,才返回给用户。实现原理也很简单,主库本地执行完毕后,等待备库的响应消息(包含最新备库接收到的binlog(file,pos)),接收到备库响应消息后,再返回给用户,这样一个事务才算真正完成。在主库实例上,有一个专门的线程(ack_receiver)接收备库的响应消息,并以通知机制告知主库备库已经接收的日志,可以继续执行。
3、全同步复制
当主库提交事务之后,所有的从库节点必须收到、APPLY并且提交这些事务,然后主库线程才能继续做后续操作。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
读写分离
主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
读写分离能提高性能的原因在于:
- 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
- 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
- 增加冗余,提高可用性。
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
9 隔离级别和mvcc
隔离级别
- 序列化(SERIALIZABLE):如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供了事务之间最大限度的隔离。
- 可重复读(REPEATABLE READ):在可重复读在这一隔离级别上,事务不会被看成是一个序列。不过,当前正在执行事务的变化仍然不能被外部看到,也就是说,如果用户在另外一个事务中执行同条 SELECT 语句数次,结果总是相同的。(因为正在执行的事务所产生的数据变化不能被外部看到)。
- 提交读(READ COMMITTED):READ COMMITTED 隔离级别的安全性比 REPEATABLE READ 隔离级别的安全性要差。处于 READ COMMITTED 级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的多个 SELECT 语句可能返回不同的结果。
- 未提交读(READ UNCOMMITTED):READ UNCOMMITTED 提供了事务之间最小限度的隔离。除了容易产生虚幻的读操作和不能重复的读操作外,处于这个隔离级的事务可以读到其他事务还没有提交的数据,如果这个事务使用其他事务不提交的变化作为计算的基础,然后那些未提交的变化被它们的父事务撤销,这就导致了大量的数据变化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I3Tvv57Q-1668006561191)(C:\Users\mingqiu.qing\Desktop\image-20221106210331854.png)]
Mvcc
MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读
10 相关日志
https://blog.csdn.net/qq_34222160/article/details/124414775
bin log
redo log
undo log
想要保证事务的原子性,就需要在发生异常时,对已经执行的操作进行回滚,在MySQL中恢复机制是通过undo log(回滚日志)实现的,所有事务进行的修改都会先被记录到这个回滚日志,然后再执行其他相关的操作。如果执行过程中遇到异常的话,我们直接利用回滚日志中的信息将数据回滚到修改之前的样子。并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。
另外,MVCC的实现依赖:隐藏字段、Read View、undo log。在底层实现中,InnoDB通过数据行的DB_TRX_ID和Read View来判断数据的可见性,如不可见,则通过数据行DB_ROLL_PTR找到undo log中的历史版本。每个事务读到的数据版本可能是不一样的,在同一个事物里,用户只能看到该事务创建Read View之前已经提交的修改和该事务本身做的修改。
11 mysql的锁
https://blog.csdn.net/lgxzzz/article/details/122368203
11.1加锁的目的
对数据加锁是为了解决事务的隔离性问题,让事务之间相互不影响,每个事务进行操作的时候都必须先对数据加上一把锁,防止其他事务同时操作数据。
11.2锁基于什么实现
数据库里面的锁是基于索引实现的,在Innodb中我们的锁都是作用在索引上面的,当我们的SQL命中索引时,那么锁住的就是命中条件内的索引节点(行锁),如果没有命中索引的话,那我们锁的就是整个索引树(表锁),如下图一下锁住的是整棵树还是某几个节点,完全取决于你的条件是否有命中到对应的索引节点。
innodb索引结构图(B+ tree):
11.3锁的分类
数据库里有的锁有很多种,为了方面理解,所以我根据其相关性"人为"的对锁进行了一个分类,分别如下:
基于锁的属性分类:共享锁、排他锁。
基于锁的粒度分类:表锁、行锁(记录锁、间隙锁、临键锁)。
基于锁的状态分类:意向共享锁、意向排它锁。
11.3.1属性锁
共享锁(Share Lock)
共享锁又称读锁,简称S锁。当一个事务对数据加上读锁之后,其他事务只能对该数据加读锁,而无法对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加写锁。 加了共享锁之后,无法再加排它锁,这也就可以避免读取数据的时候会被其它事务修改,从而导致重复读问题。
排他锁(eXclusive Lock)
排他锁又称写锁,简称X锁;当一个事务对数据加上写锁之后,其他事务将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。加了排他锁之后,其它事务就无法再对数进行读取和修改,所以也就避免了脏写和脏读的问题。
11.3.2粒度锁
行锁
行锁是对所有行级别锁的一个统称,比如下面说的记录锁、间隙锁、临键锁都是属于行锁, 行锁是指加锁的时候锁住的是表的某一行或多行记录,多个事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问;
特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高;
记录锁(Record Lock)
记录锁属于行锁中的一种,记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。
**触发条件:**精准条件命中,并且命中索引;
**例如:**update user_info set name=’张三’ where id=1 ,这里的id是索引。
**记录锁的作用:**加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。
间隙锁(Gap Lock)
间隙锁属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间。
比如下面的表里面的数据ID 为 1,4,5,7,10 ,那么会形成以下几个间隙区间,-n-1区间,1-4区间,7-10区间,10-n区间 (-n代表负无穷大,n代表正无穷大)
**触发条件:**范围查询,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。
例如:对应上图的表执行select * from user_info where id>1 and id<4(这里的id是唯一索引) ,这个SQL查询不到对应的记录,那么此时会使用间隙锁。
间隙锁作用:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务里,A事务的两次查询出的结果会不一样。
临键锁(Next-Key Lock)
临键锁也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住,遵循左开右闭原则。
**例如:**下面表的数据执行 select * from user_info where id>1 and id<=13 for update ;
会锁住ID为5,10的记录;同时会锁住,1至5,5至10,10至15的区间。
**触发条件:**范围查询,条件命中了索引。
**临键锁的作用:**结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。
11.3.3状态锁
状态锁包括意向共享锁和意向排它锁,把他们区分为状态锁的一个核心逻辑,是因为这两个锁都是描述是否可以对某一个表进行加表锁的状态。
意向锁的解释:当一个事务试图对整个表进行加锁(共享锁或排它锁)之前,首先需要获得对应类型的意向锁(意向共享锁或意向共享锁)
意向共享锁: 当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁。
意向排他锁: 当一个事务试图对整个表进行加排它锁之前,首先需要获得这个表的意向排它锁。
存在意义:
如果当事务A加锁成功之后就设置一个状态告诉后面的人,已经有人对表里的行加了一个排他锁了,你们不能对整个表加共享锁或排它锁了,那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁,避免了对整个索引树的每个节点扫描是否加锁,而这个状态就是我们的意向锁。
12事务
12 mysql高可用架构
12.1 MMM 架构
属于公司早期的架构,不再新增。
- 数据库是主从架构
- 使用 3M moniter 和 agent 管理
- 连接方式使用 VIP 连接,支持读写分离
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkOQ5cnh-1668006561194)(C:\Users\mingqiu.qing\Desktop\image-20221106205935758.png)]
- monitor 节点负责数据库探活和切换
- agent主要完成 monitor 发出的切换操作
- 应用程序通过 VIP 连接(可能会出现将 VIP 切丢的情况)
11.2 QMHA 架构
- 数据库是主从架构
- 哨兵管理
- 连接方式使用 namespace,支持读写分离
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0tSrJHn-1668006561194)(C:\Users\mingqiu.qing\Desktop\image-20221106210002898.png)]
- 每一个 sentinel 都会监控集群中的所有 MySQL 节点
- sentinel 会相互通信,确认各个 MySQL 节点的状态
- 连接方式使用 namespace 连接
11.3 PXC 架构
- 是一种节点对等的,multi-master 架构
- 哨兵管理
- 连接方式使用 namespace,支持读写分离
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpk6eAxH-1668006561195)(C:\Users\mingqiu.qing\Desktop\image-20221106210023557.png)]
- 每一个 sentinel 都会监控集群中的所有 MySQL 节点
- sentinel 会相互通信,确认各个 MySQL 节点的状态
- 连接方式使用 namespace 连接
注意事项:
- 不要有大事务更新
- 不要做大查询,若 SQL 较慢会影响整个集群的性能
三种架构对比
3M | QMHA | PXC | |
---|---|---|---|
读写分离 | Y | Y | Y |
一致性 | 能保证一致性 | 半同步复制 | 强一致性 |
自动故障转移 | Y | Y | Y |
切换影响 | 会有短暂只读时间 | 会有短暂只读时间 | 切换几乎无感知 |
管理节点 | 单点 | 分布式 | 分布式 |