根据高并发、高可用MySQL视频进行整理
建议关掉MySQL5.6、5.7自带的缓存
mysql5.5.5之前默认的存储引擎,插入数据快。空间利用率高。因为采用B+树结构和不支持事务。
查询效率要求非常高的可考虑
MySQL5.5.5之后默认存储引擎、最主流
支持事务、外键
支持崩溃修复、并发控制
数据在内存、速度快、不安全
临时表
数据压缩、空间利用率高
插入快
查询差、不支持索引(磁带)
归档
表按照主键顺序组织存放
InnoDB表均为索引组织表,数据被主键的索引组织起来
主键:非空、最先申明唯一索引
索引算法:B+树
索引和数据放在一起了
叶子节点直接存放数据
按照主键构造B+树
叶子节点不包含行数据
默认所有数据存在共享表空间
最好挡在独占表空间(idb文件)
数据段:叶子节点
索引段:非叶子节点
大小为1M,64个page(节点)
InnoDB磁盘读写的最小逻辑单位,默认16kb
Trx id
回滚指针
数据
解决数据表某一字段存的数据太大,字段过长,退化为二叉树
将大的数据转移到blob页存,热表尽量不要存长字段
禁止将图片等大文件序列化成二进制数据存在数据库
Dynamic格式
可代替最左侧字段的单独索引
口头禅:带头大哥不能死,中间兄弟不能丢
如果字符串过长,可考虑使用前缀索引节约空间,如邮箱
如果前缀区分度太小,可考虑:
例:alter table user add index index2(email(6)) 以邮箱前六位建索引
或alter bable 表名 add key (列名(n))
使用模糊查询(like %关键字% 或 like %关键字)会使索引失效
使用左模糊(like 关键字%)可以使用索引
主键:唯一且非空
唯一索引:唯一
唯一约束插入性能开销大,慎用
对数据正确性实现约束,使用少
Default/NOT NULL
如果innodb_strict_mode开启了,设置非空生效,未开启不生效
插入修改时校验数据
干扰业务,使用少
视图算法:
将视图sql合并到主查询sql,用一个sql查询,性能更高
将视图当作一张临时表处理
查询语句从执行到返回均使用同一索引,不用回表,如查询联合索引的字段
查看建表语句:show create table 表名;
查看表结构:desc +表名;
查看索引:show index from 表名; cardinality 基数,代表索引可能性
查看执行计划:explain + 查询语句;
执行计划中extra代表是否索引覆盖,possible_keys 代表使用的索引
analyze table 重新统计索引信息,修复基数估计错误
force index 强制使用某条索引
count(非索引字段)效率低,需要逐条扫描,判断是否为空
count(索引字段)、count(主键)、count(1)都需要提交给server层判断是否为null
最佳办法:使用count(*)
在MyISAM中,count(*)能直接返回数据库中记录的数据表行数,在InnoDB中数据库不记录,但MySQL专门优化了count(*)直接返回索引树中数据个数!
排序缓存:sort_bufffer
优化排序查询时间,适当增大sort_buffer_size,使中间表(where查出来的数据)尽可能放在内存中运行
加了order by,前面的where语句相当于查的中间表,是不能走索引的!
排序阈值:max_length_for_sort_data 大于阈值时,只生成排序字段+主键的中间表,然后回表查出所有数据
最高效:使用索引覆盖
当筛选字段和排序字段全在一条索引中可用
select film_id,title from film order by title;
--title字段加了索引
rand()生成0-1的随机数
order by rand() 随机排序输出
下面语句存在性能问题:
select title,description from film order by rand() limit 1;
步骤:
1.创建一个临时表,临时表的字段为rand、title、description_
2.从表中取出一行,调用RAND(),将结果和数据放入临时表,以此类推
3.针对临时表,将rand字段+行位置(主键)放入sort buffer
4.对sort_buffer排序,取出第一个的行位置(主键),查询临时表
发现只查询一条数据,确创了两个临时表,进行了排序
优化:
临时方案:
select max(film_id), min(film_id) into @M,@N from film;
set @X = floor((@M - @N + 1) * rand() + @N);
select title, description from film where film_id >= @X limit 1;
业务方案:
查询数据表总数total
total范围内,随机选取一个数字r
执行以下SQL(从第r个开始选一个,分页方式):
select title, description from film limit r,1;
在MySQL5.6及以后自带,不需要手动开启
指的是在查询辅助索引或联合索引时,查询第二个字段,不用再回表查询
SELECT * FROM inventory WHERE store_id in (1,2) and film_id=3;
其中,(store_id,film_id)为联合索引
extra:using index condition
SELECT film from inventor WHERE film_id = 3;
MySQL8.0新特性
可以不管带头大哥
1.对索引字段做函数操作,优化器会放弃索引
如month()
2.字符串与数字比较
3.隐式字符编码转换,utf8会隐式转换为utf8mb4,不同编码表联表时,需要高级转低级
原语句:
SELECT film_id,title,description FROM film ORDER BY title LIMIT 900,10;
虽然有title索引,但要查询description时回表前还要全表排序,相当于没走索引,性能下降
可以再加一个(title,description)的联合索引,如果不能加,使用下面优化方案
优化后:
SELECT f.film_id, f.title, f.description FROM film f
INNER JOIN (SELECT film_id FROM film ORDER BY title LIMIT 900,10) m
ON f.film__id = m.film_id;
归档日志:server层产生的逻辑日志
进行数据复制和数据传送
数据闪回手段
重做日志:InnoDB产生的物理日志,保证持久化
数据页的变化、日志优先于数据
内存数据更新后写redo log,写入硬盘后删除
回滚日志:InnoDB产生的逻辑日志,保证隔离性、原子性
事务回滚和展示历史版本
数据缓存更新
执行更新时,顺序一般是undo log -> redo log -> binlog
因为一旦提交了binlog十五就相当于提交了,MySQL实行日志有限,日志刷盘,数据就不会丢,为了数据安全,一般吧redo log和binlog的刷盘设为1。
粒度分:全局锁(整库无法修改)、表级锁、行锁
Flush Table with read lock
整库只读
一般用来备库备份
lock tables 表名 read/write
使用少
元数据指表结构、字段、数据类型、索引等
事务访问一般要加上,MDL读锁
事务修改加MDL写锁
读锁/写锁=共享锁/排他锁=共享锁/独占锁=S锁/X锁
S锁:自己要读,不让被人写
X锁:自己要写,不让别人读写
S锁和S锁兼容外,其他均不兼容
ACID
原子性【两阶段提交+undo log保证】、一致性【锁+两阶段提交】、隔离性【并发事务隔离,锁+undo log保证】、持久性【redo log】
隔离性有四种级别:读未提交、都提交、可重复读、串行化
格式:
开启:
> begin;
sql语句……
回滚:
> rollback;
提交:
> commit;
查询隔离级别:
> select @@tx_isolation;
读写都不加锁、不隔离
很少采用
set session transaction isolation level read uncommitted;
read committed
Oracle默认级别
提交前会加X锁
repeatable read
MySQL默认
读取本事务开始时的状态,写数据加X锁
必须两边事务都提交,再次开启事务才能看到改的数据
serializable
读加S锁,写加X锁
很少用
读到未提交的数据
两次查询数据不一样
两次查询读到数据条目数不一致
MySQL在可重复读级别,通过Next-Key锁解决了幻读问题,即【行锁+间隙锁】
行锁+间隙锁
目的:在可重复读的级别下部分预防幻读
一旦锁,将锁上 前一个间隙和当前行
主键等值查询只加行锁
非唯一索引等值查询间隙+行锁
非索引字段,锁全表
注意:当前读时,不要查询没有索引的项目
1.正确调配硬盘参数
使用fio工具查看服务器IOPS
innodb_io_capacity
2.合理配置脏页比例上限
innodb_max_dirty_pages_pct
3.控制“顺便刷脏”策略
innodb_flush_neighbors
SSD建议设为0,MySQL8.0已默认
查看长事务:information_schema库中innodb_trx表
查看锁:information_schema库中innodb_locks表
查看阻塞的事务:information_schema库中innodb_lock_waits表
MySQL8.0:
查看锁:performance_schema库中的data_locks表
查看锁等待:performance_schema库中的data_lock_waits表
查看MDL锁:performance_schema库中的metadata_locks表
没有必要最好不要开启事务
可以调整锁超时时间、死锁检测等参数
业务上尽量将加锁(更新)的操作后移,降低锁时间,先进行快照读【只加元数据锁,没有行锁】
Object Relational Mapping
对象和关系型数据库的映射
如Java的mybadis
接口层
处理层
支撑层
连接层
热备(Hot Backup):正常运行时备份
冷备(Cold Backup):数据库停掉后备份
温备(Warm Backup):数据库只读
mysqldump:逻辑、热、全量备份
xtrabackup:物理、热、全量+增量备份
原生备份指令
查看导出文件安全目录:show variables like ‘%secure%’;
命令:
select * into outfile '/var……/导出文件名' from 表名
//数据以,分隔结尾
select * into outfile '/var……/导出文件名' fields terminated by ',' from 表名
不能还原,很少用
原理:select SQL_NO_CATCH from 表名;不用缓存
–single-transaction:包含事务,在RR级别下进行(InnoDB)
–lock-all-table:使用FTWRL锁全表(MyISAM)
–lock-tables:使用READ LOCAL锁当前库的表(MyISAM)
–all_databases:备份所有库
命令:
全库备份
mysqldump -uroot -p123 --databases 数据库名 --single-transaction > 文件名.sql;
采用mysqldump全量备份+binlog增量备份
–flush-logs:备份后切换binlog文件
–master-data = 2:记录切换后的binlog文件名
步骤一:mysqldump全备
mysqldump -uroot -p123 --databases 数据库名 --single-transaction --flush-logs --master-data = 2> 文件名.sql;
步骤二:切换增量备份
mysqladmin -uroot -p123 flush-logs
步骤三:还原
先还原全量备份的sql
source 文件名.sql;
再将binlog增量还原
mysqlbinlog MySQL-bin.000002...|mysql -uroot -p123
现名:MySQL Enterprise Backup ,InnoDB官方出品
收费,所以才有开源的XtraBackup
物理备份,Percona公司开发
直接备份InnoDb底层数据文件
全量热备:备份idb文件+备份期间的redo log
1启动redo log监听线程,开始收集redo log
2拷贝ibd数据文件
3停止收集redo log
4加FTWRL锁拷贝元数据frm
增量热备:根据每个页的LSN号
XtraBackup 8.0 ->mysql 8.0
XtraBackup 2.4 ->mysql 5.1-5.7
时间非常快
全备命令:
数据备份:
innobackupex --user=root --password=123 存放文件夹/
数据还原(要停掉mysqld):
innobackupex --copy-back 存放文件夹/日期文件夹/
增量备份:
增量备份:
innobackupex --user=root --password=123 --incremental 存放文件夹/ --incremental-basedir='全备存放文件夹/日期文件夹/'
增量备份合并至全量备份
innobackupex --apply-log 全备存放文件夹/日期文件夹/ --incremental-dir=存放文件夹/新日期文件夹/
数据还原(要停掉mysqld):
innobackupex --copy-back 存放文件夹/日期文件夹/
利用逻辑卷管理器,直接备份磁盘数据
实现多线程并发备份还原,速度更快
图形化,备份恢复管理工具
集成多种备份工具
集成binlog日志分析功能
sql审计工具:Inception
伪删表:删表前先把表加一个特殊后缀改名,观察业务是否影响,无误后使用脚本删除
高并发、高可用、高性能
复制
扩展
切换
高并发:通过复制和拓展,将数据分散至多节点
高性能:复制提升速度,拓展提升容量
高可用:节点间身份切换保证随时可用
binlog->relay log
异步复制
半同步复制
组复制
主从复制(异步)步骤:
第一步,打开主从数据库服务器的binlog
vim /etc/my.cnf
进入配置:
log-bin=/var/lib/mysql/mysql-bin
server-id=123456
改完之后,重启mysqld(冷知识:mysql是MySQL客户端,mysqld才是MySQL数据库)
systemctl restart mysqld
第二步:主库上全局锁
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS \G;//查看主库写到哪个binlog文件了
第三步:备份主库所有数据
mysqldump -uroot -p123 --all-databases --master-data > dbdump.sql
第四步:使用scp等方式将备份文件传到从库
scp dbdump.sql [email protected]:/root/dbdump.sql
解掉主库全局读锁
mysql> UNLOCK TABLES;
第五步:从库执行SQL文件
mysql> source /root/dbdump.sql;
mysql> show slave status \G;//查看从库状态
如果从库已配置好了主从,先停掉,再重设主备
mysql> stop slave;
mysql> reset slave;
第六步:从库设置备份主库
mysql> change master to MASTER_HOST='主机IP',MASTER_USER='root',MATSER_LOG_FILE='mysql-bin.0000?',MASTER_LOG_POS=?;
mysql> start slave;
备库最好要加上只读
事务的全局唯一id:GTID
MySQL5.6开始引入
GTID=server_uuid:gno
即由节点的id+事务流水号组成
启用GTID:gtid_mode=on;enforce_gtid_consistency=on;
-- 主从都打开配置文件
vim /etc/my.cnf
-- 加两行
gtid_mode=on
enforce_gtid_consistency=on
-- 保存重启mysqld
-- 从库重新设置备份主库
mysql> stop slave;
mysql> change master to MASTER_HOST='主机IP',MASTER_USER='root',MASTER_POSSWORD='123',master_auto_position=1;
mysql> start slave;
statement格式:MySQL5.0之前,基于语句的复制
可能会出现如果两个库索引不同,导致同一条语句(如删除数据)执行结果不同
ROW格式:不记录sql原文,记录数据行的变化,占空间大,使用最广,基于行的复制
mixed格式:有数据风险的使用ROW,没风险的使用statement,
mysql> set binlog_format=ROW;
重放中继日志耗时
方案:
MySQL5.6开始按库并行
配置文件加上:slave-parallel-type = DATABASE
MySQL5.7按照事务组并行
binlog_group_commit_sync_delay:延迟多少微秒调用fsync,保存binlog
binlog_group_commit_sync_no_delay_count:累计多少次以后调用fsync
配置文件加上:slave-parallel-type = LOGICAL_CLOCK
MySQL5.7.22
多了个binlog-transaction-dependency-tracking参数:
commit_order:按事务组并行,和5.7一样
writeset:没有修改像同行的事务并行
writeset_session:同一线程先后执行的两个事务不能并行
强制延时
seconds_behind_master = 0
对比binlog执行位点
对比GTID执行情况
配置步骤:
-- 如果已经配置好了主从复制,很简单,只需要再在主库设置备份从库即可
-- 主库操作
mysql> stop slave;
mysql> change master to MASTER_HOST='从库IP',MASTER_USER='root',MASTER_POSSWORD='123',master_auto_position=1;
mysql> start s
-- 根据时间范围将t表分成4张InnoDB表,但在server层和客户端看来,还是一张表
-- INDEX DIRECTORY、DATA DIRECTORY指定数据存放在哪个位置
CREATE TABLE t (
ftime datetime NOT NULL,
cint (11) DEFAULT NULL,
KEY (ftime)
) ENGINE = InnoDB DEFAULT CHARSET = latin1
PARTITION BY RANGE (YEAR(ftime))(
PARTITION p_2030
VALUES
LESS THAN (2030) ENGINE = InnoDB,
INDEX DIRECTORY ='/data1',
DATA DIRECTORY = '/data2',
PARTITION p_2031
VALUES
LESS THAN (2031) ENGINE = InnoDB,
PARTITION p_2032
VALUES
LESS THAN (2032) ENGINE = InnoDB,
PARTITION p_others
VALUES
LESS THAN MAXVALUE ENGINE = InnoDB
);
分区方式:
缺点:一次访问需要打开所有的idb文件,共用MDL锁
垂直分表:按照字段分
水平分表:按行分,类似分区表,但server层也分了
垂直分库:数据表被分到不同库
水平分库:按行分表
优点:
缺点:
针对缺点处理方式:
基于开源项目MyCat
schema:虚拟数据库(不同于传统的schema)
shardingTable :虚拟表(被拆分的表)
shardingNode :虚拟节点
dbGroup :实际的MySQL集群
database :实际的database
只支持水平拆分
安装
第一步:先装java
配置Java环境变量:cd /usr/lib/jvm/jre……
vim ~/.bashrc
export JAVA HOME-/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el79.x8664
export PATHE$PATH:$JAVA HOME/bin
回到home文件夹 cd ~
第二步:下载dble
下载解压到var/lib下
cd var/lib/dble
cd conf
mv cluster_template.cnf cluster.cnf
mv bootstrap_template.cnf bootstrap.cnf
配置dble主配置文件
vim db_template.xml
更改url、user、pwd
mv db_template.xml db.xml
配置外部连接数据库用户密码
vim user_template.xml
mv user_template.xml user.xml
mv sharding_template.xml sharding.xml
第三步:启动dble
cd ..
bin/dble start
第四步:使用dble设置的用户名密码连接dble管理
mysql -h'127.0.0.1' -uman1 -P9066 -p654321
mysql> create database @@shardingnode='dn$1-6';
db.xml里面
rwSplitMode=0:直接分发到主实例
rwSplitMode=1:读操作必须在所有从实例中均衡
rwSplitMode=2:读操作在所有实例中均衡
rwSplitMode-3:读操作尽量在所有从实例中均衡
查询语句尽可能带拆分字段
插入语句必须带有拆分字段
拆分字段尽量等值(最好不要用范围查询,缩减in子句值的数量)
减少表的搜索遍历(尽量少出现distinct、group by、order by)
减少结果集
跨节点连表(常join的表按照相同拆分规则,使用连表字段作为拆分字段)
有一段时间两个库均不可写
但可能会造成数据不一致:B可能还没有写完中继日志,被强行变更为主库去写
使用keepalived漂移、代理等
Master High Availability
支持GTID
不能自动漂移VIP
步骤:
安装MHA
第一步:先配置主从
第二步:从库装上MHA manager,主从库装上node
第三步: 设置所有机器免密登录
vim /etc/ssh/sshd_config
修改两行:PermitRootLogin、PubkeyAuthentication
从库:
vim /etc/mha.cnf
免密检查:materha_check_ssh --conf=/etc/mha.cnf
主备复制检查:masterha_check_repl --conf=/etc/mha.cnf
MHA工作状态检查:masterha_check_status --conf=/etc/mha.cnf
第三步:启动MHA
从库启动
masterha_manager --conf=/etc/mha.cnf &
查看日志
tail -f /var/log/masterha/app1/app1.log
第四步:测试主库宕机
systemctl stop mysqld
代价高
方便维护
也叫DRDS架构:分布式关系数据库服务
其实就是MySQL5.8
SELECT
*,
rank() over (
PARTITION BY customer_id
ORDER BY
amount desc
) AS ranking
FROM payment;
建索引时加上 invisible/visible
用来测试索引
CREATE INDEX idx1 ON payment (payment date desc);
CTE可看作一个临时试图
可以在复杂语句中反复使用中间结果
WITH
cte1 AS (SELECT a, b FROM tablel),
cte2 AS (SELECT C, d FROM table2)
SELECT b, d
FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;
使用utf8mb4作为默认字符集
元数据操作可以回滚
在线事务交易/处理系统
并发量大
MySQL/PostgreSQL
在线分析处理系统
语句复杂,数据量大
Hive/SparkSQL/GreenPlum
混合事务/分析处理
单体数据库最强
自带分库分表中间件:Postgres-XL(OLTP ) 、GreenPlum(OLAP)【高性能sql优化器GPORCA】
阿里研发
共享存储
将三种log简化为redo log
阿里
国产公认最好的开源数据库
2015年启动,由谷歌前员工发起
完全开源
分布式shared-nothing架构
兼容Postgrest协议