day8-MySQL存储引擎

教程链接:http://c.biancheng.net/view/2361.html

什么是存储引擎

数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。

提示:InnoDB 事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。MySQL 5.5.5 之后,InnoDB 作为默认存储引擎。

MyISAM 是基于 ISAM 的存储引擎,并对其进行扩展,是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事务。

MySQL存储引擎种类

存储引擎能够根据具体的应用建立不同存储引擎表。

 1 #存储引擎种类
 2 InnoDB
 3 MyISAM
 4 MEMORY
 5 ARCHIVE
 6 FEDERATED
 7 EXAMPLE
 8 BLACKHOLE
 9 MERGE
10 NDBCLUSTER
11 CSV

其他分支

percona  : XtraDB
MariaDB  : InnoDB
其他的引擎:
TokuDB , MyRocks 
Compression: 25x for high compression
Fast Insertions and Deletions
适合于,业务当中有大量插入或者删除操做的场景。
应用于,数据量较大的业务。
功能MylSAMMEMORYInnoDBArchive
存储限制 256TB RAM 64TB None
支持事务 No No Yes No
支持全文索引 Yes No No No
支持树索引 Yes Yes Yes No
支持哈希索引 No Yes No No
支持数据缓存 No N/A Yes No
支持外键 No No Yes No

InnoDB **

MySQL 5.5或更高版本的默认存储引擎。

  • 支持 事务,其特点是 行锁设计、支持外键

  • 支持全文索引

  • 支持 非锁定读,即默认读取操作不会产生锁

  • 高并发,高性能,高可用,高可拓展

  • 采用了聚集的方式,每张表都是按主键的顺序进行存放,如果没有显式的指定主键,它会为表的每一行生成一个6字节的ROWID作为主键

MyISAM

  • 不支持事务、表锁设计

  • 支持全文索引

  • 缓冲池只缓冲索引文件,不缓冲数据文件

  • 存储引擎表由MYDMYI组成,MYD用来存放数据文件,MYI用来存放索引文件

NDB

  • 是一个集群存储引擎,结构是share nothing的集群架构,具备更高的可用性

  • 数据全部存放在内存中,可以将非索引数据存放在磁盘上

  • 主键查找

  • 不适合连接操作(Join)。ps: MySQL数据库层完成,而不是存储索引层,复杂的连接需要巨大的网络开销,因此查询速度很慢。

Memory

  • 数据存放在内存中,断电后消失,查询速度快,适合存储临时数据

  • 默认使用哈希索引

  • 只支持表锁,并发性能

  • varchar类型是按照定常字段(char)的方式存储,会浪费内存

存储引擎的基础管理命令

使用 select 确认会话存储引擎

select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.00 sec)

默认存储引擎修改

 注:不代表生产操作

会话级别

select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.00 sec)

全局级别

注:仅影响新会话

set global default_storage_engine=myisam;
Query OK, 0 rows affected (0.00 sec)

#查看存储引擎
select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| MyISAM                   |
+--------------------------+
1 row in set (0.00 sec)

重启之后,所有参数均失效

永久生效

写入配置文件

vim /etc/my.conf
[mysqld]
default_storage_engine=myisam

注:存储引擎是表级别的,每个表创建时可以指定不同的存储引擎,但是我们建议统一为innodb.

SHOW确认表的存储引擎

create table xx (id int) engine=myisam;
create table x (id int);

SHOW CREATE TABLE xG;
SHOW TABLE STATUS LIKE 'xx'G

INFORMATION_SCHEMA 确认表的存储引擎

select table_schema,table_name ,engine 
from information_schema.tables 
where table_schema 
not in ('sys','mysql','information_schema','performance_schema');

修改一个表的存储引擎

alter table x engine=innodb;
Query OK,
0 rows affected (0.18 sec) Records: 0 Duplicates: 0 Warnings: 0

注:此命令我们经常使用他,进行innodb表的碎片整理

平常处理过的mysql问题

环境:centos7.4,MySQL 5.7.20,InnoDB存储引擎

业务特点:数据量级较大,经常需要按月删除历史数据.

问题:磁盘空间占用很大,不释放

处理方法:以前:将数据逻辑导出,手工drop表,然后导入进去

现在:对表进行按月进行分表(partition,中间件)或者归档表(pt-archive)业务替换为truncate方式

如何批量修改

需求1:将zabbix库中的所有表,innodb替换为tokudb

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

需求2:将所有非InnoDB业务表查询出来,并修改为InnoDB

select concat("alter table ",table_schema,".",table_name," engine=innodb;" )
from information_schema.tables 
where engine != 'InnoDB'
and table_schema not in ('sys','performance_schema','information_schema','mysql')
into outfile '/tmp/alter.sql' ;

mysql存储引擎体系结构

宏观结构

MyISAM

文件作用
myt.frm 数据字典信息(列的定义和属性)
myt.MYD 数据行
myt.MYI 索引

InnoDB

文件作用
city.frm 数据字典信息(列的定义和属性)
city.ibd(独立表空间文件) 数据行和索引
ibdata1 (共享表空间文件) 数据字典信息,UNDO(事务回滚日志),double write 磁盘区域,change buffer磁盘区域

说明: 不同版本ibdata1中存储的数据不一样

5.5 : ibdata1 中还会存储临时表数据 +用户数据(数据行+索引)
5.6 : ibdata1 中还会存储临时表数据 
8.0 : ibdata1取消存储 数据字典信息,undo 独立了。

可以理解为,MySQL在慢慢瘦身ibdata1共享表空间,把比较关键的数据独立出来了。

ib_logfile0~ib_logfileN: InnoDB 事务重做日志(redo log)

ibtmp1: 临时表空间文件(排序,分组,多表连接,子查询,逻辑备份等。)

ib_buffer_pool:正常关库的时候,存储缓冲区的热数据。

InnoDB 微观结构

从架构图中可见,InnoDB引擎可划分为两大部分:内存结构硬盘结构.

  • 内存部分(Memory)又包含Buffer pool, change buffer, Log Buffer 等,通过操作系统缓存与硬盘结构进行交互.
  • 硬盘部分包含若干个表空间,如系统表空间,单文件表空间,一般表空间,临时表空间,undo表空间redo log.

Buffer Pool(缓冲池)#

 

缓冲池是主内存的一部分,它用于在我们查询访问任何表和索引数据时进行缓存.据官方文档介绍的统计,高达80%的查询来会由缓存池命中.

首先,缓冲池可以理解为一个塞满page的链表,注意,其中单位是页(page, innodb引擎的存储单位自上到下为表空间 table spaces,片段 segemant, 分区 extend, 页 page, 行row,列 column),也就是说,缓存是以页为单位的,io操作将硬盘中的数据读入缓冲的单位也是页.

其次,缓冲队列其实有两个sublist,最新的5/8为new sublist,较老的3/8为old sublist.new sublist 的tail与old sublist 的head相邻,这个相邻点被官方文档称之为midpoint(中点).较新访问的数据放置于new sublist,反之放置于old sublist.

第三,当我们从硬盘中读取新的页并入池时,它是放置于中点的.当然,这个"读"包含我们用户的初始化操作(user-initiated, 包含sql查询),也包含引擎为优化而做的预读操作(read-ahead).

第四,有关移动操作,对于old sublist的页成员进行读取操作时,分两种情况,若为用户初始化操作造成,则会立即将其移动到new list头,若为预读操作造成,则可能不会移动.

第五,每个页的位置相当于一个虚拟的"年龄",每当buffer pool有一个页被读取,都会造成其他页的年龄加1(实际效果即向后移位).同时,old sublist的成员也会因一些页的初次读入缓存而老化,通过这两个机制的共同作用,new sublist的元素不停地移入old sublist,old sublist中的数据可能会慢慢过期或得到新生.

change buffer(变更缓冲)#

change buffer的作用点在于,对于一些数据的二级索引进行更新操作(insert update delete都在此更新范围),而相应的辅助索引页还并未加载进缓冲池时,将相应的对辅助索引的更新缓存到change buffer,直到当后续对相应的页进行了读操作时,将这个结果合并进buffer pool.

这样实现的理由也很简单,我们知道辅助索引(二级索引)不像聚簇索引一样唯一,它的插入操作相对为随机写.对二级索引的删除和更新操作也可能会影响到在索引树中根本不相邻的数据页,因此将它暂时缓冲起来,在后续使用到变更索引的读操作发生时统一合并入buffer pool,再由buffer pool返回读取的结果,可以减少大量的随机写操作.

同时,当mysql进行周期净化(purge)操作时,或进行慢关闭时,可以将这些change buffer批量地写入到硬盘,后者会写入到系统表空间的change buffer,从而减少了多个单次io的开销.

特殊情况,当二级索引包含降序索引列,或主键包含降序索引列时,change buffer将不可用.change buffer的批量落盘操作会造成mysql瞬间的io开销增大.

adaptive hash index (自适应哈希索引)#

自适应哈希索引作用于缓冲池中的数据,当有效地平衡了工作负载和缓冲池内存时,我们使用自适应哈希索引可以令mysql在不损坏任何事务性和可靠性的前提下逼近内存数据库的性能.

它是自适应的(意味着可以由innodb自行观测查询频率,并估算优化的结果和构建哈希索引的开销比),它的构建是使用索引key的左前缀实现的,主要针对频繁访问的数据.

有两种特殊地场景,高并发地访问自适应哈希索引(如并发地进行join)可能会是一个重要的竞态来源,当我们大量使用通配符%或like操作时,自适应哈希索引将毫无益处,此时可以通过重启服务并加上 --skip-innodb-adaptive-hash-index 关闭之.

log buffer#

log buffer是一块内存区域,用于保存将要刷盘的日志操作,它有两个落盘的机制,一是周期性地落盘,二是事务提交后落盘,因此当我们使用大事务时,适当调大它的值,可以减少无谓的io.

system tablespace (系统表空间)#

系统表空间是在硬盘中存放double write bufferchange buffer的表空间,同时,若一个表创建于系统表空间(而不是单文件表空间或一般表空间)时,它可存放这些表的表数据和索引数据.

File-Per-Table Tablespaces (单文件表空间)#

据官方文档介绍,单文件表空间相对于传统的所有表数据存放于系统表空间的优势在于更加灵活,它使得每个表可以有自己的表空间文件.

General Tablespace (一般表空间)#

一般表空间是共享的,由create tablespace语法创建的表空间.它与系统表空间类似,存放可供多表使用的共享数据.它具备先天的使用优势,如在完整生命周期内将表空间的数据加载至内存,则可减少类似单文件表空间的频繁io开销.

undo tablespaces

undo log包含于undo段,undo段包含于回滚段,而undo表空间就是存放了可用于回滚事务的undo log.

temporary tablespaces(临时表空间)#

临时表空间包含两个级别:会话级别的临时表空间全局的临时表空间.

会话级临时表空间每次使用时会从一个临时表空间池中取出并和session进行attach,默认情况下,server启动时会创建一个拥有10个临时表空间的池供使用,当会话释放时,它持有的临时表空间会被清空并还池.

会话级临时表空间默认大小为5个page大小,并且以.ibt结尾.

全局级临时表空间用于存放对于用户创建的临时表的变更回滚段.在server关闭或放弃了全局级临时表空间的初始化操作时销毁,在server每次启动时重建.

 double write buffer(双写缓冲)#

双写缓冲存放于系统表空间,是innodb从内存模块的buffer pool取出的页刷新到磁盘的目的地,这也说明对于innodb的写操作其实是二次写,但这并不影响宏观的性能,反而增大了吞吐量.double write buffer中已写入的数据将在后续刷入它真正的目的地,若在此过程中出现宕机等事故,mysql server将可以在double write buffer中找到一个准确的copy.

数据页刷入double write buffer的过程使用了操作系统的fsync()函数,将较大的数据量统一处理,顺序写入.这一特性可以手动关闭,或者在支持原子写的Fusion-io设备上运行时,将自动禁用double write buffer.

redo log(重放日志)#

重放日志也是一个用于恢复数据的存放于硬盘的数据结构,但它作用于那些未完成的事务.在一次crash保存的未完成的对某些数据文件的更改可以在后续服务启动后的初始化过程中基于redo log自动重放.

重放日志在物理上体现为两个文件: ib_logfile0 , ib_logfile1 ,mysql中对这两个文件的使用是"环形方式",这意味着可以交替重用.redo log中的日志标识是一个按LSN(日志顺序号)永远递增的数.

为了节省性能,重放日志也支持按组提交落盘(批量).日志本身支持压缩.

undo log(回滚日志)#

undo log是单次读写事务的回滚日志,它包含了对于一个事务来说必要的针对一个聚簇索引记录的最近修改的回滚信息,如果有一个事务在一致读场景下需要读到原版本数据,它可以从它事务的undo log中找到相应的数据.

mysql innodb引擎的隔离级别实现与undo log有重大关联,当隔离级别为读已提交时,事务对数据的读取永远是取最新提交,并不需要undo log,但当级别为可重复读时,每次读取需要利用undo log进行.

Multi-Versioning(多版本并发控制,一般简称mvcc)#

innodb是一个支持多版本并发的存储引擎,前面已经提过,innodb利用表空间的回滚段(包含了undo log)来保存了为支持事务的并发和回滚而必需的,被修改数据行的老版本信息,它使用该信息进行回滚以及一致性读等操作.

关于mvcc的内部实现,innodb为每一行数据多维护了隐式的三个field,分别是6字节长的DB_TRX_ID,7字节长的DB_ROLL_PTR,6字节的DB_ROW_ID.

DB_TRX_ID:它表示最近对一个行的数据的插入或更新的事务id(删除在此理解为一种更新操作,只是行中有一个位表示标记为删除).

DB_ROLL_PTR:即滚动指针,它指向undo段的一个undo log.当发生该行的更新时,undo log中包含了重建历史数据的全部信息.

DB_ROW_ID:行id,它是一个在新行插入时单调递增的值,当innodb自动生成聚簇索引时,索引将包含行id,否则行id不出现在任何索引中.

存放于undo段的undo log区分为insert和update两种(后者包含delete),前者可以在事务提交之后直接舍弃,后者因一致性读的原因(这些读需要访问历史版本的数据),只能在所有快照均没有事务在使用时才能舍弃.

因此,需要及时地提交事务,尤其那些包含一致读的事务,否则undo log会越来越大,最终充满表空间.

涉及mvcc,被删除的数据行不会立即物理删除,直到有关的undo log被删除,这一操作称为purge,并且它会按照实际删除的顺序进行.

对于mvcc,innodb在聚簇索引和二级索引实现上稍有不同,聚簇索引能覆盖的记录会就地更新,而指向早期版本记录的undo log指向的一些隐藏信息条目可以进行重建,但对于二级索引,它并不包含隐藏系统列,也不进行原地更新.

当二级索引被更新时,老的二级索引记录会被标记删除,新的二级索引会插入,标记删除的老二级索引记录会最终被清理,如果已经开启了一个针对它的读事务,且发生了写操作,则从undo log中查找相应的版本记录.

当二级索引被删除时,覆盖索引将不可用,即不从索引树中查找,而是从聚簇索引记录中查找.

当使用索引条件下推优化时,且只有部分where查询条件可使用到索引,mysql server仍旧会将全条件下推到存储引擎,而存储引擎会即使相应的索引取值,如果没有取到值,则省去了后续的使用聚簇索引再次查找的过程.如果有记录(甚至可能是被标记删除但能匹配的记录,还未被purge,可能是因为mvcc),则无可避免后续的,还需要进行一次的利用聚簇索引查找的过程.

原文地址:https://www.cnblogs.com/Mercury-linux/p/12346212.html