微服务学习总结-> 数据库基础知识

456 阅读9分钟

数据库执行逻辑

MySQL整体来看有两块:

  • Server层: 做MySQL功能层面的事情,大多数MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(日期、时间、数学和加密等等),所有跨存储引擎的功能都在这一层实现(存储过程、触发器、视图等)
  • 引擎层:负责存储相关的具体事宜。

redo log(重做日志)

例如,如果因为插入导致页面过度而拆分页面, 则需要编写已拆分的两个页面,并覆盖其父页面以更新对两个子页面的引用。这是一个危险 的操作,因为如果数据库在仅有一些页面被写入后崩溃,那么最终将导致一个损坏的索引 (例如,可能有一个孤儿页面不是任何父项的子项) 。 为了使数据库对崩溃具有韧性,B树实现通常会带有一个额外的磁盘数据结构:预写式日志 (WAL, write-ahead-log)(也称为重做日志(redo log))。这是一个仅追加的文件,每个B树修改都可以应用到树本身的页面上。当数据库在崩溃后恢复时,这个日志被用来使B树 恢复到一致的状态

InnoDB引擎特有的日志,来实现crash-safe功能

  • WAL技术: 全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。

  • Redo log作用:当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做

binlog(归档日志)

Server层自己的日志。 redo log 与 binlog不同点

redo logbinlog
InnoDB引擎特有Server层实现,所有引擎都可以用
是物理日志,记录的是“在某个数据页做了什么修改”是逻辑日志,记录的是这个语句的原始逻辑,比如“给id=2这一行的c字段加1”
循环写,空间固定会用完可以追加写:文件写到一定大小后会切换到下一个,并不会覆盖以前的日志

更新过程

update T set c = c+1 where id = 2;

update内部流程:

  1. 执行器先找引擎取id=2这一行,id是主键,引擎直接用树搜索到这一行。
    • 如果id=2这一行所在的数据页本来就在内存中,就直接返回给执行器
    • 否则先从磁盘读入内存,然后再返回
  2. 执行器拿到引擎给的行数据,把这个值+1,得到新的一行数据,再调用引擎接口写入新数据
  3. 引擎将这行新数据更新到内存中,同时这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成,随时可以提交事务
  4. 执行器生成这个操作的binlog,并将binlog写入磁盘
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交commit状态,更新完成

B+ Tree

如果要更新B树中现有键的值,则搜索包含该键的叶页,更改该页中的值,并将该页写回到磁 盘(对该页的任何引用保持有效)。如果你想添加一个新的键,你需要找到其范围包含新键的页面,并将其添加到该页面。如果页面中没有足够的可用空间容纳新键,则将其分成两个半满页面,并更新父页面以解释键范围的新分区.

insert 分页

该算法确保树保持平衡:具有 n 个键的B树总是具有 O(logn)O(log n) 的深度。大多数数据库可以放入一个三到四层的B树,所以你不需要遵追踪多页面引用来找到你正在查找的页面。 (分 支因子为 500 的 4KB页面的四级树可以存储多达 256TB 。

索引

索引是从主数据衍生的附加(additional)结构。许多数据库允许添加与删除索引,这不会影 响数据的内容,它只影响查询的性能。维护额外的结构会产生开销,特别是在写入时。写入性能很难超过简单地追加写入文件,因为追加写入是最简单的写入操作。任何类型的索引通常都会减慢写入速度,因为每次写入数据时都需要更新索引。

  • 多叉树的优势: 为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。

索引类型

示例:

mysql> create table T(
id int primary key, 
value int not null, 
name varchar(16),
index (value))engine=InnoDB;
idvalue
1100
2200
3300
4400
5500
  • 主键索引:叶子节点存的是整行数据。
  • 非主键索引:叶子节点存的是主键的值。查询时,先走非主键索引树,得到主键值,然后再去主键索引树查询一次(又称回表)。

  • 覆盖索引:指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取

  • 普通索引

    • 查找过程:查找到满足条件的第一个记录后,需要查找下一个记录,直到碰到第一个不满足条件的记录
    • 更新过程,根据目标页是否在内存中
      • 在内存中:找到更新的位置,插入这个值,语句执行结束
      • 不在内存中:则是将更新记录在 change buffer,语句执行就结束了
  • 唯一索引

    • 查找过程:由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索
    • 更新过程,根据目标页是否在内存中
      • 在内存中:找到更新的位置,判断到没有冲突,插入这个值,语句执行结束;
      • 不在内存中:需要将数据页读入内存,判断到没有冲突,插入这个值,语句执行结束;
  • 联合索引

    • 最左前缀原则:不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索
    • 第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的
    • 索引下推:可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

无索引下推:从第一个符合条件位置开始一个个回表。到主键索引上找出数据行,再对比字段值。

索引下推:

更新过程

  • 当需要更新一个数据页时,如果数据页在内存中就直接更新
  • 而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

OLTP VS OLAP

这些OLTP系统通常具有高度的可用性,并以低延迟处理事务,因为这些系统往往对业务运作 至关重要。因此数据库管理员密切关注他们的OLTP数据库他们通常不愿意让业务分析人员在 OLTP数据库上运行临时分析查询,因为这些查询通常很昂贵,扫描大部分数据集,这会损害 同时执行的事务的性能。

相比之下,数据仓库是一个独立的数据库,分析人员可以查询他们心中的内容,而不影响 OLTP操作。数据仓库包含公司所有各种OLTP系统中的只读数据副本。从OLTP数据库 中提取数据(使用定期的数据转储或连续的更新流),转换成适合分析的模式,清理并加载 到数据仓库中。将数据存入仓库的过程称为“抽取-转换-加载(ETL)

面向列的存储

列压缩

编码

复制

同步与异步

RedoLog BinLog

从库读取的问题

单调读(Monotonic reads)是这种异常不会发生的保证。这是一个比强一致性 (strong consistency)更弱,但比最终一致性(eventually consistency)更强的保证。 当读取数据时,您可能会看到一个旧值;单调读取仅意味着如果一个用户顺序地进行多次读 取,则他们不会看到时间后退,即,如果先前读取到较新的数据,后续读取不会得到更旧的 数据。

多主复制

分区

Hash分区

Rebalance

三种路由

ACID

脏读

未完待续