innodb存储引擎笔记(上)

MySQL发展路线图:

MySQL体系结构

innodb存储引擎笔记(上)_第1张图片

InnoDB体系架构图

innodb存储引擎笔记(上)_第2张图片

总体架构图:

innodb存储引擎笔记(上)_第3张图片

存储结构:

表空间

  • 所有的数据都需要存储在表空间中
  • 表空间分类
    • 系统表空间(ibdata1)
    • 独立表空间(innodb_file_per_table)
    • undo tablespace,MySQL5.6+
    • temporary tablespace,MySQL5.7+
    • general tablespace,MySQL5.7+(类似于oracle的)

问:数据库创建后,还能创建undo 表空间不?
答:目前不能,undo表空间是在数据库初始化的时候创建的。

问:undo有默认的过期时间吗?
答:undo没有默认的过期时间。等这个事务提交完以后,没有更多的事务需要这份undo log的时候,它就可以被清除。也就是MVCC里面没有事务再需要这份旧的undo log的时候,就可以purge掉;

系统表空间

  • 总是必须的
  • 文件名ibdata1
  • innodb_data_file_path定义路径、初始化大小、自动扩展策略
  • 主要存储对象
    • data dictionary
    • double write buffer
    • insert buffer/change buffer
    • rollback segments
    • undo space(新版本可以独立出去)
    • foreign key constraint system tables
    • user data,if innodb_file_per_table=0

建议大小:
innodb_data_file_path = ibdata1:1G:autoextend
除去占用空间最大的undo space之后,剩下的就很小了,不需要太大空间。

独立表空间

  • 设置innodb_file_per_tables = 1
  • 每个table都有各自的xx.ibd文件
  • rollback segments,double write buffer等仍然存放在共享表空间文件里
  • 主要存储聚集索引B+树以及其他普通索引数据

日志文件

  • undo log
  • redo log

Innodb是聚集索引组织表

  • 基于B+树
  • 数据以聚集索引逻辑顺序存储
  • 聚集索引有限选择显示定义的主键
    • 其次选择第一个非null的唯一索引
    • 再次使用隐藏的rowid
    • 聚集索引叶子节点存储整行数据
  • 普通索引同时存储主键索引键值
  • 所有的索引都由两个segment组成
    • leaf page segment
    • non-leaf page segment

表空间

  • 独立表空间优势
    • 表空间可更方便回收
    • 透明表空间文件迁移
  • 共享表空间优势
    • 删除大表或删除大量数据时开销更小,drop table/truncate table
    • 可以使用裸设备,据称性能可能有提升。

表空间管理

  • 消除碎片
    • alter table xx engine=innodb;
    • 或者optimize table xx;
    • 尽量用pt-osc来操作
  • 回收表空间
    • 独立表空间:alter table xx engine = innodb;
    • 共享表空间:重新导入导出
    • 尽量用pt-osc来操作
  • 表空间文件迁移
    • 目标服务器上:alter table xx discard tablespace;
    • 源服务器上:flush table xx for export,备份过去,修改权限
    • 目标服务器上:alter table xx import tablespace;
    • 表结构务必一致
    • innodb_page_size也要一致

问:如何看innodb表的碎片?
答:show table status like ‘tab_name’,看data_length+index_length 然后看idb文件,对比大小。
问:有表 查是400M 物理文件9G,原因是什么?
答:各种大字段 varchar(4000)啊 text什么的。。。

表空间文件迁移步骤:(5.6以后)

1.在目标实例上创建一张和源实例表结构相同的表(表名可以不同)。
2.在目标实例上将表空间discard。 删除旧表空间文件。
alter table xx discard tablespace(执行完这个命令之后,ibd文件就没有了,只剩frm文件了)
3.在源实例上执行FLUSH TABLE xx FOR EXPORT。(执行完这个命令之后,表可以读取,但无法修改,metadata lock。目录下多了个.cfg文件)
将文件cp到目标实例上。并且修改文件权限。
4.在目标实例上执行import tablespace。源实例上unlock tables。
alter table xx import tablespace。

问:表空间迁移到目标实例后,有数据,但是数据行数、大小统计不到了。。。
答:anaylze table

通用表空间(general tablespace)(现在用的不多)

  • 5.7+
  • 类似oracle的做法
  • 多个table放在同一个表空间中
  • 可以定义多个通用表空间,并且分别放在不同的磁盘上
  • 可以减少metadata的存储开销
  • 和系统表空间类似,已分配占有的表空间无法收缩归还给操作系统(全部需重建)

临时表空间,temporary tablespace

  • 5.7+
  • 独立表空间文件ibtmp1,默认12MB
  • 实例关闭后,文件也会删除
  • 实例启动后,文件新创建
  • 无需参与crash recovery,因此也不记录redo log
  • 不支持压缩
  • 由innodb_temp_data_file_path定义

问:排序会用到临时表空间吗?
答:不会,只有create temporary table xxx;这种才会用到。
通用临时表会用到。内部临时表不会用到。
select * from x order by y; 由于没有索引,产生的排序临时表,称为内部临时表,如果session内存排序空间不足,会放到internal_tmp_disk_storage_engine指定的问题,磁盘临时文件。
create temporary table xxx; 通用临时表

undo表空间,undo tablespace

  • 5.6+独立的undo表空间
  • 存储事务中的旧数据
  • innodb_undo_logs设置undo表空间个数
  • 系统表空间总是需要1个undo表空间
  • 临时表空间总是需要32个undo表空间(5.7+)
  • 因此,undo表空间总是必须大于33个,并且循环轮流使用
  • 可以被在线truncate(5.7+)
  • 当所有的undo加起来超过innodb_max_undo_log_size时,会触发truncate工作
  • purge 执行innodb_purge_rseg_truncate_frequency次后,也会触发truncate工作(默认128次)
  • 建议使用独立undo表空间

innodb是聚集索引组织表

  • 基于B+树
  • 数据以聚集索引逻辑顺序存储
  • 聚集索引优先选择显示定义的主键
    • 其次选择第一个非null的唯一索引
    • 再次使用隐藏的rowid
    • 聚集索引叶子节点存储整行数据
  • 普通索引同时存储主键索引键值
  • 所有的索引都由2个segment组成
    • leaf page segment
    • non-leaf page segment

存储结构

tablespace -> segment -> extent(64个page,1M) -> page

  • page,页
    • 最小IO单位,16kB,5.6版本起可以自定义page size
    • 每个page最少存储两行记录(因为是B+tree结构,是双向链表。因此必须存储至少两行记录,才能前后互相连接起来。)
  • extent,区
    • 空间管理单位
    • 每个extent总是1MB,由64个page组成
    • 如果page size是8kB的话,则由128个page组成
  • segment,段
    • 对象单位,例如rollback seg,undo seg,data seg,index seg等
    • 每个segment由N个extent以及32个零散page组成
    • segment最小以extent为单位扩展
  • tablespace,表空间
    • 表存储对象
    • 每个tablespace都至少包含2个segment(叶子/非叶子 page file segment)

问:每个page至少两行记录,那如果是空表,怎么办?
答:每个page都至少有两个虚拟记录,这两个虚拟记录指向的是虚拟最小记录和虚拟最大记录,确保了每个page至少存储两行记录。infimum, supermum
innodb存储引擎笔记(上)_第4张图片

innodb主键

  • 最好是自增属性,INT/BIGINT最佳
  • 数据类型长度小,性能更佳
  • 数据顺序写入也是顺序的,不会离散
  • 也更有利于将更多普通索引放到buffer page中
  • 主键尽量不要更新,否则更新主键时,辅助索引也要跟着更新。(想想为啥?辅助索引记录主键值)

row,行记录

  • row-format
    • redundant,最早的行格式
    • compat,5.0.3以后的默认行格式
    • dynamic,将长字段完全off-page存储
    • compressed,将data,index pages进行压缩,但buffer pool中的page则不压缩。压缩比约1/2,但tps能下降到原来的1/10,不建议使用。
    • 查看行格式:select * from I_S.innodb_sys_tables where name like ‘%tab_name%’;
  • 行溢出,overflow
    • 行记录长度大约超过page一半时,一次将最长的列拆分到多个page存储,知道不在超过page的一般为止。
    • 溢出的列放在一个page中不够的话,还会继续放在新的page中
    • compat格式下,溢出的列只存储前768个字节
    • dynamic格式下,溢出的列只存储前20个字节(指针)
    • select * 会同时读取这些溢出的列,因此代价很高
    • 出现filesort或temporary table时,一般都无法放在内存中,需要变成disk tmp table,IO代价更高。
  • 每row中至少存储几个基本信息
    • DB_ROW_ID,6byte,指向对应行记录,每次写新数据该ID自增,如果已有显示声明的主键,则不需要存储DB_ROW_ID
    • DB_TRX_ID,6byte,每个事务的唯一标识符
    • DB_ROLL_PTR,7bytes,指向undo的回滚指针
    • 用于实现MVCC

注意:现在默认的数据文件类型已经是Barracuda了,不是Antelope了,两种最大区别是对于超长列的存储。Antelope前768个字节存储在行里,Barracuda只存储20个字节的指针。(只针对单行长度超过page大小一半的时候,才会overflow page,并不是只要出现blob或者text就一定会overflow的,单行长度不超过page大小一半,即使行中有blob列,也不overflow page)
innodb存储引擎笔记(上)_第5张图片

内存管理

  • innodb buffer pool一般设置物理内存的50%-70%(5.7可以在线调整)
  • 设置太大可能导致SWAP
  • 使用多个buffer pool instance降低并发内存争用(一般建议每个instance管理8-16G内存)
  • page采用hash算法分配到多个instance中读写
  • 每个缓冲区池管理自己的数据
    • innodb_buffer_pool_instances
    • 每个instance管理自己的free list,flush list,LRU list及其他,并由各自的buffer pool mutex负责并发控制
  • 可以在线修改buffer pool size

  • 在启动时预装入buffer pool

    • innodb_buffer_pool_load_at_startup
    • innodb_buffer_pool_dump_at_shutdown
  • 设置buffer pool刷新机制
    • innodb_flush_method = O_DIRECT(绕过操作系统缓存,直接写阵列卡)
  • buffer pool管理
    • LRU机制
    • 两个列表,young ,old
    • 优先放在young队列
    • 超过innodb_old_blocks_time后移入old队列
    • old队列默认占比innodb_old_blocks_pct = 37

提问:在主从复制中,一张表若是除了一个非唯一的二级索引外并无其他索引,为什么根据二级索引的索引列来更新,也需要校验整行记录的值,并且所有的值一致才能正常在slave上重放? 不是根据二级索引,得到一个内部的隐藏rowid就可以进行更新了吗?

答:因为同一行的rowid在主从上不一定一致。
为什么ROW格式日志一定要用主键定位记录,如果用二级索引行不行?虽然没有主键那么精准,但至少可以避免全表扫描。
根据主键做的更新,不会校验行数据。

你可能感兴趣的:(mysql)