众所周知,innodb主键聚集索引,index organized table
那么没有主键的时候,找非空唯一索引,或者自动创建6byte大小的指针,但是它自动创建的索引你是没办法拿来做主键过滤的;
非空唯一索引如果有多个,按照“定义”顺序选择第一个
select _rowid from talbe; 其中_rowid帮你看到主键值,当然了,如果主键为多个列,这招不好使,你不如show create talbe ~~~
innodb的逻辑存储组织形式为: tablespace-->segement-->extent-->page-->row
tablespace
这个tablespace主要是ibdata1,就是这个名字,你肯定能找到,默认情况下,就这一个文件,所有表信息都在里面了
但是,如果你innodb_file_per_table on,那么文件就多了,名字往往是ib_logfile*,因为你看名字也知道,这是让每个表单独存放,不过这时候ibdata1还是有重要作用,它叫共享表空间
那么idbdata1此时什么作用呢?
ib_logfile*(每个表自己的空间):数据(跟主键索引一块儿),索引(辅助索引那些),插入缓冲bitmap
ibdata1(共享表空间) :undo信息,插入缓冲索引页,系统事务信息,double write buffer等
尤其是undo信息放共享表里,这个表分分钟大小会变化,因为你要写undo日志啊
这里插播一条:插入缓冲的介绍
主键聚集索引你懂的,索引跟数据一起放的,那么其他索引只好放到索引页去了;
那么我要往辅助索引页里面写东西,这些索引页我不能全放在内存中,如果每个要被写入的索引页我都主动把它读进内存,这代价太大;
于是我们等着这些索引页在内存的时候再往里写好了,于是我们搞一个buffer,插入的东西放里面等着,一旦有需要被写入的索引页被读入内存了,我们趁机把buffer里的东西写进去,你说这多好,就是这样;
但是注意如果是唯一非空索引页,那你就必须检查你要插入的索引是不是唯一的,这时候就不能用插入缓冲这一招了
segement
数据段:聚簇索引嘛,数据段就是B+树的叶子节点咯,放的都是数据
索引段:非叶子节点放这边,原来B+树的非叶子就是索引
回滚段:后面再说
extent
这东西中文叫“区”,好多凑一块叫一个segment;extent里面放了好多page
extent的大小永远是1M;innodb为了保证extent是连续的,一般申请的时候都是申请4~5个
对于innodb,page默认大小是16K,参数innodb_page_size可以改默认,变成4K,8K这样;
以下是一个有意思的实际应用情况:
用了innodb_file_per_talbe之后啊,你创建一个表,默认大小是96K,为什么不直接给一个extent这样就1M了呢?
这是innodb为了节省空间做的一个策略,就是你搞个小表(砸)或者undo这类的小段,分给你1M太浪费了;所以innodb准备了一些碎片page,你用一个段之前,我先给你32个碎的page,这些要是不够用了,我就知道你不是个小表了,那么我就给你1M用
不过实际过程中,32个page似乎算的是“数据segment"有多少,《MySQL技术内幕》中做了一个实验,大概是数据段的页超过32个时,此时碎片页用完,然后开始用连续的64个页进行分配,此时查看表的大小,应该是1M的整数倍了
page
对于页的大小,新版本的innodb是可以进行设置的,但是一旦设置之后则不能更改,表中所有页的大小均为所设的值,除非通过mysqldump进行导入导出操作
页类型有:数据页,undo页,系统页,事务数据页,插入缓冲位图页,插入缓冲空闲列表页,未压缩的二进制大对象页,压缩的二进制大对象页
row
innodb引擎存储是面向row的,也就是数据是一行一行存储的,也有按照列存储的引擎,但是我们不去管,只看innodb
实际上innodb存放行数据有两种格式compact和redundant,但是后者只是为了兼容旧版本,老东西了没意思
compact存储方式长下图这个样
我们想要高效地存储数据,什么是高效?就是一个页里放尽可能多的数据