1 Star 0 Fork 0

方温南/学习文档

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
MySQL 13.36 KB
一键复制 编辑 原始数据 按行查看 历史
方温南 提交于 2020-11-18 21:54 +08:00 . aaa
MySQL
InnoDB体系架构:
后台线程:
Master Thread:
负责将缓冲区的数据刷新到磁盘,包括脏页的刷新,合并插入缓冲,undo页的回收
IO Thread:
InnoDB1.0之前有四个write,read,insert buffer和log io thread,linux平台下IO thread的大小不能调整,在windows可以
可以通过innodb_file_io_threads参数调整大小
但是在innodb1.0之后舍弃了这个参数,read thread和write thread大小也提高到了4个,并且使用innodb_read_io_threads
和innodb_write_io_threads参数进行设置
Insert into select这个语句需要在表中加索引避免全表扫描
Btree+:
叶子节点存储数据
非叶子节点存储主键+指针
btree+树高度等于2的时候可以存两万多条数据
MySQL中一页有16KB,即16384字节,bigint为主键为8字节+指针的6字节,大概一个页可以存储1170组键值对,即代表有多少个叶子节点
假设1行数据1kb,大概1170*16行数据=18724,即一万多条数,树的高度等于3的时候大概可以存储1170*1170*16,即千万级数据
select * from t1 where b > 1 and c = 1;
InnoDB必须要有一个主键,如果没有,则会按照下列规则来生成:
1.查看表中是否有非空的唯一索引,有多个则选择第一个
这里有点感悟,不管什么软件系统,应用在得到多条数据时,都会选择第一条,不知道是否有什么理论
2.自动生成一个rowid,占用6字节
主键的选择是根据定义索引的顺序,而不是定义列的顺序,主键是根据索引定义,所以肯定得按照索引来,而不是定义列的顺序
select _rowid from sys_menu;
可以查看主键id为哪个字段,这个只能用于查看单个列为主键的情况,而不能查看多个列组成的主键
InnoDB逻辑存储结构:
所有数据逻辑的存放在一个空间中,叫表空间
1.表空间
表空间可以看做InnoDB存储逻辑结构的最高层,有一个默认的表空间ibdata1,所有数据都存放在这里面
可以通过innodb_file_pre_table来让每个表内的数据单独放在一个表空间
开启了innodb_file_pre_table时,存储的只是数据,索引,插入缓冲bitmap页,其他数据如undo,插入缓冲索引页
系统事务信息,二次写缓冲都存储在原来的共享表中
分为段,区,页
a.段
常见的段有数据段,索引段,回滚段
因为InnoDB存储引擎的数据是索引组织起来的,所以也可以说索引就是数据,数据就是索引
Btree+树中叶子节点即为数据,非叶子节点即为索引
对段的管理是由存储引擎完成的,我们没有必要去管理它
b.区
区是连续页组成的,大小为1M,每次申请4-5个区,默认情况下页为16KB,即一个区一共有64个页
innodb1.x版本开始引入了压缩页,可以将页压缩为2k,4k,8k.每个区的页大小也会随之发生变化.
可以通过innodb_page_size设置页的大小
这里还有个问题,设置了innodb_file_pre_table参数后,每个表大小为96KB
在段的开始有个32个页大小的碎片页,使用完之后才是连续64个连续页的申请,这样对一些undo或者小表可以开始时申请较小的空间
c.页,也叫block
同其他的数据库一样,innodb也有页的概念,默认大小16KB,InnoDB1.2.x之后可以通过参数设置页大小
若设置完成,则所有表的页大小都为16KB,除非通过mysqldump导入和导出操作来产生新的库
页类型:
数据页
undo页
系统页
事务数据页
插入缓冲位图页
插入缓冲空闲列表页
d.行
InnoDB存储引擎是面向列的,也就是说数据是按照行存放的,最多允许7992行数据
2.行记录格式
a.Compact
MySQL5.0引入
变长字段长度列表|NULL标志位|记录头信息|列1数据|列2数据|...
变长字段长度列表:
按照列的顺序逆序存放,长度为:
a.如果长度小于255字节,用1字节表示
b.如果长度大于255字节,用2字节表示
长度最大不超过2字节,这是因为varchar类型最大长度为65535
NULL标志位:
记录是否有NULL值
1字节记录,实际存储不占用任何空间
记录头信息:
固定占用5字节
各标志位意义可去这里查看
https://images2015.cnblogs.com/blog/990532/201701/990532-20170116113042192-830819397.png
除了定义这些之外,还有两个隐藏列
事务ID和回滚指针列,分别为6字节和7字节,如果没有定义主键还有一个生成的主键RowID
固定长度char字段,如果没有存够则会用0x20来填充数据
b.Redundant
MySQL5.0之前使用,支持是为了兼容
字段长度偏移列表|记录头信息|列1数据|列2数据|列3数据|...
字段长度偏移列表:
按照列的顺序逆序存放
a.如果长度小于255字节,用1字节表示
b.如果长度大于255字节,用2字节表示
记录头信息:
6字节
有个n_fields为10位,正好解释了一行最多支持的列为1023
具体详见:
https://images2015.cnblogs.com/blog/990532/201701/990532-20170116121931974-1300710619.png
c.行溢出数据
InnoDB可以将一些数据存储在真正的数据页面之外,一般认为BLOB,LOB之类的大数据会存储在数据页面之外,但是这个理解有点偏差
VARCHAR也可以将数据存储为行溢出数据
VARCHAR可以支持65535,这个单位为字节
如果表的字符集为utf8,则只能存储21845(utf8)或者32767,而这里为字符的长度
官方手册中说的65535是指的所有列的总和,即一行中所有的varchar列的总和不能超过65535
e.Compressed和Dynamic行记录格式
外键:
InnoDB引擎才支持外键
外键列和参照列必须要有相似的数据类型
MySQL的版本链和readview
MySQL:
存储引擎是基于表的,而不是数据库
MySQL基于多版本并发控制(MVCC)来获得高并发性能,并且实现了四种隔离级别,同时使用next-key locking来避免幻读
还提供了插入缓存,二次写,自适应hash索引,预读
COUNT(*)和COUNT(COLUMN)区别,*不管列中是否包含null,column不会将包含null算入
内存:
1.缓冲区
缓冲池中页的大小默认为16KB
show engine innodb status;
show variables like "%innodb_buffer%";
2.LRU List,Free List,Flush List
InnoDB引擎对LRU做了一些改变,加入了midpoint位置
show variables like "innodb_old_blocks_pct"; 默认37
默认为LRU列表尾端37%的位置,在midpoint之后的称为old列表,之前的称为new列表,可以理解为new列表中是最
活跃的数据
猜测原因:如果某个sql只查了一次,但是后续没用到了就没必要直接放到LRU列表最前面
show variables like "innodb_old_blocks_time"; 默认1000
表示读取到mid位置后多久会被放入LRU列表的热端
LRU页刚开始是空的,在启动后会从Free List取的页放入LRU List,从old到new的过程称为page made young
而因为innodb_old_blocks_time影响而没有从lod到new的称为page not made young
在LRU中的页被修改之后称该页为脏页,这时数据库会通过checkpoint机制将数据刷回磁盘,而Flush List中的页即为脏页列表
3.重做日志缓冲
InnoDB的内存区域除了缓冲池之外,还有重做日志缓冲
show variables like "%innodb_log_buffer_size%"; 默认8MB
8MB大小足以满足需要,在三种情况会将重做日志缓冲刷新到磁盘重做日志文件
a.Master Thread每1秒刷新一次
b.每个事务提交时
c.重做日志缓冲区大小小于1/2
缓冲区的目的是为了协调CPU与缓冲的鸿沟
本质来说,缓冲区的作用就是协调速度不一致的两方
CheckPoint:
InnoDB有两种checkpoint:Sharp Checkpoint、Fuzzy Checkpoint
B+Tree:
索引占用8B,而下一级指针索引占用6B,共14B,而MySQL一个页一个16kb,16*1024/14~=1170
MySQL的SHOW ENGINE INNODB STATUS命令结果解析
https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html
导入InnoDB表
1.初始条件
a.innodb_file_per_table必须启用
b.表空间的页面大小必须与目标MySQL服务器实例的页面大小匹配。 InnoDB页面大小由innodb_page_size变量定义,该 变量在初始化MySQL服务器实例时配置
c.如果表具有外键关系,则 foreign_key_checks必须在执行前禁用它DISCARD TABLESPACE。另外,应在同一逻辑时间点导出所有与外键相关的表,因为
ALTER TABLE ... IMPORT TABLESPACE这不会对导入的数据施加外键约束。为此,请停止更新相关表,提交所有事务,获取表上的共享锁,然后执行导出操作
d.从另一个MySQL服务器实例导入表时,两个MySQL服务器实例都必须具有通用状态(GA),并且必须具有相同的版本.否则,必须在将表导入到的同一MySQL服务器实例上创建表.
e.如果表是通过在DATA DIRECTORY语句中指定子句在外部目录中创建的CREATE TABLE,则在目标实例上替换的表必须使用相同的DATA DIRECTORY 子句定义。如果子句不匹配,则报告架构不匹配错误。要确定源表是否用DATA DIRECTORY子句定义,请使用 SHOW CREATE TABLE查看表定义
f.如果ROW_FORMAT未在表定义中明确定义或 ROW_FORMAT=DEFAULT使用选项, innodb_default_row_format 则源实例和目标实例上的设置必须相同。否则,当您尝试导入操作时,将报告架构不匹配错误。使用 SHOW CREATE TABLE检查表定义。使用SHOW VARIABLES检查 innodb_default_row_format设置
MySQL选择数据类型原则
1.越小的一般越好
2.简单
3.尽量避免null
MySQL的VARCHAR类型是不定长存储,但是有例外,如果表参数有ROW_FORMAT=FIXED的话会定长存储
VARCHAR类型使用额外的两个字节存储长度,如果小于255是1,大于的话就是使用2字节
CHAR的存储因为是定长的不需要记录长度,如果只是存储Y/N之类的可以使用CHAR,CHAR只存储一个字节,而VARCHAR要两个字节
与VARCHAR和CHAR相同的还有BINARY和VARBINARY,只是存储的是字节码,填充也不一样,会填充\0
BLOB和TEXT
如果BLOB和TEXT的长度太长的话会使用外部空间区域存储,在每个值会有个1-4字节存储一个指针,指向一个地址
两者唯一的不同时BLOB存储二进制数据,没有排序规则和字符集,而TEXT又排序规则和字符集
DATETIME和TIMESTAMP
TIMESTAMP只能使用到2038年.MySQL提供了函数FROM_UNIXTIME()和UNIX_TIMESTAMP()函数转换Unix时间戳和时间
BIT
在MySQL5.0和更新版本中,这个是一个独立的数据类型.
最长64位
标识列
尽量使用默认的int
如果使用字符串类型,例如UUID,则可以使用UNHEX()函数转换为16字节的数字,并且存储在BINARY(16)中,检索时
可以通过HEX()方法来格式化为十六进制格式
特殊数据类型
例如ip地址,可以使用函数INET_ATON()和INET_NTOA()进行转换
数据库范式
第一范式:属性的原子性
第二范式:属性完全依赖于主键
第三范式:
第三范式要求一个数据库表中不包含已在其他表中已包含的非主关键字信息, 例如 存在一个课程表,课程表中有课程号(Cno),课程名(Cname),学分(Ccredit),那么在学生信息表中就没必要再把课程名,学分再存储到学生表中,这样会造成数据的冗余, 第三范式就是属性不依赖与其他非主属性,也就是说,如果存在非主属性对于码的传递函数依赖,则不符合第三范式
数据库:表很大,性能下降?
增删改查慢
查询
1.1个或者少量依然很快
2.并发大的时候会受硬盘带宽影响速度
数据在磁盘和内存体积不一样,因为磁盘没有指针这些东西
两个基础设施
1.冯诺依曼体系的硬件
2.以太网,TCP/IP的网络
架构师
1.架构选型
2.架构对比
信息法则
关系数据库中的所有信息都用唯一的一种方式表示——表中的值
保证访问法则
依靠表名、主键值和列名的组合,保证能访问每个数据项(这一条其实是数据库表的可读性约束)
空值的系统化处理
支持空值(NULL),以系统化的方式处理空值,空值不依赖于数据类型。
数据的物理独立性
不管数据库的数据在存储表示或访问方式上怎么变化,应用程序和终端活动都保持着逻辑上的不变性。
数据的逻辑独立性
当对表做了理论上不会损害信息的改变时,应用程序和终端活动都会保持逻辑上的不变性。
数据完整性的独立性
专用于某个关系型数据库的完整性约束必须可以用关系数据库子语言定义,而且可以存储在数据目录中,而非程序中。
分布独立性
不管数据在物理是否分布式存储,或者任何时候改变分布策略,RDBMS的数据操纵子语言必须能使应用程序和终端活动保持逻辑上的不变性
MySQL索引失效的原因
1.使用!=或<>等导致失效
2.类型不一致导致的索引失效
3.使用函数导致的索引失效
4.运算符导致的索引失效,例如对列进行了(+,-,*,/,!), 那么都将不会走索引
5.or引起的索引失效
6.模糊搜索导致的索引失效
7.NOT IN、NOT EXISTS导致索引失效
1.innodb支持事务,myisam不支持
2.innodb有外键,myisam没有
3.innodb支持表锁和行锁,myisam支持表锁
4.索引存储的叶子节点的数据不同
5.count(*)myisam比较快,不能带任何查询条件
OLTP:联机事务处理过程
OLAP:联机分析处理过程
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Java
1
https://gitee.com/nanwenfang/learning_documents.git
git@gitee.com:nanwenfang/learning_documents.git
nanwenfang
learning_documents
学习文档
master

搜索帮助