数据的储存
在innoDB存储引擎中,所有数据都被逻辑的放在表空间中,表空间是存储引擎中最高的存储逻辑单位,在表空间的下面包括段(segment),区(extent),页(page)
同一个数据库实例的所有表空间都有相同的页大小,默认情况下,表空间中的页大小都为16kb,可以通过innoDB-page-size进行修改.
一个区的大小最小为1m,页最少为64.区大小=页*页大小
如何存储表
使用innoDB存储表时,会将表的定义和数据索引等信息分开存储,前者存储在.frm文件中,后者存在.ibd文件中.
- .frm 无论在mysql中选择了那个存储引擎,所有的mysql表都会在硬盘上创建一个.frm文件用来描述表的格式..frm文件的格式在不用的平台上都是相同的.
- .ibd
inniDB中用于存数数据的文件总共有两个部分,一是系统表的空间文件,包括ibdata1,ibdata2等文件,其中存储了innoDB系统信息和用户数据库表数据和索引,是所有表公用的
当打开innodb-file-per-table选项时,.ibd文件就是每一个表独有的表空间,文件存储了当前表的数据和索引数据.如何存储记录
innoDB使用页作为磁盘管理的最小单位,数据在innoDB存储引擎中都是按行存储的,每个16k大小的页可以存放2-200行记录.
当innoDB存储数据时,可以使用不用的行格式进行存储.
数据页结构
页是innoDB存储引擎管理数据的最小磁盘单位,而B-Tree节点就是实际存放表中数据的页面.一个innoDB页有七个部分:
- 每一页包含两对/header/trailer,内部的page Header/page Directory关心的是页状态信息,而Fil Header/Fil Trailer关心的是记录页的头信息(4).
- 在页的头部和尾部之间就是用户记录和空闲空间,每一个数据页中都包含infimum和supremum这两个虚拟的记录(理解为占位符),infimum记录是比页中任何主键都要小的值,supremum是该页中最大的值(1)
- user Records就是整个页面中真正用于存放行记录的部分,而free space就是空余空间,他是一个链表的数据结构,为了保证插入和删除的效率,整个页面不会按照主键顺序对所有记录进行排序,他会自动从左侧向右寻找空白节点进行插入,行记录在物理存储上并不是按照顺序的,他们之间的顺序由next-record指针控制(2)
B+树在查找对应的记录时,并不会直接从树中找出对应的行记录,他只能获取记录所在的页,将整个页加载到内存中,再通过page directory中存储的稀疏索引和n-owned,next-record属性取出对应的记录,不过因为这个操作是在内存中进行的,所以通常会忽略这部分的耗时.
索引
索引的数据结构
InnoDB存储引擎在绝大多数情况下使用B+树建立索引,这个关系型数据库中查找最常用有效的索引,但是B+树索引并不能找到一个给定键对应的具体值,他只能找到数据行对应的页,然后数据库把整个页读入内存中,并在内存中查找具体的数据行.
B+树是平衡树,他查找任意节点所消耗的时间都是完全相同的,比较的次数就是树的高度.
聚集索引和辅助索引
B+树索引可以分为聚簇索引和辅助索引,聚簇索引中存放着一条行记录的全部信息,而辅助索引中只包含索引列和一个用于查找对应行记录的书签.
聚簇索引
innoDB存储引擎中的表都是使用索引组织的,也就是按照键的顺序存放,聚集索引就是按照表中主键的顺序构成的一颗b+树,并在叶子节点中存放表中的行记录数据.
当使用聚簇索引对表中的数据进行检索时,可以直接获得聚簇索引对应的整行记录数据所在的页,不需要进行第二次操作
辅助索引
数据库将所有的非聚簇索引都划分为辅助索引,辅助索引也是通过b+树实现的,但是他的叶子节点并不包含行记录的全部数据,仅包含索引中的所有键和一个用于查找对应记录的书签,在innoDB中,这个书签就是当前记录的主键
聚簇索引构成的b+树是数据实际存储的形式,而辅助索引只用于加速数据的查找,所以一张表上有多个辅助索引来提升性能.
锁
- 共享锁(读锁):允许事务对同一行数据进行读取
- 互斥锁(写锁)”允许事务对一条行数据进行删除或更新
在数据库中可以并行读,但是只能串行写,线程安全.
锁的粒度
无论是共享锁还是互斥锁其实都是对某一个数据行进行加锁,innoDB支持多种粒度的锁,就是行锁和表锁,为了支持多粒度锁定,innoDB存储引擎引入了意向锁(intention lock),意向锁是表级锁.
意向锁分两种
- 意向共享锁:事务想要在获取表中的某些记录的共享锁,需要在表上先加意向共享锁.
- 意向互斥锁:事务想要在获得表中的某些记录的互斥锁,需要在表上先加意向互斥锁.
意向锁不会阻塞全表扫描之外的请求,主要目的是为了表示是否有人请求锁定表中的某一行数据.
比如有人使用行锁对表中某一项进行修改时,另一个人需要对全表修改,就需要扫描每一行是否被锁定.有了意向锁,在进行某一行修改之前,先为表添加意向互斥锁,在添加行锁,另一个人就不需要扫描每一行了.
锁算法
- Record lock
记录锁,是加到索引记录上的锁.
比如last-name和age建立了索引,id是主键,
如果使用id或者last-name作为sql中where语句中的过滤条件,nameinnoDB就可以通过索引建立的b+树找到行记录并添加锁,如果使用first-name作为过滤条件,由于innodb不知道待修改记录具体存放的位置,也无法对将要修改哪条记录提前判断会锁定整个表. - gap lock 间隙锁:对索引记录中的一段连续区域锁,当使用类似
select * from users where id between 10 and 20 for update
时,就会阻止其他事物向表中插入id=15的记录,因为整个范围都被间隙锁锁定了
- next-key lock
他是记录锁和记录前的间隙锁的结合.next-key锁锁定的是当前值和前面的范围
当更新一条记录
select * from users where age=30 for update
innoDB不仅会在范围(21,30]上加next-key锁,还会在这条记录的后面范围(30,40]加间隙锁.
为了解决幻读的问题
innoDB和myisam区别和场景应用
区别
- 事务处理
myisam是非事务安全,innoDB是事务安全的
- 锁机制不同
myisam是表级锁,innoDB是行级锁 - select,update.delete操作
myisam:如果执行大量的select,myisam是更好的选择
innoDB:如果执行大量的insert或update,应该使用innoDB - 查询表的行数不同
select count() from table,myisam只要简单的读出保存好的行数,如果后面有where,两种表操作一样
innodb中不保存具体的行数,count需要扫描整个表 - 外键 myisam不支持外键,innodb支持
- myisam查找更快
innodb在做select时,要维护很多东西
- 数据块,innodb要缓存,myisam只缓存索引块
- innodb寻址要映射到块,再到行,myisam记录的是文件的offset,定位快
- innodb维护mvcc一致(多版本并发控制)
应用场景
myisam适合做count计算,插入不频繁,查询频繁,没有事物 innodb适合可靠性要求高,要求事务,更新和查询都频繁,行锁定多