三太子敖丙 潜水
  • 1发帖数
  • 1主题数
  • 0关注数
  • 0粉丝
开启左侧

打工四年总结的数据库知识点

[复制链接]
三太子敖丙 发表于 2020-10-14 11:47:06 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
国庆在家无聊,我顺手翻了一下家里数据库相关的书籍,这一翻我就看上瘾了,由于大学比较熟悉的一些数据库范式我居然都忘了,怀揣着好奇心我就看了一个小国庆。
[size=0.833em]看的过程中我也做了一些小笔记,可能没我之前体系文章那么有趣,但是绝对也是干货十足,得当大家去回顾或者口试突击的得当看看,也不多说先放图。

                               
登录/注册后可看大图

存储引擎

InnoDB

[size=0.833em]InnoDB 是 MySQL 默认的事件型存储引擎,只要在需要它不支持的特性时,才思量使用其他存储引擎。
[size=0.833em]InnoDB 采用 MVCC 来支持高并发,并且实现了四个标准隔离级别(未提交读、提交读、可重复读、可串行化)。其默认级别时可重复读(REPEATABLE READ),在可重复读级别下,通过 MVCC + Next-Key Locking 防止幻读。
[size=0.833em]主索引时聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对主键查询有很高的性能。
[size=0.833em]InnoDB 内部做了很多优化,包括从磁盘读取数据时采用的可预测性读,能够自动在内存中创建 hash 索引以加速读操纵的自适应哈希索引,以及能够加速插入操纵的插入缓冲区等。
[size=0.833em]InnoDB 支持真正的在线热备份,MySQL 其他的存储引擎不支持在线热备份,要获取一致性视图需要制止对所有表的写入,而在读写混淆的场景中,制止写入可能也意味着制止读取。
MyISAM

[size=0.833em]设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操纵,则依然可以使用它。
[size=0.833em]提供了大量的特性,包括压缩表、空间数据索引等。
[size=0.833em]不支持事件。
[size=0.833em]不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操纵的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。
[size=0.833em]可以手工或者自动执行查抄和修复操纵,但是和事件恢复以及瓦解恢复不同,可能导致一些数据丢失,而且修复操纵是非常慢的。
[size=0.833em]假如指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机瓦解时会造成索引破坏,需要执行修复操纵。
InnoDB 和 MyISAM 的比较


  • [size=0.833em]事件:InnoDB 是事件型的,可以使用 Commit 和 Rollback 语句。
  • [size=0.833em]并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
  • [size=0.833em]外键:InnoDB 支持外键。
  • [size=0.833em]备份:InnoDB 支持在线热备份。
  • [size=0.833em]瓦解恢复:MyISAM 瓦解后发生破坏的概率比 InnoDB 高很多,而且恢复的速率也更慢。
  • [size=0.833em]别的特性:MyISAM 支持压缩表和空间数据索引。
索引

B+ Tree 原理

数据结构

[size=0.833em]B Tree 指的是 Balance Tree,也就是均衡树,均衡树是一颗查找树,并且所有叶子节点位于同一层。
[size=0.833em]B+ Tree 是 B 树的一种变形,它是基于 B Tree 和叶子节点次序访问指针进行实现,通常用于数据库和操纵体系的文件体系中。
[size=0.833em]B+ 树有两种类型的节点:内部节点(也称索引节点)和叶子节点,内部节点就是非叶子节点,内部节点不存储数据,只存储索引,数据都存在叶子节点。
[size=0.833em]内部节点中的 key 都按照从小到大的次序排列,对于内部节点中的一个 key,左子树中的所有 key 都小于它,右子树中的 key 都大于即是它,叶子节点的记录也是按照从小到大排列的。
[size=0.833em]每个叶子节点都存有相邻叶子节点的指针。

                               
登录/注册后可看大图

操纵

[size=0.833em]查找
[size=0.833em]查找以典型的方式进行,类似于二叉查找树。起始于根节点,自顶向下遍历树,选择其分离值在要查找值的恣意一边的子指针。在节点内部典型的使用是二分查找来确定这个位置。
[size=0.833em]插入

  • [size=0.833em]Perform a search to determine what bucket the new record should go into.
  • [size=0.833em]If the bucket is not full(a most b - 1 entries after the insertion,b 是节点中的元素个数,一般是页的整数倍),add tht record.
  • [size=0.833em]Otherwise,before inserting the new record split the bucket. original node has 「(L+1)/2」itemsnew node has 「(L+1)/2」items Move 「(L+1)/2」-th key to the parent,and insert the new node to the parent.Repeat until a parent is found that need not split.
  • [size=0.833em]If the root splits,treat it as if it has an empty parent ans split as outline above.
[size=0.833em]B-trees grow as the root and not at the leaves.
[size=0.833em]删除
[size=0.833em]和插入类似,只不过是自下而上的合并操纵。
树的常见特性

[size=0.833em]AVL 树
[size=0.833em]均衡二叉树,一般是用均衡因子差值决定并通过旋转来实现,左右子树树高差不凌驾1,那么和红黑树比较它是严格的均衡二叉树,均衡条件非常严格(树高差只有1),只要插入或删除不满意上面的条件就要通过旋转来保持均衡。由于旋转是非常耗费时间的。所以 AVL 树适用于插入/删除次数比较少,但查找多的场景。
[size=0.833em]红黑树
[size=0.833em]通过对从根节点到叶子节点路径上各个节点的颜色进行约束,确保没有一条路径会比其他路径长2倍,因而是近似均衡的。所以相对于严格要求均衡的AVL树来说,它的旋转保持均衡次数较少。得当,查找少,插入/删除次数多的场景。(现在部分场景使用跳表来替换红黑树,可搜刮“为啥 redis 使用跳表(skiplist)而不是使用 red-black?”)
[size=0.833em]B/B+ 树
[size=0.833em]多路查找树,出度高,磁盘IO低,一般用于数据库体系中。
B + 树与红黑树的比较

[size=0.833em]红黑树等均衡树也可以用来实现索引,但是文件体系及数据库体系普遍采用 B+ Tree 作为索引结构,主要有以下两个缘故原由:
[size=0.833em](一)磁盘 IO 次数
[size=0.833em]B+ 树一个节点可以存储多个元素,相对于红黑树的树高更低,磁盘 IO 次数更少。
[size=0.833em](二)磁盘预读特性
[size=0.833em]为了淘汰磁盘 I/O 操纵,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行次序读取,次序读取不需要进行磁盘寻道。每次会读取页的整数倍。
[size=0.833em]操纵体系一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位互换数据。数据库体系将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。
B + 树与 B 树的比较

[size=0.833em]B+ 树的磁盘 IO 更低
[size=0.833em]B+ 树的内部节点并没有指向关键字具体信息的指针。因此其内部节点相对 B 树更小。假如把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数目也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
[size=0.833em]B+ 树的查询服从更加稳固
[size=0.833em]由于非叶子结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询服从相当。
[size=0.833em]B+ 树元素遍历服从高
[size=0.833em]B 树在进步了磁盘IO性能的同时并没有解决元素遍历的服从低下的问题。正是为相识决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频仍的,而 B 树不支持这样的操纵(或者说服从太低)。
MySQL 索引

[size=0.833em]索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。
B+ Tree 索引

[size=0.833em]是大多数 MySQL 存储引擎的默认索引类型。

  • [size=0.833em]由于不再需要进行全表扫描,只需要对树进行搜刮即可,所以查找速率快很多。
  • [size=0.833em]由于 B+ Tree 的有序性,所以除了用于查找,还可以用于排序和分组。
  • [size=0.833em]可以指定多个列作为索引列,多个索引列共同组成键。
  • [size=0.833em]适用于全键值、键值范围和键前缀查找,此中键前缀查找只适用于最左前缀查找。假如不是按照索引列的次序进行查找,则无法使用索引。
[size=0.833em]InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完备的数据记录,这种索引方式被称为聚簇索引。由于无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。

                               
登录/注册后可看大图

[size=0.833em]辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找,这个过程也被称作回表。

                               
登录/注册后可看大图

哈希索引

[size=0.833em]哈希索引能以 O(1) 时间进行查找,但是失去了有序性:

  • 无法用于排序与分组;
  • 只支持准确查找,无法用于部分查找和范围查找。
[size=0.833em]InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频仍时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些长处,比如快速的哈希查找。
全文索引

[size=0.833em]MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相称。
[size=0.833em]查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
[size=0.833em]全文索引使用倒排索引实现,它记录着关键词到其所在文档的映射。
[size=0.833em]InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。
空间数据索引

[size=0.833em]MyISAM 存储引擎支持空间数据索引(R-Tree),可以用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用恣意维度来进行组合查询。
[size=0.833em]必须使用 GIS 相关的函数来维护数据。
索引优化

独立的列

[size=0.833em]在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。
[size=0.833em]例如下面的查询不能使用 actor_id 列的索引:
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;多列索引

[size=0.833em]在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。例如下面的语句中,最好把 actor_id 和 film_id 设置为多列索引。
SELECT film_id, actor_ id FROM sakila.film_actorWHERE actor_id = 1 AND film_id = 1;索引列的次序

[size=0.833em]让选择性最强的索引列放在前面。
[size=0.833em]索引的选择性是指:不重复的索引值和记录总数的比值。最大值为 1,此时每个记录都有唯一的索引与其对应。选择性越高,每个记录的区分度越高,查询服从也越高。
[size=0.833em]例如下面显示的效果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,COUNT(*)FROM payment;   staff_id_selectivity: 0.0001customer_id_selectivity: 0.0373               COUNT(*): 16049前缀索引

[size=0.833em]对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。
[size=0.833em]前缀长度的选取需要根据索引选择性来确定。
覆盖索引

[size=0.833em]索引包含所有需要查询的字段的值。
[size=0.833em]具有以下长处:

  • 索引通常远小于数据行的大小,只读取索引能大大淘汰数据访问量。
  • 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操纵体系来缓存。因此,只访问索引可以不使用体系调用(通常比较费时)。
  • 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。
索引的长处


  • [size=0.833em]大大淘汰了服务器需要扫描的数据行数。
  • [size=0.833em]帮助服务器避免进行排序和分组,以及避免创建临时表(B+Tree 索引是有序的,可以用于 ORDER BY 和 GROUP BY 操纵。临时表主要是在排序和分组过程中创建,不需要排序和分组,也就不需要创建临时表)。
  • [size=0.833em]将随机 I/O 变为次序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)。
索引的使用条件


  • [size=0.833em]对于非常小的表、大部分情况下简单的全表扫描比创建索引更高效;
  • [size=0.833em]对于中到大型的表,索引就非常有效;
  • [size=0.833em]但是对于特大型的表,创建和维护索引的代价将会随之增长。这种情况下,需要用到一种技能可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技能。
[size=0.833em]为什么对于非常小的表,大部分情况下简单的全表扫描比创建索引更高效?
[size=0.833em]假如一个表比较小,那么显然直接遍历表比走索引要快(由于需要回表)。
[size=0.833em]注:首先,要注意这个答案隐含的条件是查询的数据不是索引的构成部分,否也不需要回表操纵。其次,查询条件也不是主键,否则可以直接从聚簇索引中拿到数据。
查询性能优化

使用 explain 分析 select 查询语句

[size=0.833em]explain 用来分析 SELECT 查询语句,开辟人员可以通过分析 Explain 效果来优化查询语句。
select_type

[size=0.833em]常用的有 SIMPLE 简单查询,UNION 联合查询,SUBQUERY 子查询等。
table

[size=0.833em]要查询的表
possible_keys

[size=0.833em]The possible indexes to choose
[size=0.833em]可选择的索引
key

[size=0.833em]The index actually chosen
[size=0.833em]现实使用的索引
rows

[size=0.833em]Estimate of rows to be examined
[size=0.833em]扫描的行数
type

[size=0.833em]索引查询类型,常常用到的索引查询类型:
[size=0.833em]const:使用主键或者唯一索引进行查询的时候只有一行匹配 ref:使用非唯一索引 range:使用主键、单个字段的辅助索引、多个字段的辅助索引的最后一个字段进行范围查询 index:和all的区别是扫描的是索引树 all:扫描全表:
system

[size=0.833em]触发条件:表只有一行,这是一个 const type 的特殊情况
const

[size=0.833em]触发条件:在使用主键或者唯一索引进行查询的时候只有一行匹配。
SELECT * FROM tbl_name WHERE primary_key=1;SELECT * FROM tbl_name  WHERE primary_key_part1=1 AND primary_key_part2=2;

                               
登录/注册后可看大图

eq_ref

[size=0.833em]触发条件:在进行联接查询的,使用主键或者唯一索引并且只匹配到一行记录的时候
SELECT * FROM ref_table,other_table  WHERE ref_table.key_column=other_table.column;SELECT * FROM ref_table,other_table  WHERE ref_table.key_column_part1=other_table.column  AND ref_table.key_column_part2=1;ref

[size=0.833em]触发条件:使用非唯一索引
SELECT * FROM ref_table WHERE key_column=expr;SELECT * FROM ref_table,other_table  WHERE ref_table.key_column=other_table.column;SELECT * FROM ref_table,other_table  WHERE ref_table.key_column_part1=other_table.column  AND ref_table.key_column_part2=1;

                               
登录/注册后可看大图

range

[size=0.833em]触发条件:只有在使用主键、单个字段的辅助索引、多个字段的辅助索引的最后一个字段进行范围查询才是 range
SELECT * FROM tbl_name  WHERE key_column = 10;SELECT * FROM tbl_name  WHERE key_column BETWEEN 10 and 20;SELECT * FROM tbl_name  WHERE key_column IN (10,20,30);SELECT * FROM tbl_name  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

                               
登录/注册后可看大图

index

[size=0.833em]The index join type is the same as ALL, except that the index tree is scanned. This occurs two ways:
[size=0.833em]触发条件:
[size=0.833em]只扫描索引树
[size=0.833em]1)查询的字段是索引的一部分,覆盖索引。 2)使用主键进行排序

                               
登录/注册后可看大图

all

[size=0.833em]触发条件:全表扫描,不走索引
优化数据访问

淘汰请求的数据量


  • 只返回须要的列:最好不要使用 SELECT * 语句。
  • 只返回须要的行:使用 LIMIT 语句来限制返回的数据。
  • 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据常常被重复查询时,缓存带来的查询性能提升将会是非常明显的。
淘汰服务器端扫描的行数

[size=0.833em]最有效的方式是使用索引来覆盖查询。
重构查询方式

切分大查询

[size=0.833em]一个大查询假如一次性执行的话,可能一次锁住很多数据、占满整个事件日记、耗尽体系资源、阻塞很多小的但紧张的查询。
DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH);rows_affected = 0do {    rows_affected = do_query(    "DELETE FROM messages WHERE create  < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000")} while rows_affected > 0分解大连接查询

[size=0.833em]将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有:

  • 让缓存更高效。对于连接查询,假如此中一个表发生变革,那么整个查询缓存就无法使用。而分解后的多个查询,即使此中一个表发生变革,对别的表的查询缓存依然可以使用。
  • 分解成多个单表查询,这些单表查询的缓存效果更可能被别的查询使用到,从而淘汰冗余记录的查询。
  • 淘汰锁竞争;
  • 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。
  • 查询自己服从也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 次序进行查询,这可能比随机的连接要更高效。
SELECT * FROM tagJOIN tag_post ON tag_post.tag_id=tag.idJOIN post ON tag_post.post_id=post.idWHERE tag.tag=&#39;mysql&#39;;SELECT * FROM tag WHERE tag=&#39;mysql&#39;;SELECT * FROM tag_post WHERE tag_id=1234;SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);事件

[size=0.833em]事件是指满意 ACID 特性的一组操纵,可以通过 Commit 提交一个事件,也可以使用 Rollback 进行回滚。
ACID

[size=0.833em]事件最基本的莫过于 ACID 四个特性了,这四个特性分别是:

  • Atomicity:原子性
  • Consistency:一致性
  • Isolation:隔离性
  • Durability:长期性
[size=0.833em]原子性
[size=0.833em]事件被视为不可分割的最小单元,事件的所有操纵要么全部成功,要么全部失败回滚。
[size=0.833em]一致性
[size=0.833em]数据库在事件执行前后都保持一致性状态,在一致性状态下,所有事件对一个数据的读取效果都是相同的。
[size=0.833em]隔离性
[size=0.833em]一个事件所做的修改在最终提交从前,对其他事件是不可见的。
[size=0.833em]长期性
[size=0.833em]一旦事件提交,则其所做的修改将会永远保存到数据库中。即使体系发生瓦解,事件执行的效果也不能丢。
ACID 之间的关系

[size=0.833em]事件的 ACID 特性概念很简单,但不好理解,主要是由于这几个特性不是一种平级关系:

  • 只有满意一致性,事件的效果才是正确的。
  • 在无并发的情况下,事件串行执行,隔离性一定能够满意。此时只要能满意原子性,就一定能满意一致性。在并发的情况下,多个事件并行执行,事件不仅要满意原子性,还需要满意隔离性,才能满意一致性。
  • 事件满意长期化是为了能应对数据库瓦解的情况。

                               
登录/注册后可看大图

隔离级别

[size=0.833em]未提交读(READ UNCOMMITTED)
[size=0.833em]事件中的修改,即使没有提交,对其他事件也是可见的。
[size=0.833em]提交读(READ COMMITTED)
[size=0.833em]一个事件只能读取已经提交的事件所做的修改。换句话说,一个事件所做的修改在提交之前对其他事件是不可见的。
[size=0.833em]可重复读(REPEATABLE READ)
[size=0.833em]保证在同一个事件中多次读取同样数据的效果是一样的。
[size=0.833em]可串行化(SERIALIZABLE)
[size=0.833em]欺压事件串行执行。
[size=0.833em]需要加锁实现,而别的隔离级别通常不需要。
[size=0.833em]隔离级别 [size=0.833em]脏读 [size=0.833em]不可重复读 [size=0.833em]幻影读 [size=0.833em]未提交读 [size=0.833em]√ [size=0.833em]√ [size=0.833em]√ [size=0.833em]提交读 [size=0.833em]× [size=0.833em]√ [size=0.833em]√ [size=0.833em]可重复读 [size=0.833em]× [size=0.833em]× [size=0.833em]√ [size=0.833em]可串行化 [size=0.833em]× [size=0.833em]× [size=0.833em]×


[size=0.833em]锁是数据库体系区别于文件体系的一个关键特性。锁机制用于管理对共享资源的并发访问。
锁类型

[size=0.833em]共享锁(S Lock)
[size=0.833em]允许事件读一行数据
[size=0.833em]排他锁(X Lock)
[size=0.833em]允许事件删除或者更新一行数据
[size=0.833em]意向共享锁(IS Lock)
[size=0.833em]事件想要获得一张表中某几行的共享锁
[size=0.833em]意向排他锁
[size=0.833em]事件想要获得一张表中某几行的排他锁
MVCC

[size=0.833em]多版本并发控制(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。而未提交读隔离级别总是读取最新的数据行,无需使用 MVCC。可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。
底子概念

[size=0.833em]版本号

  • 体系版本号:是一个递增的数字,每开始一个新的事件,体系版本号就会自动递增。
  • 事件版本号:事件开始时的体系版本号。
[size=0.833em]隐藏的列
[size=0.833em]MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版本号:

  • 创建版本号:指示创建一个数据行的快照时的体系版本号;
  • 删除版本号:假如该快照的删除版本号大于当前事件版本号表示该快照有效,否则表示该快照已经被删除了。
[size=0.833em]Undo 日记
[size=0.833em]MVCC 使用到的快照存储在 Undo 日记中,该日记通过回滚指针把一个数据行(Record)的所有快照连接起来。

                               
登录/注册后可看大图

实现过程

[size=0.833em]以下实现过程针对可重复读隔离级别。
[size=0.833em]当开始一个事件时,该事件的版本号肯定大于当前所有数据行快照的创建版本号,理解这一点很关键。数据行快照的创建版本号是创建数据行快照时的体系版本号,体系版本号随着创建事件而递增,因此新创建一个事件时,这个事件的体系版本号比之前的体系版本号都大,也就是比所有数据行快照的创建版本号都大。
[size=0.833em]SELECT
[size=0.833em]多个事件必须读取到同一个数据行的快照,并且这个快照是距离现在最近的一个有效快照。但是也有破例,假如有一个事件正在修改该数据行,那么它可以读取事件自己所做的修改,而不用和别的事件的读取效果一致。
[size=0.833em]把没有对一个数据行做修改的事件称为 T,T 所要读取的数据行快照的创建版本号必须小于即是 T 的版本号,由于假如大于 T 的版本号,那么表示该数据行快照是别的事件的最新修改,因此不能去读取它。除此之外,T 所要读取的数据行快照的删除版本号必须是未定义或者大于 T 的版本号,由于假如小于即是 T 的版本号,那么表示该数据行快照是已经被删除的,不应该去读取它。
[size=0.833em]INSERT
[size=0.833em]将当前体系版本号作为数据行快照的创建版本号。
[size=0.833em]DELETE
[size=0.833em]将当前体系版本号作为数据行快照的删除版本号。
[size=0.833em]UPDATE
[size=0.833em]将当前体系版本号作为更新前的数据行快照的删除版本号,并将当前体系版本号作为更新后的数据行快照的创建版本号。可以理解为先执行 DELETE 后执行 INSERT。
快照读与当前读

[size=0.833em]在可重复读级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中,就很可能出问题。
[size=0.833em]对于这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库当前版本数据的方式,叫当前读 (current read)。很显然,在MVCC中:
[size=0.833em]快照读
[size=0.833em]MVCC 的 SELECT 操纵是快照中的数据,不需要进行加锁操纵。
select * from table ….;[size=0.833em]当前读
[size=0.833em]MVCC 别的会对数据库进行修改的操纵(INSERT、UPDATE、DELETE)需要进行加锁操纵,从而读取最新的数据。可以看到 MVCC 并不是完全不用加锁,而只是避免了 SELECT 的加锁操纵。
INSERT;UPDATE;DELETE;[size=0.833em]在进行 SELECT 操纵时,可以欺压指定进行加锁操纵。以下第一个语句需要加 S 锁,第二个需要加 X 锁。
- select * from table where ? lock in share mode;- select * from table where ? for update;[size=0.833em]事件的隔离级别现实上都是定义的当前读的级别,MySQL为了淘汰锁处理(包括等待别的锁)的时间,提升并发本领,引入了快照读的概念,使得select不用加锁。而update、insert这些“当前读”的隔离性,就需要通过加锁来实现了。
锁算法

Record Lock

[size=0.833em]锁定一个记录上的索引,而不是记录自己。
[size=0.833em]假如表没有设置索引,InnoDB 会自动在主键上创建隐藏的聚簇索引,因此 Record Locks 依然可以使用。
Gap Lock

[size=0.833em]锁定索引之间的间隙,但是不包含索引自己。例如当一个事件执行以下语句,别的事件就不能在 t.c 中插入 15。
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;Next-Key Lock

[size=0.833em]它是 Record Locks 和 Gap Locks 的联合,不仅锁定一个记录上的索引,也锁定索引之间的间隙。例如一个索引包含以下值:10, 11, 13, and 20,那么就需要锁定以下区间:
(-∞, 10](10, 11](11, 13](13, 20](20, +∞)
[size=0.833em]在 InnoDB 存储引擎中,SELECT 操纵的不可重复读问题通过 MVCC 得到相识决,而 UPDATE、DELETE 的不可重复读问题通过 Record Lock 解决,INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的。
锁问题

脏读

[size=0.833em]脏读指的是不同事件下,当前事件可以读取到别的事件未提交的数据。
[size=0.833em]例如:
[size=0.833em]T1 修改一个数据,T2 随后读取这个数据。假如 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。

                               
登录/注册后可看大图

不可重复读

[size=0.833em]不可重复读指的是同一事件内多次读取同一数据集合,读取到的数据是不一样的情况。
[size=0.833em]例如:
[size=0.833em]T2 读取一个数据,T1 对该数据做了修改。假如 T2 再次读取这个数据,此时读取的效果和第一次读取的效果不同。

                               
登录/注册后可看大图

[size=0.833em]在 InnoDB 存储引擎中,SELECT 操纵的不可重复读问题通过 MVCC 得到相识决,而 UPDATE、DELETE 的不可重复读问题是通过 Record Lock 解决的,INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的。
Phantom Proble(幻影读)

[size=0.833em]The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
[size=0.833em]Phantom Proble 是指在同一事件下,一连执行两次同样的 sql 语句可能返回不同的效果,第二次的 sql 语句可能会返回之前不存在的行。
[size=0.833em]幻影读是一种特殊的不可重复读问题。
总结

[size=0.833em]这都是些底子知识,我没想到再次回顾大半我都已忘却了,也庆幸有这样的假期能够重新拾起来。
[size=0.833em]说实话做自媒体后我充电的时间少了很多,也少了很多时间研究技能栈深度,国庆假期我也思考反思了很久,后面准备继续压缩自己业余时间,比如看手机看B站的时间压缩一下,照旧得按时充电,目前作息还算规律早睡早起都做到了,我们一起加油哟。
絮叨

[size=0.833em]敖丙把自己的口试文章整理成了一本电子书,共 1630页!
[size=0.833em]干货满满,字字精髓。目录如下,另有我复习时总结的口试题以及简历模板,现在免费送给大家。

                               
登录/注册后可看大图

回复【资料】有我准备的一线大厂口试资料和简历模板,有大厂口试完备考点。

精彩评论20

梦幻一境界 发表于 2020-10-22 18:12:33 | 显示全部楼层
总结的十分精辟,相比之前看的文章多了更多底层的东西,原来理解JMM总会默认想起什么堆内存。栈内存。方法区。云云。现在理解的更为透彻。
freshswq 发表于 2020-11-19 22:26:52 | 显示全部楼层
资料,谢谢
DEnd 发表于 2020-10-14 16:34:54 | 显示全部楼层
干货满满啊,收下了,谢谢哈
starzgh 发表于 2021-1-7 23:25:33 | 显示全部楼层
资料,谢谢
蜗牛不是牛gg 发表于 2020-10-15 10:54:18 | 显示全部楼层
资料,谢谢
_落幕于夕阳 发表于 2020-10-15 11:28:50 | 显示全部楼层
资料,谢谢
篮球枫子1 发表于 2020-10-15 00:04:22 | 显示全部楼层
资料 谢谢
BIG倪 发表于 2020-10-14 20:07:08 | 显示全部楼层
资料,谢谢
自由光束S 发表于 2020-10-28 13:11:21 | 显示全部楼层
资料
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

猜你喜欢
在线客服邮箱
wxcy#wkgb.net

邮箱地址#换为@

Powered by 创意电子 ©2018-现在 专注资源实战分享源码下载站联盟商城