112. MySQL 存储引擎

1.存储引擎介绍

相当于Linux 文件系统.组织存储表数据.

2.存储引擎的种类

show engines;
InnoDB 
MyISAM
CSV	做迁移时使用
Memory
其他的存储引擎: 
MariaDB  : InnoDB,TokuDB ,Myrocks  
percona  : 原生xtradb ,TokuDB ,Myrocks 

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

3.InnoDB存储引擎的核心特性

面试题:
(1) InnoDB存储引擎的特性 
(2) InnoDB和MyISAM的区别

MVCC       多版本并发控制  
聚簇索引   PK,主键,id会自增
事务
行级锁     MyISAM支持表锁(ROW Level Lock)
外键       FK(FOREIGN KEY)	
复制支持高级特性: GTID等高级复制
自适应hash索引 Adaptive HASH Index
支持热备,MyISAM支持温备份
ACSR(自动故障恢复)
Replication	

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;
  
2.查询所有非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)
  
3.修改表的存储引擎
  alter table test.test engine=innodb; 
  
  
扩展: 碎片问题解决.
  由于业务中有大量的delete操作,产生了大量的碎片.
  (1) 表数据逻辑导出,删除原表,重新导入.
  (2) mysql> alter table test.test engine=innodb;
  
mysql> create table abc(id int not null primary key auto_increment,name varchar(64));  
mysql> insert into abc(name) values('a');
Query OK, 1 row affected (0.00 sec)

mysql> insert into abc(name) values('b');
Query OK, 1 row affected (0.00 sec)

mysql> insert into abc(name) values('c');
Query OK, 1 row affected (0.00 sec)

mysql> insert into abc(name) values('d');
Query OK, 1 row affected (0.35 sec)

mysql> select * from abc;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
|  3 | c    |
|  4 | d    |
+----+------+
4 rows in set (0.00 sec)
mysql> delete from abc where id=2;
Query OK, 1 row affected (0.01 sec)

mysql> select * from abc;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  3 | c    |
|  4 | d    |
+----+------+
3 rows in set (0.00 sec)
mysql> insert into abc(name) values('e');
Query OK, 1 row affected (0.00 sec)

mysql> select * from abc;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  3 | c    |
|  4 | d    |
|  5 | e    |
+----+------+
4 rows in set (0.00 sec)

小项目:
  环境:centos7.5,MySQL 5.7.20,InnoDB存储引擎
  业务特点:数据量级较大,经常需要按月删除历史数据.
  问题:磁盘空间占用很大,不释放
  处理方法:
  以前:将数据逻辑导出,手工truncate,然后导入进去
  
现在:
  对表进行按月进行归档表
  业务替换为truncate方式
当我删除了某一个id时,发现我的id自增长值越来越大,我们当时就认为这个表有大量的delete操作造成碎片过多,然后呢,我们想做一个碎片清理,释放掉一部分空间,使用这条命令alter table test.test engine=innodb; 为了更加彻底的清除碎片,我们在凌晨一点多,将数据逻辑导出--->truncat--->重新导入,最终把我们的碎片问题彻底的解决掉了   

5.生产案例:

环境: 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';
[root@zabbix ~]# mysqldump -B zabbix >/tmp/zabbix.sql
[root@zabbix ~]# scp -rp /tmp/zabbix.sql [email protected]:/tmp/
导入zabbix数据库  mysql> source /tmp/zabbix.sql;



为什么?

1. 原生态支持TokuDB,另外经过测试环境,10.x要比5.5 版本性能 高  2-32. TokuDB:insert数据比Innodb快的多,数据压缩比要Innodb3.监控数据按月份进行切割,为了能够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

7. InnoDB存储引擎物理存储结构

7.1 表空间(tablespace) ***
支持两类表空间: 共享,独立
5.5 版本 :  默认共享表空间.    包含: 数据字典\undo\tmp\用户表数据和索引
5.6 版本 :  默认独立表空间.    包含: 数据字典\undo\tmp,将用户数据和索引独立,每个表单独存储
5.7 版本 :  默认独立表空间.    包含: 数据字典\undo,tmp独立,将用户数据和索引独立,每个表单独存储
8.0 版本 :  默认独立表空间.    数据字典取消掉, undo,tmp独立  将用户数据和索引独立,每个表单独存储

(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自动独立出来,移除了数据字典的存储.

7.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

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

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

7.4 表空间迁移(快速迁移部分表数据;适合大表)
(1) 准备一个新环境
启动mysql3307--->创建db1数据库--->
mysql> create table t1 (id int(11) default null,addr json default null);
Query OK, 0 rows affected (0.10 sec)
mysql> insert into t1(id,addr) values(1,'{"addr_1":"山东省"}');	插入json数据
(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) 导入表空间文件.
mysql> select * from t1;
ERROR 1814 (HY000): Tablespace has been discarded for table 't1'

alter table t1 import tablespace;
mysql> select * from t1;
+------+-------------------------+
| id   | addr                    |
+------+-------------------------+
|    1 | {"addr_1": "山东省"}    |
+------+-------------------------+

7.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

8.实施过程:zabbix库替换存储引擎

##### 1.部署 Mariadb 环境 10.0.38

[root@db01 mysql]# vim /etc/yum.repos.d/mariadb.repo 
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=0
enabled=1

tar   xf mariadb-10.0.38-rhel-7-x86_64-rpms.tar

2.改配置文件
[root@db01 my.cnf.d]# vim /etc/my.cnf.d/tokudb.cnf 

[mariadb]
plugin-load-add=ha_tokudb.so
plugin-dir=/data/tokudb/plugin/
tokudb_commit_sync=ON
tokudb_cache_size=128M
tokudb_directio=ON
tokudb_row_format=tokudb_fast
tokudb_tmp_dir=/data/tokudb/tmp
tokudb_write_status_frequency =1
tokudb_read_status_frequency=1
tokudb_data_dir=/data/tokudb/data
tokudb_log_dir=/data/tokudb/log
~                                                                                                                                   
mkdir -p ~    /data/tokudb/{plugin,tmp,data,log}                                       
chown -R mysql.mysql /data/*
cd /usr/lib64/mysql/plugin/
cp -a * /data/tokudb/plugin/
chown -R mysql.mysql /data/*

3.启动数据库
[root@db01 data]# mysqld_safe &

4.生成批量替换语句 
select concat('alter table ',table_schema,'.',table_name,' drop FOREIGN KEY ', CONSTRAINT_NAME,";") from information_schema.TABLE_CONSTRAINTS  where table_schema='zabbix'  and CONSTRAINT_TYPE='FOREIGN KEY';

select concat('alter table ',table_schema,'.'table_name,' engine=tokudb') from information_schema.tables where table_schema='zabbix' into outfile '/tmp/alter.sql';


percona-server+tokudb+zabbix
https://www.jianshu.com/p/898d2e4bd3a7
   1. 支持哪些存储引擎 
   2. 同源产品的存储引擎: TokuDB ,Myrocks
      小项目:  zabbix 监控系统 mariadb5.5   ----> mariadb  10.0.38 (Perconna 版本都支持)
   3. InnoDB引擎和MyISAM引擎区别 
      MVCC 
      CLusterd Index
       Transaction 
      Row Level Lock
      FOREIGN KEY 
      Hot Backup 
      Adaptive HASH Index
      ACSR
      Replication 
   4. 表空间迁移 
      create table  
      alter  table  discard 
      alter  table  import
   
   5. 碎片整理 
      alter table t1 engine=innodb;
   
   6. ICP,Insert buffer,AHI,MRR,SNL,BNL,BKA
      ICP   : 索引下推
         减少了 Server和engine,engine和磁盘的次数
      Insert buffer : 插入缓冲
         insert数据,不会立即更新到索引树中,存储在Insert buffer中.
        index merge 功能在内存中合并查询索引树. 减少的大批量insert操作时索引的更新,减少IO和锁表的时间.
      AHI : 自适应HASH索引
        访问次数>=3的索引内存也,InnoDB会自动生成索引页的HASH索引(内存).加速索引页的访问
      MRR : 辅助索引---回表->聚簇索引, 在回表之前自动将主键值先排序,一次性回表查询
        减少回表次数,随机IO尽可能转换为顺序IO
      SNL,BNL,BKA : Join 的三种经典算法 
      SNL :  关联表中没有索引.我们不建议出现
      BNL :  在驱动表,得到所有数据,一次性到内循环中进行匹配
   
   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)

9.物理存储结构

1.1 表空间 
支持两类表空间: 共享,独立
5.5 版本 :  默认共享表空间.    包含: 数据字典\undo\tmp\用户表数据和索引
5.6 版本 :  默认独立表空间.    包含: 数据字典\undo\tmp,将用户数据和索引独立,每个表单独存储
5.7 版本 :  默认独立表空间.    包含: 数据字典\undo,tmp独立,将用户数据和索引独立,每个表单独存储
8.0 版本 :  默认独立表空间.    数据字典取消掉, undo,tmp独立  将用户数据和索引独立,每个表单独存储

1.2 功能名词介绍
transaction :        事务********
undo  : ibdata1       回滚日志
tmp   : ibtmp1        临时表空间 
redo  : ib_logfile0~N 重做日志
ibd   : t1.ibd        表空间数据文件,存放数据和索引


Innodb Buffer Pool    数据缓冲区池(70-80%)5.7以后加入的特性
log buffer            重做日志缓冲区
LSN                   日志序列号  
Trx_id                事务ID
checkpoint            检查点  

10.事务

(1) 自动提交机制 
MySQL 5.6 以后:

1.begin子句会自动添加
2.每一条执行完成之后都会自动提交
mysql> delete from city where id=100;
Query OK, 1 row affected (0.00 sec)

mysql> select * from city where id=100;
Empty set (0.00 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+

[root@db01 data_3306]# vim /etc/my.cnf 
autocommit=0
[root@db01 data_3306]# /etc/init.d/mysqld restart
mysql> delete from city where id=200;
Query OK, 1 row affected (0.00 sec)

mysql> delete from city where id=300;
Query OK, 1 row affected (0.00 sec)

mysql> delete from city where id=400;
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from city where id=300;
+-----+-----------+-------------+-------------------+------------+
| ID  | Name      | CountryCode | District          | Population |
+-----+-----------+-------------+-------------------+------------+
| 300 | Gravataí  | BRA         | Rio Grande do Sul |     223011 |
+-----+-----------+-------------+-------------------+------------+
1 row in set (0.00 sec)


说明: 默认情况下,开启事务时不加begin,逐条自动提交. 手工开启begin命令,按照正常事务工作过程.--->rollback


(2) 隐式提交
1.用于隐式提交的 SQL 语句:
begin 
a
b
begin
---------------------------------------------------------------------------
SET AUTOCOMMIT = 1
2.导致提交的非事务语句:
DDL语句: (ALTERCREATEDROP)
DCL语句: (GRANTREVOKESET PASSWORD)
锁定语句:(LOCK TABLESUNLOCK TABLES3.导致隐式提交的语句示例:
TRUNCATE TABLE
LOAD DATA INFILE
SELECT FOR UPDATE
========================================================================
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from city where id=200;
Query OK, 1 row affected (0.00 sec)

mysql> delete from city where id=300;
Query OK, 1 row affected (0.00 sec)

mysql> create database test1;
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from city where id=200;
Empty set (0.00 sec)

mysql> select * from city where id=300;
Empty set (0.00 sec)

(3) 隐式回滚
会话断开
数据库重启
死锁 

11.事务底层的工作过程

画图说明.
(1) redo 
分布: 
	内存: log buffer
	磁盘: ib_logfile0~N
功能: 

 	1. 保存内存数据页的变化
     2. commit, 实现事务的快速持久化的特性:  量少,顺序IO
     3. 宕机时,通过redo实现重做事务,将数据库恢复到宕机之前的状态.
        我们由把这步称之为 ACSR 中的"前滚"操作

(2) undo 回滚日志
分布:    默认 ibdata1, 5.7开始可以独立undo,8.0后自动独立 

功能 :   
	 1. 保存当前事务操作的反操作
     2. 在执行rollback命令时,undo提供回滚操作,在ACID中主要实现A的特性,CI也有部分功能
	 3. 宕机时,ACSR过程中提供回滚操作(将没有commit标记的)
	 
(3)() 及 隔离级别()主要保证隔离性
1.锁 :
 S    : 共享锁,读锁
 X    : 排它锁,写锁
 IS   : 意向S锁
 IX   : 意向X锁

2. X 锁的细分 
TX       ------> 表锁   DDL
2.1全局锁表:
备份时,备份系统表时(非INOODB表),FTWRL(全局锁表)
mysql> flush table with read lock;	加锁
mysql> unlock tables;	解锁

2.2单表锁: DDL
mysql> lock table t1 read ;
mysql> unlock tables; 

2.3有索引的情况下称为索引锁
RX       		------> 记录锁 DML
GAP  LOCK X     ------> 间隙锁 特殊DML
Next LOCK X     ------> 下一键锁定


(3) 隔离级别(transaction_isolation)
mysql> select @@transaction_isolation;
RU  :读未提交        READ-UNCOMMITTED

模拟: 
session  A  
mysql> begin;
mysql> use world
mysql> delete from city where id=1000;

session  B 
mysql> begin;
mysql> use world
mysql> select *from city where id=1000;

会产生的问题: 
	1. 脏读
	2. 不可重复读现象
	3. 幻读

RC  :读已提交  ***** READ-COMMITTED
	1. 不可重复读现象
	2. 幻读
	3.注意:在金融行业不要使用这种方式
	
模拟RC不可重复读现象:
mysql01> begin;
Query OK, 0 rows affected (0.00 sec)

mysql01> delete from city where id=2000;
Query OK, 1 row affected (0.00 sec)
mysql 02> begin;
Query OK, 0 rows affected (0.00 sec)

mysql 02> select * from city where id=2000;
+------+----------+-------------+----------+------------+
| ID   | Name     | CountryCode | District | Population |
+------+----------+-------------+----------+------------+
| 2000 | Changzhi | CHN         | Shanxi   |     317144 |
+------+----------+-------------+----------+------------+
1 row in set (0.00 sec)
mysql01> commit;
Query OK, 0 rows affected (0.00 sec)
mysql02> select * from city where id=2000;
Empty set (0.00 sec)

===========================================================================================
模拟RC幻读现象
mysql01
mysql> create table t2 (id int ,name varchar(10));
Query OK, 0 rows affected (0.10 sec)

mysql> insert into t2 values(1,'a'),(2,'b'),(3,'c'),(10,'x'),(20,'x');
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> seletct * from t2;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'seletct * from t2' at line 1
mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|   10 | x    |
|   20 | x    |
+------+------+
5 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|   10 | x    |
|   20 | x    |
+------+------+
5 rows in set (0.00 sec)

mysql> update t2 set name='z' where id>3;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

-------------------------------------------------------------------------------------
mysql02
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t2 values(15,'yy');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t2 values(50,'yi');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t2 set name='dgsgsg' where id=20;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
--------------------------------------------------------------------------

mysql01
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|   10 | z    |
|   20 | z    |
|   15 | yy   |
|   50 | yi   |
+------+------+
7 rows in set (0.00 sec)
幻读原理:01事务要更新一个范围内的值,条件为大于10的,预想的是大于10的值都将变为z,0201工作过程中在表中范围内插入了一些新的值,导致01提交完成之后再查看时发现了意想不到的结果,发现新录入的数据并没有修改,这就是幻读的现象

RR  :可重复读  ***** REPEATABLE-READ
	1. 幻读    
说明: 
1. RR级别+ GAP+ 下键锁Next lock(GAP锁+RX行级锁) 有效防止幻读现象  基于索引  where条件限制
2. 通过MVCC,多版本并发控制中,一致性快照读技术,解决了不可重复读问题.
模拟RR 可重复读
mysql01
mysql> use test;
mysql> create table t3 (id int not null primary key auto_increment,money int);
Query OK, 0 rows affected (0.14 sec)

mysql> alter table t3 add index idx(money);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into t3 values(1,1000),(2,2000),(3,3000),(4,3200),(5,3500),(6,3600);
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t3;                                       
+----+-------+
| id | money |
+----+-------+
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
|  4 |  3200 |
|  5 |  3500 |
|  6 |  3600 |
+----+-------+
6 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t5;
+----+-------+
| id | money |
+----+-------+
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
|  4 |  3200 |
|  5 |  3500 |
|  6 |  3600 |
+----+-------+
6 rows in set (0.00 sec)

mysql> insert into t5 values(7,3700);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t5 values(8,500);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql02
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t5;
+----+-------+
| id | money |
+----+-------+
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
|  4 |  3200 |
|  5 |  3500 |
|  6 |  3600 |
+----+-------+
6 rows in set (0.00 sec)
结果:可以看出无论你怎么操作,它都是可重复读
============================================================================
RR 模拟防止幻读现象
mysql01
mysql> select * from t5;
+----+-------+
| id | money |
+----+-------+
|  8 |   500 |
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
|  4 |  3200 |
|  5 |  3500 |
|  6 |  3600 |
|  7 |  3700 |
+----+-------+
8 rows in set (0.00 sec)

mysql> 
mysql> 
mysql> update t5 set money=3000 where money<3000;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0
-----------------------------------------------------------------------------------
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t5;
+----+-------+
| id | money |
+----+-------+
|  8 |   500 |
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
|  4 |  3200 |
|  5 |  3500 |
|  6 |  3600 |
|  7 |  3700 |
+----+-------+
8 rows in set (0.01 sec)

mysql> insert into t5 values(9,800);	因为有间隙键控制,小于3000的是插不进去
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into t5 values(9,8000);	相反,大于3000即可插入
Query OK, 1 row affected (0.01 sec)
================================================================================
模拟RR解决了不可重复读问题

SR  :串行化

总结:
	A I D 都是为了数据库最终一致性 C
	SQL_MODE
	约束

自己扩展:  
MDL  原数据锁
page lock  页锁
latch  内存页锁

12.InnoDB 存储引擎核心参数

1.共享表空间的参数设置:一般是512M
mysql> select @@innodb_data_file_path;
mysql> select @@innodb_file_per_table;	每个表都是独立的表空间

2.缓冲区池
mysql> select @@innodb_buffer_pool_size;  #不要超过80%物理内存 ----> Out of memory
默认128M;

mysql> select @@innodb_log_buffer_size;		查看日志缓冲区的大小(与日志文件的大小有关,默认16M)
mysql> select @@innodb_log_file_size;	存放redo日志的信息;默认日志文件大小48M ib_logfile0 可以设置多个
并发量大的话,需要根据当前的情况对以上两个参数进行调整
mysql> show variables like '%group%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| binlog_group_commit_sync_delay          | 0     |
| binlog_group_commit_sync_no_delay_count | 0     |
| group_concat_max_len                    | 1024  |
| innodb_log_files_in_group               | 2     |
| innodb_log_group_home_dir               | ./    |
| slave_checkpoint_group                  | 512   |
+-----------------------------------------+-------+
mysql> select @@innodb_log_file_in_group;	设置个数;
需要修改的话-----》编辑mysql配置文件 my.cnf 添加以下参数--->重启mysql服务
innodb_log_file_size=256M
innodb_log_files_in_group=3

[root@db01 ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL....................... SUCCESS!
[root@db01 data_3306]# ls -l |grep ib_logfile
-rw-r----- 1 mysql mysql 268435456 Dec 26 01:12 ib_logfile0
-rw-r----- 1 mysql mysql 268435456 Dec 26 01:12 ib_logfile1
-rw-r----- 1 mysql mysql 268435456 Dec 26 01:12 ib_logfile2

mysql> select @@innodb_flush_log_at_trx_commit; # 双1标准之一.控制redo刷写的策略.
+----------------------------------+
| @@innodb_flush_log_at_trx_commit |
+----------------------------------+
|                                1 |
+----------------------------------+
1 row in set (0.00 sec)

0  每秒钟刷写redo到磁盘. 
1  每次事务提交,理解刷写redo到磁盘
2  每次事务提交,立即写日志到OS cache中,然后每秒钟刷写到磁盘.

mysql> select @@innodb_flush_method; 控制(buffer脏页,redo buffer日志)刷写方式
建议设置:   
	O_DIRECT :  数据页刷写磁盘直接穿过文件系统缓存,redo 刷写时,先写os cache,再写到磁盘。

查看数据库占用的内存
mysql> show engine innodb status \G
Buffer pool size   8191		#代表8191个内存页;默认128M
Free buffers       7695		#未使用的
Database pages     494		#已使用的

发布了148 篇原创文章 · 获赞 65 · 访问量 7630

猜你喜欢

转载自blog.csdn.net/chengyinwu/article/details/103721334