MySQL-DBA课程-Day07

上节回顾

  1. 索引类型
    BTREE : b-tree , b+tree , b*tree
    RTREE
    FULLTExT
    HASH

  2. 聚簇索引和辅助索引区别和联系
    区别:

    1. 一般选择主键生成聚簇索引,一张表只能一个 ,没有主键选择唯一键,都没有选择隐藏rowid,自动生成隐藏聚簇索引.
    2. 聚簇索引叶子节点,存储的是整行的表数据.枝节点和根节点,叶子节点ID值的范围.
    3. 辅助索引,可以有多个.
    4. 辅助索引,叶子节点,存储的是索引列值+主键.

关系:
执行查询时,select * from t1 where name='bgx';
1. 首先根据name的索引,快速锁定bgx的主键ID
2. 根据ID列值回表查询聚簇索引,获取整行.

  1. 管理
show  index from city;
alter table city add index idx_name(name);
alter table city add index idx_a_b_c(a,b,c);
alter table city add index idx_a(a(10));
alter table city add unique index idx_a(a(10));
alter table city drop index idx_name;   
  1. explain / desc
    type : ALL index range ref eq_ref const(system) NULL

key_len
联合索引应用"道道" *****
-- 建立联合索引时,最左侧列,选择重复值最少的列.
alter table keyt add index idx(a,b,c);
-- 例子:
-- 哪些情况可以完美应用以上索引.
desc select *from student where xname='张三' and xage=11 and xgender='m';
desc select *from student where xage=11 and xgender='m' and xname='张三' ;
desc select *from student where xgender='m' and xname='张三' and xage=11 ;
-- 影响到联合索引应用长度的.
-- 缺失 联合索引最左列,不走任何索引
mysql> desc select *from student where xage=11 and xgender='m' ;
-- 缺失中间部分,只能走丢失部分之前的索引部分
mysql> desc select *from student where xname ='张三' and xgender='m' ;
-- 查询条件中,出现不等值查询(> ,< ...like )
mysql> desc select *from student where xname ='张三' xage<18 and xgender='m' ;
联合索引应用长度到不等值列截断了.
-- 多子句
按照 select 子句顺序创建联合索引.

mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='780P'" engine=innodb --number-of-queries=2000 -uroot -p123 -verbose

===========================================================
索引续集

  1. 索引应用规范
    1.1 创建索引的条件
    (1) 必须要有主键,建议是自增长的ID列
    (2) 经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)
    (3) 唯一值多的列作为联合索引最左列.
    (4) 列值长度较长的索引列,我们建议使用前缀索引.
    (5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit(xxxxx)
    (6) 索引维护要避开业务繁忙期
    (7) 经常更新的列不要建索引

1.2 开发规范
(1) 没有查询条件,或者查询条件没有建立索引

mysql> desc select * from city; 
mysql> desc select * from city where true;
mysql> desc select * from city where 1=1;
mysql> desc select * from city where name='jinan';
mysql> desc select *from student where xage=11 and xgender='m'  ;

(2) 查询结果集是原表中的大部分数据,应该是20-30%以上。
1000w 200w-300w ----> 有可能导致索引失效.
解决方案: 给范围查询增加上限和下限

(3) 索引本身失效,统计数据不真实,更新不及时
前几天运行的很快,突然有一天慢了.
desc select * from city where name='jinan';
解决方案:

    1. 手工触发更新统计信息
      ANALYZE TABLE city;
      optimize table city;
    1. 重建索引

(4) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)
mysql> desc select * from city where id-1=9;

(5) 隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误.
mysql> desc select * from tab where telnum='110';

(6) <> ,not in 不走索引(辅助索引)
(7) like "%_" 百分号在最前面不走
(8) 联合索引规范
联合索引(a,b,c) ----> bc ---> c 不走任何索引
联合索引(a,b,c) ----> ac 只能走部分
联合索引(a,b,c) 中间出现不等值(> < like)

  1. 扩展
    2.1 AHI 自适应hash索引
    mysql> select @@innodb_adaptive_hash_index;
    Adaptive Hash Indexes 原理
    InnoDB存储引擎会监控对二级索引的查找,如果发现某一个二级索引被频繁访问,二级索引成为一个热数据。那么此时建立hash索引可以带来速度的提升 经常访问的二级索引数据会自动被生成到hash索引里面去(最近连续被访问三次的数据),自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。而且不需要将整个表都建哈希索引,InnoDB存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。
    查看使用状况:
    show engine innodb status ;
    可以通过观察show engine innodb status结果中的SEMAPHORES部分来决定是否使用自适应哈希索引。如果你看到很多线程都在btr0sea.c文件上创建rw-latch上waiting,那么建议关闭掉自适应哈希索引。高并发模式下AHI引起的竞争,需要关闭AHI.

设置参数
innodb_adaptive_hash_index=on/off

2.2 MySQL Insert Buffer技术
插入缓冲技术,对于非聚集类索引的插入和更新操作,不是每一次都直接插入到索引页中,而是先插入到内存中。具体做法是:如果该索引页在缓冲池中,直接插入;否则,先将其放入插入缓冲区中,再以一定的频率和索引页合并,这时,就可以将同一个索引页中的多个插入合并到一个IO操作中,大大提高写性能。
这个设计思路和HBase中的LSM树有相似之处,都是通过先在内存中修改,到达一定量后,再和磁盘中的数据合并,目的都是为了提高写性能
那么插入缓冲如何减少随机IO的呢?每个一段时间,insert buffer会去合并在insert buffer中的二级非唯一索引。通常情况下,它会合并N个修改到同一个btree索引的索引页中,从而节约了很多IO操作。经测试,insert buffer可以提高15倍的插入速度。
在事务提交后,insert buffer可能还在合并写入。所以,假如当DB异常重启,reovery阶段,当有非常多的二级索引需要更新或插入时,insert buffer将可能花费很长时间,甚至几个小时。在这个阶段,磁盘IO将会增加,那么就会导致IO-Bound类型的查询有显著的性能下滑。

2.3 Index Condition Pushdown (ICP)
mysql使用索引从表中检索行数据的一种优化方式,MySQL5.6开始支持
MySQL 5.6之前,存储引擎会通过遍历索引定位基表中的行,然后返回给Server层,再去为这些数据行进行WHERE后的条件的过滤。
mysql 5.6之后支持ICP后,如果WHERE条件可以使用索引
MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索引过滤,把满足的行从表中读取出。
ICP能减少引擎层访问基表的次数和 Server层访问存储引擎的次数。

联合索引(a,b,c) ----> ac 只能走部分
没有ICP
a ---> 从磁盘拿满足a条件的数据 加载到内存 ,再C过滤想要的结果 =====> SQL层 --->
有ICP
a ----> a + c =====> SQL 层

mysql> SET @@optimizer_switch='index_condition_pushdown=on
mysql> show variables like 'optimizer_switch%' \G
*************************** 1. row ***************************

Variable_name: optimizer_switch
Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,subquery_materialization_cost_based=on,use_index_extensions=on

2.4 MRR 的全称是 Multi-Range Read
Optimization,是优化器将随机 IO 转化为顺序 IO 以降低查询过程中IO开销的一种手段,这对IO-bound类型的SQL语句性能带来极大的提升,适用于range ref eq_ref类型的查询
MRR优化的几个好处
使数据访问有随机变为顺序,查询辅助索引是,首先把查询结果按照主键进行排序,按照主键的顺序进行书签查找
减少缓冲池中页被替换的次数
批量处理对键值的操作

mysql> SET @@optimizer_switch='mrr=on,mrr_cost_based=off';
mysql> show variables like 'optimizer_switch%' \G
*************************** 1. row ***************************

Variable_name: optimizer_switch
        Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=off,block_nested_loop=on,batched_key_access=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on,subquery_materialization_cost_based=on,use_index_extensions=on
1 row in set (0.00 sec)

2.5 针对多表连接查询
Simple Nested Loops Join(SNL),简单嵌套循环算法
Index Nested Loops Join(INL),索引嵌套循环连接​​​​
Block Nested Loops Join(BNL),块嵌套循环连接
Batched Key Access join(BKA) , BNL+MRR
说明:

  1. batched_key_access=on
  2. mrr必须开启 ,mrr=on,mrr_cost_based=off
  3. 被驱动表,关联列必须有索引.

作用:

  1. 减少了 Nested Loops 次数
  2. 将扫描非驱动表时,可以将大量的随机IO转变为顺序IO

A
id name age
1 zs 12
2 l4 13
3 w5 14

B
id addr telnum
1 bj 110
2 sh 120
3 tj 119

select name,age,telnum
from a join b
on A.id=b.id
where name like '张%'

提高表join性能的算法。当被join的表能够使用索引时,就先排好顺序,然后再去检索被join的表,听起来和MRR类似,实际上MRR也可以想象成二级索引和 primary key的join
如果被Join的表上没有索引,则使用老版本的BNL策略(BLOCK Nested-loop)

SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

mysql> show variables like 'optimizer_switch%' \G
*************************** 1. row ***************************

Variable_name: optimizer_switch
        Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on, ,block_nested_loop=on,batched_key_access=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on,subquery_materialization_cost_based=on,use_index_extensions=on
1 row in set (0.00 sec)

===============================================

第五章节 存储引擎
1. 存储引擎介绍
相当于Linux 文件系统.组织存储表数据.
2. 存储引擎的种类
show engines;
InnoDB
MyISAM
CSV
Memory

其他的存储引擎:
MariaDB : InnoDB,TokuDB ,Myrocks
percona : xtradb ,TokuDB ,Myrocks

TokuDB ,Myrocks : 比较适合于在写入操作较多的场景,数据量级大的场景.
原因是: 插入性能很高, 压缩比较高.
监控类的业务.

学员案例:
环境: zabbix 3.x mariaDB 5.5 centos 7.3
现象 : zabbix卡的要死 , 每隔3-4个月,都要重新搭建一遍zabbix,存储空间经常爆满.
问题 :

  1. zabbix 版本
  2. 数据库版本 ---> 5.5 ----> ibdata1 ----> 5.7 ,8.0
  3. zabbix数据库500G,存在一个文件里

优化建议:
1.数据库版本升级到Mairia 10.x版本,zabbix升级更高版本
2.存储引擎改为tokudb
3.监控数据按月份进行切割(二次开发:zabbix 数据保留机制功能重写,数据库分表)
4.关闭binlog和双1 等安全参数需要关闭
5.参数调整....
优化结果:
监控状态良好
select concat("alter table zabbix.",table_name," engine=tokudb") from information_schema.tables
where table_schema='zabbix';

为什么?
1.原生态支持TokuDB,另外经过测试环境,10.x要比5.5 版本性能 高 2-3倍
2.TokuDB:insert数据比Innodb快的多,数据压缩比要Innodb高
3.监控数据按月份进行切割,为了能够truncate每个归档表,立即释放空间
4.关闭binlog ----->减少无关日志的记录.
5.参数调整...----->安全性参数关闭,提高性能.
3.InnoDB存储引擎的核心特性
==================================================
面试题:
(1) InnoDB存储引擎的特性
(2) InnoDB和MyISAM的区别
==================================================
MVCC 多版本并发控制
聚簇索引 PK
事务
行级锁 MyISAM支持表锁
外键 FK
复制支持高级特性: GTID等高级复制
自适应hash索引
支持热备,MyISAM支持温备份
ACSR(自动故障恢复)
4. 存储引擎的操作
4.1 查看存储引擎

mysql> show engines;
mysql> select @@default_storage_engine;
mysql> create table mt (id int) engine=myisam;
mysql> create table et (id int) engine=innodb;

查询所有非INNODB的表 , 并且提出修改建议

mysql> SELECT 
    -> table_schema,
    -> table_name ,
    -> ENGINE ,
    -> CONCAT("alter table ",table_schema,".",table_name," engine=innodb;") AS "修改建议"
    -> FROM information_schema.tables
    -> WHERE table_schema NOT IN ('sys','information_schema','performance_schema','mysql')
    -> AND ENGINE <> 'innodb';
+--------------+------------+--------+--------------------------------------+
| table_schema | table_name | ENGINE | 修改建议                             |
+--------------+------------+--------+--------------------------------------+
| test         | mt         | MyISAM | alter table test.mt engine=innodb;   |
| test         | test       | MyISAM | alter table test.test engine=innodb; |
+--------------+------------+--------+--------------------------------------+
2 rows in set (0.01 sec)

4.2 修改表的存储引擎
alter table test.test engine=innodb;
扩展: 碎片问题解决.
由于业务中有大量的delete操作,产生了大量的碎片.
(1) 表数据逻辑导出,删除原表,重新导入.
(2) mysql> alter table test.test engine=innodb;

小项目:
环境:centos7.4,MySQL 5.7.20,InnoDB存储引擎
业务特点:数据量级较大,经常需要按月删除历史数据.
问题:磁盘空间占用很大,不释放
处理方法:
以前:将数据逻辑导出,手工truncate表,然后导入进去
现在:
对表进行按月进行归档表
业务替换为truncate方式
=============================================
学员案例:
环境: zabbix 3.x mariaDB 5.5 centos 7.3
现象 : zabbix卡的要死 , 每隔3-4个月,都要重新搭建一遍zabbix,存储空间经常爆满.
问题 :

  1. zabbix 版本
  2. 数据库版本 ---> 5.5 ----> ibdata1 ----> 5.7 ,8.0
  3. zabbix数据库500G,存在一个文件里

优化建议:
1.数据库版本升级到Mairia 10.x版本,zabbix升级更高版本
2.存储引擎改为tokudb
3.监控数据按月份进行切割(二次开发:zabbix 数据保留机制功能重写,数据库分表)
4.关闭binlog和双1 等安全参数需要关闭
5.参数调整....
优化结果:
监控状态良好

select concat("alter table zabbix.",table_name," engine=tokudb") from information_schema.tables where table_schema='zabbix';

为什么?
1.原生态支持TokuDB,另外经过测试环境,10.x要比5.5 版本性能 高 2-3倍
2.TokuDB:insert数据比Innodb快的多,数据压缩比要Innodb高
3.监控数据按月份进行切割,为了能够truncate每个归档表,立即释放空间
4.关闭binlog ----->减少无关日志的记录.
5.参数调整...----->安全性参数关闭,提高性能.
==================================================
实施过程:

1.部署 Mariadb 环境 10.1
(1) 上传解压

[root@zabbix-server local]# tar xf mariadb-10.2.30-linux-glibc_214-x86_64.tar.gz 
[root@zabbix-server mariadb]# ln -s mariadb-10.2.30-linux-glibc_214-x86_64 mariadb
[root@zabbix-server mariadb]# chown -R mysql.mysql /usr/local/mariadb
[root@zabbix-server mariadb]# mkdir -p /data/mysql/data
[root@zabbix-server mariadb]# chown -R mysql.mysql data
[root@zabbix-server mariadb]# mv /etc/my.cnf /etc/my.cnf.bak

(2) 备份原数据库zabbix数据
mysqldump -B zabbix > /tmp/zabbix.sql

(3) 停源库 ,启新库

[root@zabbix-server local]# systemctl stop mariadb
/usr/local/mariadb/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mariadb --datadir=/data/mysql/data
[root@zabbix-server data]# cd /usr/local/mariadb/support-files/
[root@zabbix-server support-files]# cp mysql.server /etc/init.d/mysqld 
[root@zabbix-server support-files]# chkconfig --add mysqld

====未完待续(翻车现场.....)

==============================================
5. InnoDB存储引擎物理存储结构
5.1 表空间(tablespace) ***
(1) MySQL5.5版本出现了共享表空间模式(移植了Oracle)
实现了较为方便的扩容功能,但是所有的表数据都集中在几个文件中,管理十分不方便.
(2) MySQL 5.6中 ,默认使用独立表空间模式实现数据的存储.
保留了共享表空间,只用来存储系统相关数据(数据字典+undo+tmp表空间)
把用户表数据和索引单独存储(独立表空间)
(3) MySQL 5.7
保留了共享表空间ibdata1,只用来存储系统相关数据(数据字典+undo),undo在5.7 手工配置将他独立出来=
(4) MySQL 8.0
保留了共享表空间ibdata1,只用来存储系统相关数据(dw,cb)
undo自动独立出来,移除了数据字典的存储.

5.2 表空间管理
查看表空间模式:
mysql> select @@innodb_file_per_table;
共享表空间的设置:
mysql> select @@innodb_data_file_path; ibdata1:332M;ibdata2:128M:autoextend

一般情况下: 安装MySQL ,提前设置好
mysqld --initialize-insecure ....
my.cnf
ibdata1:512M:ibdata2:512M:autoextend

5.3 表的物理存储介绍
t1表:
ibd : 数据行

frm : 数据字典部分信息(列,列属性)
ibdata1 : 整个数据库的数据字典(所有表的列信息,列属性....),undo
ib_logfileN : redo事务日志

5.4 表空间迁移(快速迁移部分表数据)
(1) 准备一个新环境
(2) 创建和原表结构一样的表
show create table t1 ;
create ....
(3) 删除空表的ibd表空间文件
alter table t1 discard tablespace;
(4) cp 原表的ibd表空间到新环境
[root@db01 test]# cp -a t1.ibd /data/mysql/data_3307/db1
(5) 导入表空间文件.
alter table t1 import tablespace;

5.5 学员的项目
案例背景:
硬件及软件环境:
联想服务器(IBM)
磁盘500G 没有raid
centos 6.8
mysql 5.6.33 innodb引擎 独立表空间

备份没有,日志也没开

开发用户专用库:
jira(bug追踪) 、 confluence(内部知识库) ------>LNMT
故障描述:
断电了,启动完成后“/” 只读
fsck 重启,系统成功启动,mysql启动不了。
结果:confulence库在 , jira库不见了

学员求助内容:
求助:
这种情况怎么恢复?
我问:
有备份没
求助:
连二进制日志都没有,没有备份,没有主从
我说:
没招了,jira需要硬盘恢复了。
求助:
1、jira问题拉倒中关村了
2、能不能暂时把confulence库先打开用着

将生产库confulence,拷贝到1:1虚拟机上/var/lib/mysql,直接访问时访问不了的

问:有没有工具能直接读取ibd
我说:我查查,最后发现没有

我想出一个办法来:
表空间迁移:

create table xxx
alter table  confulence.t1 discard tablespace;
alter table confulence.t1 import tablespace;

虚拟机测试可行。

处理问题思路:
confulence库中一共有107张表。

1、创建107和和原来一模一样的表。
他有2016年的历史库,我让他去他同时电脑上 mysqldump备份confulence库
mysqldump -uroot -ppassw0rd -B confulence --no-data >test.sql
拿到你的测试库,进行恢复
到这步为止,表结构有了。

2、表空间删除。
select concat('alter table ',table_schema,'.'table_name,' discard tablespace;') from information_schema.tables where table_schema='confluence' into outfile '/tmp/discad.sql';

source /tmp/discard.sql

执行过程中发现,有20-30个表无法成功。主外键关系
很绝望,一个表一个表分析表结构,很痛苦。
set foreign_key_checks=0 跳过外键检查。
把有问题的表表空间也删掉了。
3、拷贝生产中confulence库下的所有表的ibd文件拷贝到准备好的环境中
select concat('alter table ',table_schema,'.'table_name,' import tablespace;') from information_schema.tables where table_schema='confluence' into outfile '/tmp/discad.sql';

4、验证数据
表都可以访问了,数据挽回到了出现问题时刻的状态(2-8)

你可能感兴趣的:(MySQL-DBA课程-Day07)