mysql数据库知识整理

2023-11-10

目录

InnoDB和MyISAM引擎常见区别

索引的基本原理

聚簇索引和非聚簇索引的区别

索引的数据结构及优势

索引的设计原则

innerdb主键索引自增的原因以及联合索引最左原则 

锁的类型有哪些

MySQL执行计划

InnoDb引擎的执行计划内容

IS NULL是否走索引

事物的基本特性和隔离级别

慢查询及优化

分库分表 

ACID是靠什么保证的

Innodb是如何实现事物的

 MVCC是什么

MySQL主从同步原理

MyISAM 和INNODB的区别

简述MySQL中索引类型及对数据库性能的影响

如何实现分库分表     

存储拆分后如何解决唯一主键问题     

雪花算法原理

为什么尽量三表一下join关联

为何禁止外键约束


InnoDB和MyISAM引擎常见区别

事务方面:InnoDB支持事务,MyISAM 不支持事务。这是MySQL将默认存储引擎从MyISAM变成InnoDB的重要原因之一.
外键方面:InnoDB支持外键,MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败
索引层面:InnoDB是聚集(聚簇)索引,MyISAM 是非聚集(非聚簇)索引。MyISAM支持FULLTEXT类型的全文索引,InnoDB不支持FULLTEXT类型的全文索引,但是InnoDB可以使用sphinx插件支持全文索引,并且效果更好。
锁粒度方面:InnoDB最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是MySQL将默认存储引擎从MyISAM变成InnoDB的重要原因之一。
硬盘存储结构:MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。
●frm文件存储表的定义。
●数据文件的扩展名为. MYD (MYData)。
●素引文件的扩展名是. MYI (MYIndex)。
Innodb存储引擎存储数据库数据,一共有两个文件(没有专门保存数据的文件):
●Frm文件: 表的定义文件。
●Ibd文件: 数据和索引存储文件。数据以主键进行聚集存储,把真正的数据保存在叶子节点中。

索引的基本原理

索引用来快速地寻找那些具有特定值的记录。如果没有索引,-般来说执行查询时遍历整张表。    索引的原理:就是把无序的数据变成有序的查询

    1.把创建了索引的列的内容进行排序

    2.对排序结果生成倒排表

    3.在倒排表内容上拼上数据地址链

    4.在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

聚簇索引和非聚簇索引的区别

都是B+树的数据结构

  • 聚簇索引:将数据存储和索引放在一起、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻的存放在磁盘上的。
  • 非聚簇索引:叶子节点不存储数据,存储的是数据行地址,也就是说根据索引查找到数据行的位置再去磁盘查找数据,索引和数据是分开存储的。这就有点类似一本书的目录,比如要找到第三章第一节,那就现在目录里面查找,找到对应的页码后再去对应的页码看文章。

优势
1、查找通过聚簇索引可以直接获取到数据,相比非聚簇索引需要第二次查询(覆盖索引除外,只要索引字段)效率要高
2、聚簇索引对范围查询的效率很高,因为其数据是按照大小排列的
3、聚簇索引适合用在排序场合,非聚簇索引不适合。
劣势
1、维护索引代价大,特别是插入新行或者主键被更新导致要分页的时候。建议在大量插入新行后,选择负载较低的时间段,通过OPTIMIZE TABLE优化表
2、表因为使用UUID作为主键,使数据存储稀疏,这就会出现聚簇索引有可能会比全表扫面更慢,所以建议使用int的auto_increment作为主键。
3、如果主键比较大的话,那辅助索引(除主键外的)将会变得更大,因为辅助索引的叶子节点存储的是主键值,过长的主键值,会导致非叶子节点占用更多的物理空间

InnoDB中一定有主键,主键一定是聚簇索引,不手动设置,则会使用一个unique索引作为主键索引,没有unique索引,则会使用数据库内部的一个隐藏行id来当作主键索引。在聚簇索引之上创建的索引称为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引,前缀索引、唯一索引。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。

MyISM使用的是非聚簇索引,没有聚簇索引,大数据量的全表扫描还是有优势的。

辅助索引和非聚簇索引的不同是,非聚簇索引上存储的是数据行的地址,辅助索引存的是主键值

索引的数据结构及优势

索引的数据结构和具体存储引擎的实现有关,再MySQL中,使用较多的索引有Hash索引,B+树索引等InnDB存储引擎的默认索引实现为B+数索引,对于哈希索引来说,底层的数据结构就是哈希表,因此,在绝大多数需求为单条记录查询的时候,可以选择哈希索引查询性能最快,其余大部分场景建议选择B+Tree索引

B+树:

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过一,而且同层级的节点间有指针相互链接,在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动效率非常高,因此,B+树索引被广泛应用,数据库文件等场景

很明显能看到,只有叶子节点存储记录地址。非叶子节点层级少了 data 域后节省了空间,可以存储更多的索引,优势自然而然的就体现出来了。

即:B+树在同一层级的索引页中存储的索引个数比B树更多,并大大减少了 IO。

并且他还有个更加关键的特性,叶子结点是一个排好序的链表结构,每一个节点指向它下一个节点的地址。 

哈希索引:

哈希索引就是采用一定的哈希算法,把剑值换算成新的哈希值检索时,不需要类似B+树那样从根节点到叶子节点逐级查找,只需要一次哈希算法即可立即定位到相应的位置,非常快,如果是等值查询,那么,哈希索引明显有优势,因为只要经过一次算法即可找到相应的,前提是键值都是唯一的,如果键值不唯一,就需要先找到该建所在位置,然后再根据链表往后扫描,直到找到相应的数据

如果是范围查询检索,这时候哈希索引就毫无用武之地,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围检索,哈希索引也没办法利用索引完成排序以及like‘xxx%’这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询)哈希索引也不支持多列联合索引(将多个字段设置为一个索引)最左匹配规则;在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在哈希碰撞问题。

索引的设计原则

查询更快、占用空间更小
1、适合索引的列是出现where子句中的列,或者连接子句中指定的列。
2、基数较小的表数据量小,索引效果较差,所以数量较小的表没有必要建立索引
3、使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词超出索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。
4、不要过度使用索引。索引需要额外的磁盘空间,并降低写操作性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
5、定义有外键的数据列一定要建立索引。

---------------------------不适合建索引的情况-----------------------------
6、更新频繁字段不适合创建索引
7、若是不能有效区分数据的列不适合做索引(如性别:男、女和未知,最多也就三种,区分度太低)
8、尽量扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可(建联合索引而不是再将b作为索引)。
9、对于那么查询中很少涉及的列,重复值比较多的列不要建立索引。

innerdb主键索引自增的原因以及联合索引最左原则 

innerdb主键索引的叶子节点,data存放的是索引所在行的其他列数据,而非索引所在行的其他列地址;非主键索引的叶子节点data存放的是所在行的主键,所以,使用二级索引时,是先查到该索引所在行的主键,再到主键索引中进行查找,也称为回表。如果不建主键,数据库也会内部维护一个rowId做为索引组织B+tree,主键用自增整型效率高查询快,而字符串是逐一比对。自增的主键在插入时也节省性能,减少数据结构算法上的消耗,因为自增只是向后依次增加,减少分裂。mysql数据库索引类型也有Hash而且查询效率很高,但是不适用范围查找。联合索引最左原则的原理是取决于联合索引树结构的,如abc三列,第一列a列区分出大小排好序后其余两列就不用继续对比和排序了。如果不遵循最左原则,无法保证后面列索引的顺序,要挨个遍历比对,相当于全表扫描了。在第前一列相同的情况下,后一列才有序。
如果where条件:where age= ?and name =? 也是会走索引的因为优化器会优化成最左匹配原则

锁的类型有哪些

基于锁的属性分类:共享锁、排他锁
基于锁的力度分类:页级锁(BDB引擎)、表级锁(InnoDb、Myisam)、行级锁(InnoDb)、记录锁、间隙锁、临键锁(next-key lock)
基于锁的状态分类:意向共享锁、意向排他锁

  • 共享锁(Share Lock)

共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,知道所有的读锁释放之后,其他事务才能对进行加写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复都的问题。

  • 排他锁

排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,知道该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改的时候,不允许其他人同时修改,也不允许其他人读取。避免了出现脏数据和脏读问题。

  • 表锁

表锁是指上锁的时候锁住的时整个表,当下一个事务访问该表的时候,必须等待前一个事务释放了锁才能进行对表进行访问。
特点:粒度大,加锁简单,容易冲突

  • 行锁

行锁是指上锁的时候锁住的是表的某一行或者多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可以正常访问。
特点:粒度小,加锁比表锁麻烦,不容易起冲突,相比表锁并发度要高

  • 页锁

页级锁时MYSQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级锁冲突少,但速度慢。所以取了折中的页级锁,一次锁定一个页的大小(默认16K)
特点:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般

  • 记录锁

记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。
精准条件命中,并且命中的条件字段是唯一索引
加了记录锁之后可以避免数据在查询的时候被修改造成重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。

  • 间隙锁

属于行级锁中的一种,间隙锁是在事务加锁后,锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙会形成一个区间,遵循左开右闭。
范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在可重复读的事务隔离级别中。
触发条件:防止幻读问题

  • 临键锁

也属于行锁的一种,并且他是InnoDb的行锁默认算法,总结来说,他就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙也锁住,把相邻的下一个区间锁住
触发条件:范围查询命中,查询命中索引
结合记录锁和间隙锁的特点,临键锁避免了在范围查询时出现脏读、重复度、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。

如果当事务A加锁成功之后就设置一个状态告诉后面的人,已经有人对表里的行加了排他锁了,你们不能对整个表加共享锁或者排他锁;额,那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁,避免了对整个索引树的每个节点扫描是否加锁,这个状态就是意向锁。

  • 意向共享锁

当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁

  • 意向排他锁

当一个事务试图对整张表加排他锁之前,首先需要获得这个表的意向排他锁。

MySQL执行计划

执行计划是Mysql如何执行一条sql语句,包括sql查询顺序、是否使用索引、索引信息、查询命中率等信息。
基本语法

explain select * form ····

InnoDb引擎的执行计划内容

id:是一个有顺序的编号,是查询的顺序号,有几个select就显示几行。是按select出现的顺序增长的。id列的值越大执行优先级越高,越先执行,id列的值相同则从上往下执行,id列为null的最后执行由一组数字组成,表示一个查询中各个子查询的执行顺序;

id相同执行顺序由上之下
id不同,id值越大优先级越高,越先被执行
id为null时表示一个结果集,不需要使用它查询,常出现在包含union等查询语句中

selectType:表示查询中每个select字句的类型

SIMPLE:表示此查询不包含union查询或子查询
PRIMARY:表示此查询是最外层的查询(包含子查询)
SUBQUERY:子查询中的第一个select
UNION:表示此查询时union的第二或随后的查询
....

table: 表示该语句查询的表

type:优化sql的重要字段,也是我们判断sql性能和优化程度重要指标。他的取值范围:

1、const(常量):通过索引一次命中,匹配一行数据
2、system:表中只有一行记录,相当于系统表,比const效率更高
3、eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配(有可能回表)
4、ref:非唯一性索引扫描,返回匹配某个值的所有(有可能回表)
5、range:指检索给定范围的行多个索引,使用一个索引来选择行,一般用于between、<、>
6、index:只遍历索引树。会遍历所有索引
7、all:表示全表扫描。没走索引
执行效率:all<index<range<ref<eq_ref<const<system

possible_keys:可能使用的索引,不一定使用。查询涉及到的字段上若存在索引,则该索引将被列出来。

key:显示mysql查询中实际使用的索引,若没有使用索引,结果为null

key_len :索引长度在联合索引中比较有意义

ref:命中索引字段名,走常量打印const

rows:mysql查询查询优化器根据统计信息估算该sql返回结果集需要扫描读取的行数,这个值相当重要,索引优化之后,扫描读取的行数越多,说明索引设置不对,或者字段传入的类型之类的问题,说明需要进行优化

filtered:返回结果的行数占需要读取的行(rows)的百分比,百分比越高,说明需要查询到数据越准确。

extra

1、using filesort:表示mysql对结果集进行外部排序,不能通过索引顺序达到排序效果。一般有using_filesort都建议优化去掉,因为这样的查询cpu资源消耗大,延时长。
2、using index:覆盖索引扫描,表示查询在索引树中就可查找到所需数据,不用扫描表数据文件,往往说明性能不错
3、using temporary:查询有使用临时表,一般出现于排序,分组和多表join的情况,查询效率不高,建议优化。
4、using where:sql使用了where过滤,效率较高。 

IS NULL是否走索引

select * from t where name is null   或 is not null
建表时索引列(name列为例)不能为空时都不走索引,但是如果是select name 那么走覆盖索引
name列可为空时是走索引的
但是为何大众误解认为is null、is not null、!=这些判断条件会导致索引失效而全表扫描呢?
导致索引失效而全表扫描的情况通常是因为一次查询中回表数量太多。mysql计算认为使用索引的时间成本高于全表扫描,于是mysql宁可全表扫描也不愿意使用索引。使用索引的时间成本高于全表扫描的临界值可以简单得记忆为20%左右。
也就是如果一条查询语句导致的回表范围超过全部记录的20%,则会出现索引失效的现象。而is null、is not null、!=这些判断条件经常会出现在这些回表范围很大的场景,然后被人误解为是这些判断条件导致的索引失效。复现索引失效,只需要使回表范围超过全部记录的20%,如插入1000条非null记录。此时表中一共有1003条记录,其中只有1条记录的name值为null。那么is null判断语句导致的回表记录只有1/1003不会超过临界值,而is not null判断语句导致的回表记录有1002/1003远远超过临界值,将出现索引失效的现象。
is null依然正常使用索引,而is not null如预期由于回表率太高而宁可全表扫描也不使用索引。

事物的基本特性和隔离级别

事务的基本特性ACID分别是:
原子性指的是一个事务中的操作要么都成功,要么都失败。
一致性指的是数据库总是从一个一致性状态转移到另外一个一致性状态。比如A转账给B100块钱,假设A只有90块,支付之间我们数据库里面的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏了约束,因此事务不能成功,这里我们说事务提供了一致性的保证。
隔离性指的是一个事务的修改在最终提交之间,对其他事务是不可见的
持久性指的是一旦事务提交,所作的修改就会永远保存在数据库中

隔离性有四个隔离级别,分别是:

  • read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。

本来应该读取到id=1的用户age应该是10,结果读取到了其他事务还没有提交的事务,读取结果age=20,这就是脏读,重点是修改

  • read commit 读已提交,两次读取结果不一致,也叫做不可重复度

读已提交解决了脏读问题,他只会读取已经提交的事务
用户A开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里面查询到不同的结果叫做不可重复读。

  • repeatable read 可重复读,这是mysql的默认级别,就是每次读取结果都一样,但是有可能产生幻读。

幻读的重点在于新增或删除 (数据条数变化)同样的条件, 第1次和第2次读出来的记录数不一样目前age为10的有10人。 
事务1,读取所有age为10的。共读取10条记录 。这时另一个事务向表中插入了一条记录,age也为10
事务1再次读取所有age为10的记录。共读取到了11条记录,这就产生了幻读

  • serializable 串行化,一般不会使用,他会给每一行读取的数据加锁,会导致大量超时和锁竞争的问题。

慢查询及优化

在业务系统中,除了使用主键进行查询,其他的都会在测试库上测试其耗时。

慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是load了不需要的数据列select *?还是数据量太大?

所以优化也是针对这三个方向来的:

  • 首先分析语句,看看是否load了额外的数据列,可能是查询了多余的行并且抛弃掉了(使用select * ),也可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
  • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引
  • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

分库分表 

分库:是为了解决数据库连接资源不足问题,和磁盘IO的性能瓶颈问题。
垂直:大拆成小,基于列拆分按业务拆分,拆分的是结构
水平:例如用户表横向按照地理区域分, 如果有用户请求过来的时候,先根据用户id路由到其中一个用户库然后再定位到某张表。根据id取模,比如: id=7, 有4张表则7%4=3, 模为3,路由到用户表3。给id指定一个区间范围,比如: id的值是0-10万,则数据存在用户表0, id的值是10-20万,则数据存在用户表1。还有就是一致性hash算法。拆分的是数据。
分表:是为了解决单表数据量太大,sq|语句查询数据时,即使走了索引也非常耗时问题。此外还可以解决消耗cpu资源问题。
垂直:字段多数据量大

分库分表:可以解决数据库连接资源不足、磁盘lO的性能瓶颈、 检索数据耗时和消耗cpu资源等问题。

用户并发量很大,但是需要保存的数据量很少,这时可以只分库,不分表。
用户并发量不大,但是需要保存的数量很多,这时可以只分表,不分库。
用户并发量大,并且需要保存的数量也很多时,可以分库分表。

场景:订单数据库拆分基于userid ?orderid?
分情况:前端(userid我的订单订单详情)后端:小二(业务非常的复杂可能很难实现)管理员(当天的订单数月业务
前端用户多: userid(访问比较多数据非常及时QPS很高)互联网
后端用户多:传统系统

分库分表带来的问题:
1、分布式事务acid
2、跨库join查询
3、分布式全局唯ID
4、开发成本高
用来解决上述问题的开源框架(start也有解决):
jdbc直连层分片(应用层):在内存中的,性能高、支持多种数据库
shardingsphere、tdd1 
proxy代理层分片:跨进程的。跨语言、开发成本低、支持同一种数据库
mycat、mysql -proxy (atlas 360)

ACID是靠什么保证的

A 原子性 由undo log日志保证,它记录了需要回滚的日志信息,事务回滚是撤销已经成功执行的sql
C 一致性 由其他三大特性保证、程序代码要保证业务上的一致性
I 隔离性 由MVCC来保证
D 持久性 由内存+redo log来保证,mysql修改数据同时在内存和redo log记录这次操作,宕机的时候可以从redo log 恢复。

InnoDb redo log 写盘 ,InnoDB事务进入prepare状态。
如果前面prepare成功,binlog写盘,再继续将事务日志持久化到binlog,如果持久化成功,那么InnoDb事务则进入commit状态。(在redo log里面写一个commit记录)

确保事务执行成功的一个重要判断指标就是 在redo log中此事务是否有commit记录。

redolog刷盘会在系统空闲时进行。

Innodb是如何实现事物的

Innodb通过Buffer Pool、LogBuffer、Redo Log、Undo Log来实现事物,以一个update语句为例:

1.InnoDB在收到一个update语句后,会先根据条件查找到数据所在的页,并将该页缓存在Buffer Pool中

2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据

3.针对update语句生成一个ReadLog对象,并存入LogBuffer中

4.针对update语句生成undolog日志,用于事物回滚

5.如果事物提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool所修改的数据页持久化到磁盘中。

6.如果事物回滚则利用undolog日志执行回滚。

 MVCC是什么

多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同事务会话看到自己特定版本的数据,使用版本链。

MVCC只在READ COMMITTED(不可重复读) 和 REPEATABLE READ(可重复读) 两个隔离级别下工作。其他两个隔离级别和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。

事务版本号trx_id:事务ID(也每开启一个事务,我们都会从数据库中获得一个就是事务版本号),这个事务ID是自增长的,通过ID大小,我们就可以判断事务的时间顺序。是一个隐藏列

行记录的隐藏列roll_pointer:每次对某条聚簇索引记录有修改的时候,都会把老版本写入undo日志中这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息(插入操作的undo日志没有这个属性因为没有上一个版本)InnoDB的叶子端存储了数据页,数据页中保存了行记录,而在行记录中有一些重要的隐藏字段,如下所示:

db_row_id:隐藏的行ID,用来生成默认的聚簇索引。如果我们创建数据表的时候没有指定聚簇索引,并且没有唯一索引,这时候InnoDb就会使用这个隐藏ID来创建聚簇索引,采用聚簇索引的方式可以提升数据的查询效率。
db_trx_id : 操作这个数据的事务ID,也就是最后一个对该数据进行插入或更新的事务ID。
db_roll_ptr:回滚指针,也就是指向上一个事务的undo log 日志记录 。这样就形成了版本链。

已提交读和可重复读的区别就在于他们生成ReadView的策略不同

当执行查询sq时会生成一致性Rread-view. 它由执行查询的时所有未提交事务id数组(数组里重最小的id为min id)和已创建的最大事务id (max id)组成,查询的数据结果需要跟read-view做比对从而得到快照结果
版本链比对规则:
1.如果落在绿色部分( trx_id<min_id), 表示这个版本是已提交的事务生成的,这个数据是可见
的:
2.如果落在红色部分( trx_id>max_id),表示这个版本是由将来启动的事务生成的。是肯定不可
见的:
3.如果落在黄色部分(min_id <=trx_id< = max_id).那就包括两种情况
   a若row的trx id在数组中,表示这个版本是由还没提交的事务生成的,不可见,如果当前自己的事务那么是可见的;
   b.若row的trx id不在数组中,表示这个版本量已经提交了的事务生成的,可见
对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx id.同时在该条记录的头信息(record header)中的(deleted flag)标
记位写上true,来表示当前记录已经被删除。在查询时按照上面的规则查到对应的记录如果
delete fLag标记位为true,意味着记录已被删时,则不返回数据。

开始事务时创建readview,readview维护当前所有活动的事务id,即未提交的事务id,排序生成一个数组访问数据,以及获取数据中最大事务id,然后nudo log中trx_id逐条和对比readview:

如果在readview的左边(比readview都小),可以访问(在左边意味着该事务已提交)

如果在readview的右边(比readview都小)或者就在readview中则不可访问,获取roll_pointer取上一版本更新对比(在右边意味着,该事务在readview生成之后出现,在readview中意味着该事务还未提交)

已提交读的隔离级别下的事务在每次查询开始都会生成一个独立的readview,而可重复读隔离级别则在第一次度的时候生成一个readview,之后的读都是复用之前的readview

这就是MySQL的MVCC通过版本链,实现多版本可并发读-写,写-读。通过readview生成策略的不同实现不同的隔离级别。

ReadView是如何工作的
在mvcc机制中,多个事务对同一个记录进行更新会产生多个历史快照,这些历史快照保存在Undo log里。如果一个事务要查询这些记录,需要读取哪个版本的历史数据呢?这时就需要用到Read View了,它帮我们解决了行的可见性问题。Read View保存了当前事务开启时所有活跃(还没有提交)的事务列表,换个角度可以理解为Read View保存了不应该让这个事务看不到的其他食事务ID列表

在Read View中有几个重要属性

trx_ids:系统当前正在活跃的事务ID集合
low_limit_id:活跃的事务中最大的事务ID
up_limit_id:活跃的事务中最小的事务ID
creator_trx_id:创建这个Read View的事务ID

假设当前有事务creator_trx_id想要读取某行记录,这个行记录的事务id为trx_id,那么会出现以下几种情况。

1、如果 trx_id < 活跃的最小事务ID(up_limit_id),也就是说这个行记录在这些活跃事务创建之前就已经提交了,那么这个行记录对该事务是可见的。

2、如果 trx_id > 活跃的最大事务ID(low_limit_id),这说明该行记录在这些活跃的事务创建之后才创建,那么这个行记录对当前事务不可见。

3、如果 up _limit_id < trx_id < low_limit_id ,说明该行记录所在的事务 trx_id在目前creator_trx_id这个事务创建的时候,可能还处于活跃状态,因此我们需要在trx_ids集合中进行遍历,如果trx_id存在于活跃集合中,证明这个事务还处于活跃状态,不可见。否则,不存在于活跃集合中,说明事务已经提交了,该行记录可见。

了解了这写概念之后,我们看一下当查询一条记录的时候,系统如何通过多版本并发控制技术找到它:

1、首先获取事务自己的版本号,也就是事务ID;
2、获取Read View
3、查询得到的数据,然后与Read View中的事务版本号进行比较。
4、如果不符合Read View规则,就需要从Undo log中获取历史快照
5、最后返回符合规则的数据。

已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的Read View,而可重复读隔离级别则在第一次读的时候生成Read View,之后都复用这个Read View。

MySQL主从同步原理

主要针对读写请求不同,进行了读写分离
mysql主从同步过程:
mysql的主从复制主要有三个线程:master:二进制日志转储线程(binlog dump thread)、slave:I/O线程(I/O thread)和SQL线程(SQL thread).master一条线程和slave中的两条线程。

  • 主节点binlog,主从复制的基础是主库将数据库的所有变更记录到binlog,实际上主从同步的原理就是基于binlog进行数据同步的。
  • 主节点二进制日志转储线程(log dump),当binlog有变动时,log dump线程读取其内容并发送给从节点
  • 从节点I/O线程,接受binlog内容(这里是数据更新的部分),并将其拷贝到本地形成中继日志(Relay log)
  • 从节点SQL线程读取relay log 文件内容对数据更新进行重放,最终保证主从数据库一致性。
    注:主节点使用binlog文件 + position偏移量来定义主从同步的位置,从节点会保存其已接受到的偏移量,如果从节点发生宕机重启,则会自动从position的位置发起同步

由于mysql默认的复制方式是异步的,主库把日志发送给从库后不关心从库是否已经处理,这样会产生一个问题就是假设主库挂了,从库处理失败,这时候从库升级为主库后,日志就丢失了。

全同步复制:主库写入binlog后强制同步日志到从库,所有的从库执行完成之后长才返回给客户端,但是这样性能就会收到严重影响。
半同步复制:和全同步复制不同的是,半同步复制是从库写入日志成功返回ACK确认给主库,主库收到至少一个从库的确认就认为写操作完成。

MyISAM 和INNODB的区别

在MySQL 5.1之前的版本中,默认的搜索引擎是MyISAM,从MySQL 5.5之后的版本中,默认的搜索引擎变更为InnoDB

MYISAM INNODB
事务支持 不支持 支持
数据行锁定 不支持(表锁定) 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间大小 较小 较大,约为2倍
  • MYISAM 节约空间,速度较快,记录了总条数,所示 count(1) 查询总条数快。采用非聚簇索引,索引文件的数据域存储指向数据文件的指针。
  • INNODB 安全性高,支持事务处理,支持外键多表操作。主键采用聚簇索引(索引的数据域存储数据文件本身)

物理空间位置:

  • 所有的数据库文件都存在data目录下,本质还是文件存储,一个文件夹就是一个数据库

mysql引擎在物理文件上的区别

  • INNODB
    • INNODB在文件中只有一个 *.frm文件,以及上级目录下的ibdata1文件
  • MYISAM
    • *.frm - 表结构的定义文件
    • *.MYD - 数据文件(data)
    • *.MYI - 索引文件(index)

其他区别:

  • 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
  • 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。

简述MySQL中索引类型及对数据库性能的影响

普通索引:允许被索引的数据列包含重复的值

唯一索引:可以保证数据记录的唯一性

主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字primary key 来创建

联合索引:索引可以覆盖多个数据列,如像index(columnA,columnB)索引

全文索引:通过建立倒排索引,可以极大的提高检索效率解决判断字段是否包含的问题,是目前搜索引擎使用的一种关键技术。可以通过alter table xxx_table add full text (column)创建全文索引

索引可以提高查询速度,但是会降低插入、删除、更新表的速度,因为执行这些操作时还要操作索引文件。索引需要占物理空间,如果要见聚簇索引需要的空间就会更大。如果非聚簇很多,一旦聚簇索引改变了,那么所有非聚簇索引都会跟着改变。

当普通的B+树包含要查询的所有字段时可以不用回表称覆盖索引
select id,name from t where name = 'zhangsan'  (id和name都是索引)

如何实现分库分表     

将原本存储于单个数据库上的数据拆分到多个数据库,把原来存储在单张数据表的数据拆分到多张数据表中,实现数据切分,从而提升数据库操作性能。分库分表的实现可以分为两种方式:垂直切分(关注业务)和水平切分(关注的是数据的特点)。     

水平:将数据分散到多张表或库,涉及分区键去定位具体哪个库哪张表,   

  • 分库:每个库结构-样,数据不-样,没有交集。库多了可以缓解io和cpu压力(比如将id进行hash打散根据数据库数量取模得到索引值、按某时间字段拆分)
  • 分表:每个表结构一样,数据不一样,没有交集。表数量减少可以提高sq|执行效率、减轻cpu压力

垂直:将字段拆分为多张表,需要一定的重构   

  • 分库:每个库结构、数据都不一样,所有库的并集为全量数据
  • 分表:每个表结构、数据不一样,至少有-列交集,用于关联数据,所有表的并集为全量数据 

存储拆分后如何解决唯一主键问题     

UUID:简单、不依赖第三方、性能好,但是没有顺序不适合范围查询,没有业务含义,存在泄漏mac地址的风险(基于硬件信息生成)  

数据库主键:实现简单,单调递增,具有一定的业务可读性,强依赖db、存在性能瓶颈,存在暴露业务信息的风险 。分库分表存在重复的可能,那么可以起始值不同,步长相同的递增方式,但又导致了加库改步长的问题,涉及了大量的数据迁移

redis, mongodb, zk等 中间件:增加了系统的复杂度和稳定性     

雪花算法 

雪花算法原理

 

第一位符号位固定为0, 41位时间戳,101workld, 12位序列号,位数可以有不同实现     

优点:     

  • 每个毫秒值包含的ID值很多,不够可以变动位数来增加,性能佳(依赖workld的实现)。   
  • 时间戳值在高位,中间是固定的机器码,自增的序列在低位,整个ID是趋势递增的。   
  • 能够根据业务场景数据库节点布置灵活调整bit位划分, 灵活度高。

 缺点:     

  • 强依赖于机器时钟,如果时钟回拨,会导致重复的ID生成,所以一般基于此的算法发现时钟回拨,都会抛异常处理,阻止ID生成,这可能导致服务不可用。

为什么尽量三表一下join关联

进行表关联时需要join的字段数据类型要一致,多表关联查询时,保证被关联的字段需要有索引
多表join关联性能差的原因:查询时先找缓存,有则直接返回,没有则进行解析查询,Mysql在三表及以上的关联SQL优化器做的并不好,性能差。在解析查询时会进行优化,优化SQL语句,计算和决定表的读取顺序,以及相关的索引等重构查询,修改顺序,表比较多的情况,排列的方式多,计算的成本就大大增加

为何禁止外键约束

添加外键数据库引攀必须为InnoDB、测试造数据非常麻烦、性能问题(额外的数据一致性校验查询)、井发问题(外键约柬会启动行级锁,主表写入时会进入阻塞)、耦合性问题(迁移困难)
以学生和成绩的关系为例,学生表中的student_ id 是主键,那么成绩表中的student_ id则为外键。如果更新学生表中的student_ id, 同时触发成绩表中的student_ id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql数据库知识整理 的相关文章

随机推荐

  • JavaScript简单算法-----二分查找

    二分查找又称折半查找 只适用于有序数组 二分查找就是将需要查找的元素不断地与数组中间的元素进行比较 数组不断地拆分为两段 查找元素小于中间值在前半段查找 大于中间值在后半段进行查找 代码展示 javaScript 的二分查找算法 var A
  • 搭建第一个Docker

    Docker 是一个开源的容器引擎 用于创建 管理和编排容器 可以轻松为任何应用创建一个轻量级 可移植 自给自足的容器 本步骤将在linux上部署一个Docker服务 并配置DockerHub的镜像加速器 安装软件包 在linux命令行输入
  • 【新员工座位安排系统】

    新员工座位 工位由序列F1 F2 Fn组成 Fi值为0 1或2 其中0代表空置 1代表有人 2代表障碍物 1 某一空位的友好度为左右连续老员工数之和 2 为方便新员工学习求助 优先安排友好度高的空位 给出工位序列 求所有空位中友好度的最大值
  • 十大管理——项目成本管理

    目录 1 成本管理概念 2 成本管理的四个过程域 2 1四个过程的整体理解 2 2四个过程的ITO口诀版记忆 2 3过程1 制定项目管理计划 2 4过程2 项目成本估算 2 5过程3 项目成本预算 2 5过程4 项目成本控制 3计算题 1
  • Nginx配置系统服务&设置环境变量

    1 Nginx操作问题 由于我们使用源码编译安装Nginx 因此 我们启动 关闭nginx或重新加载配置文件等也就比较麻烦 需要先进入nginx的可执行文件目录 才可以执行nginx相关命令 为了方便对nginx进行相关操作 我们可以将ng
  • 【图像处理】CvArr、Mat、CvMat、IplImage、BYTE转换

    一 Mat 类型 矩阵类型 Matrix 在openCV中 Mat是一个多维的密集数据数组 可以用来处理向量和矩阵 图像 直方图等等常见的多维数据 Mat有3个重要的方法 1 Mat mat imread const String file
  • selenium.chrome怎么写扩展拦截或转发请求?

    Selenium WebDriver 是一组开源 API 用于自动测试 Web 应用程序 利用它可以通过代码来控制chrome浏览器 有时候我们需要mock接口的返回 或者拦截和转发请求 今天就来实现这个功能 代码已开源 https git
  • 坑很多的一道题(含测试样例)——L1-009 N个数求和 (20分)

    L1 009 N个数求和 20分 本题的要求很简单 就是求N个数字的和 麻烦的是 这些数字是以有理数分子 分母的形式给出的 你输出的和也必须是有理数的形式 输入格式 输入第一行给出一个正整数N 100 随后一行按格式a1 b1 a2 b2
  • 微信小程序开发流程步骤 简单 详细

    微信小程序是一种不需要下载安装即可使用的应用 它搭载在目前最流行 用户量最大的社交软件 微信 中 用户通过扫一扫或搜索小程序名字即可找到使用想要的小程序并进行使用 非常的方便快捷 对于开发者而言呢 它也有非常全面 稳定 高效的接口API供开
  • 分布式消息传输系统Kafka的工作原理及其在大数据领域的应用

    引言 在大数据处理过程中 消息队列是一种非常重要的技术工具 它能够有效地解耦数据生产者和消费者之间的关系 实现高效的异步通信 而分布式消息传输系统Kafka 作为一种高性能 高可伸缩性的消息队列 已经成为了大数据领域中最受欢迎的工具之一 一
  • 一文看懂推荐系统:概要02:推荐系统的链路,从召回粗排,到精排,到重排,最终推荐展示给用户

    一文看懂推荐系统 概要02 推荐系统的链路 从召回粗排 到精排 到重排 最终推荐展示给用户 提示 最近系统性地学习推荐系统的课程 我们以小红书的场景为例 讲工业界的推荐系统 我只讲工业界实际有用的技术 说实话 工业界的技术远远领先学术界 在
  • mysql数据库卸载再安装失败_MySQL数据库——数据安装与卸载

    MySQL数据库的安装 双击msi 因为6 0之后是收费版本 所以这里我们使用5 5版本的mysql 打开下载的 mysql 安装文件双击解压缩 运行 mysql 5 5 40 win32 msi 或者 mysql 5 5 40 win64
  • vsqt中导出工程的Pro文件

    直接在qtvstools中使用Create Basic pro File所产生的Pro与Pri文件无法打开原工程 正确的做法应该是先用Export Project to pri File导出Pri文件后再使用Create Basic pro
  • C语言动态内存练习:【通讯录(动态内存版本)实现】

    全文目录 前言 目标规划 结构变化 功能实现的不同点 添加功能 AddContact 扩容检查 CheckCapacity 销毁通讯录 DestroyContact 总结 源码 前言 前面我们写了一个静态数组版本的通讯录 再结合刚学习的动态
  • bug记录 bigint数据返回前端数字精度丢失

    我的主键是bigint 9607408720124535 但是前端展示就是9607408720124536 使用postman调用就是9607408720124535 正确的 最终确定是js的number类型有个最大安全值 即2的53次方
  • JavaFX通过Controller类实现第二窗口销毁和程序退出

    Preface Q 为什么有此文 A 不能高度自定义化 网上大部分文章是通过简易的warning窗口 或者 information窗口实现的 且过于繁琐 大部分放在了Main java 不好弄 原理 Controller类中关键性代码 具体
  • MYSQL——模糊查询:like

    模糊查询指的是在数据中按照一定模糊的条件进行搜索 模糊查询的核心在于通配符的使用 通过使用通配符可以匹配不同的字符或字符串 一般模糊查询语句如下 SELECT 字段 FROM 表 WHERE 某个字段 LIKE 条件 表示任意0个或多个字符
  • css 背景效果_软件技术:我写CSS的常用套路(附demo的效果实现与源码)

    前言 本文是笔者写CSS时常用的套路 不论效果再怎么华丽 万变不离其宗 1 交错动画 有时候 我们需要给多个元素添加同一个动画 播放后 不难发现它们会一起运动 一起结束 这样就会显得很平淡无奇 那么如何将动画变得稍微有趣一点呢 很简单 既然
  • Harbor仓库介绍与搭建过程

    一 介绍 Harbor 是一个英文单词 意思是港湾 港湾是干什么的呢 就是停放货物的 而货物呢 是装在集装箱中的 说到集装箱 就不得不提到Docker容器 因为docker容器的技术正是借鉴了集装箱的原理 所以 Harbor正是一个用于存储
  • mysql数据库知识整理

    目录 InnoDB和MyISAM引擎常见区别 索引的基本原理 聚簇索引和非聚簇索引的区别 索引的数据结构及优势 索引的设计原则 innerdb主键索引自增的原因以及联合索引最左原则 锁的类型有哪些 MySQL执行计划 InnoDb引擎的执行