数据库原理读书笔记三

阅读: 评论:0

数据库原理读书笔记三

数据库原理读书笔记三

缓存管理器

数据库的主要瓶颈是磁盘 I/O。为了提高性能,现代数据库使用缓存管理器。

查询执行器不会直接从文件系统拿数据,而是向缓存管理器要。缓存管理器有一个内存缓存区,叫做缓冲池,从内存读取数据显著地提升数据库性能。对此很难给出一个数量级,因为这取决于你需要的是哪种操作:

  • 顺序访问(比如:全扫描) vs 随机访问(比如:按照row id访问)
  • 读还是写

但是这导致了另一个问题 缓存管理器需要在查询执行器使用数据之前得到数据不然的话查询管理器不得不等待数据从缓慢的磁盘中读出来

然后这个步骤是可优化的
可以采用预读

  • 当查询执行器处理它的第一批数据时
  • 会告诉缓存管理器预先装载第二批数据
  • 当开始处理第二批数据时
  • 告诉缓存管理器预先装载第三批数据,并且告- 诉缓存管理器第一批可以从缓存里清掉了

缓存管理器在缓冲池里保存所有的这些数据。为了确定一条数据是否有用,缓存管理器给缓存的数据添加了额外的信息(叫闩锁)。
什么叫一条数据可用 难道载入内存的数据 还会在载入时删掉 这怎么有点像内存中的写缓冲器

但是问题由来了 有的时候查询执行器不知道它需要什么数据
数据库使用一种推测预读法(比如:如果查询执行器想要数据1、3、5,它不久后很可能会要 7、9、11),或者顺序预读法(这时候缓存管理器只是读取一批数据后简单地从磁盘加载下一批连续数据)。

又可以优化了。。

为了监控预读的工作状况,现代数据库引入了一个度量叫缓冲/缓存命中率,用来显示请求的数据在缓存中找到而不是从磁盘读取的频率。

但是问题又来了

如果有经常执行的查询,但是我们知道缓冲是容量有限的内存空间
那么每次都把查询结果加载然后清除,效率就太低了。现代数据库用缓冲区置换策略来解决这个问题。

LRU

LRU代表最近最少使用(Least Recently Used)算法,背后的原理是:在缓存里保留的数据是最近使用的,所以更有可能再次使用。

和LinkedHashMap有一曲同工之妙

Map<String, Employee〉staff = new LinkedHashMap<>();
staff.put("144-25-5464", new Employee("Amy Lee"));
staff.put("567-24-2546", new Employee("Harry Hacker"));
staff.put("157-62-7935", new Employee("Gary Cooper"));
staff.put("456-62-5527", new Employee("Francesca Cruz"));//使用无参构造器遍历的结果是 将按照插入顺序对映射条目进行迭代 如果后续插入元素 迭代的顺序不会改变化
LinkedHashMap(K, V>(initialCapacity, loadFactor, true);
//将按照访问顺序对映射条目进行迭代  每次调用get和put 受到影响的条目将从当前的位置删除,并放到条目列表的尾部 只有该条目在链表中的位置会受到影响 而散列表中的桶不会受到影响 

这么好的算法也有问题的
如果对一个大表执行全表扫描怎么办?换句话说,当表/索引的大小超出缓冲区会发生什么?使用这个算法会清除之前缓存内所有的数据,而且全扫描的数据很可能只使用一次。

为了防止这个现象,有些数据库增加了特殊的规则,比如Oracle文档中的描述:

『对非常大的表来说,数据库通常使用直接路径来读取,即直接加载区块[……],来避免填满缓冲区。对于中等大小的表,数据库可以使用直接读取或缓存读取。如果选择缓存读取,数据库把区块置于LRU的尾部,防止清空当前缓冲区。』

还有更牛逼的算法

使用高级版本的LRU,叫做 LRU-K。例如,SQL Server 使用 LRU-2。

这个算法的原理是把更多的历史记录考虑进来。简单LRU(也就是 LRU-1),只考虑最后一次使用的数据。
什么叫只考虑最后一次使用的数据
就是直接操作 比如上述的LinkedHashMap

LRU-K呢:

  • 考虑数据最后第K次使用的情况
  • 数据使用的次数加进了权重
  • 一批新数据加载进入缓存,旧的但是经常使用的数据不会被清除(因为权重更高)
  • 但是这个算法不会保留缓存中不再使用的数据
    所以数据如果不再使用,权重值随着时间推移而降低

事务管理器

一个ACID事务是一个工作单元 它要保证4个属性

  • 原子性(Atomicity):事务『要么全部完成,要么全部取消』,即使它持续运行10个小时。如果事务崩溃,状态回到事务之前(事务回滚)。
  • 隔离性(Isolation): 如果2个事务 A 和 B 同时运行,事务 A 和 B 最终的结果是相同的,不管 A 是结束于 B 之前/之后/运行期间。
  • 持久性(Durability): 一旦事务提交(也就是成功执行),不管发生什么(崩溃或者出错),数据要保存在数据库中。
  • 一致性(Consistency): 只有合法的数据(依照关系约束和函数约束)能写入数据库,一致性与原子性和隔离性有关。

SQL定义了4个隔离级别

  • 串行化(SQLite默认实现) 两个事务 都有自己的世界 即不同步
  • 可重复读(Mysql默认实现)
    每个事务有自己的『世界』,除了一种情况。如果一个事务成功执行并且添加了新数据,这些数据对其他正在执行的事务是可见的。但是如果事务成功修改了一条数据,修改结果对正在运行的事务不可见。所以,事务之间只是在新数据方面突破了隔离,对已存在的数据仍旧隔离。

简而言之 对添加可见 其他不可见

  • 读取已提交
    可重复读+新的隔离突破。如果事务A读取了数据D,然后数据D被事务B修改(或删除)并提交,事务A再次读取数据D时数据的变化(或删除)是可见的。

  • 读取未提交
    读取未提交(Read uncommitted):最低级别的隔离,是读取已提交+新的隔离突破。如果事务A读取了数据D,然后数据D被事务B修改(但并未提交,事务B仍在运行中),事务A再次读取数据D时,数据修改是可见的。如果事务B回滚,那么事务A第二次读取的数据D是无意义的,因为那是事务B所做的从未发生的修改(已经回滚了嘛)。
    这叫脏读(dirty read)。

参考

本文发布于:2024-02-05 05:15:25,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170724985363356.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:(2011
下一篇:mysql 逻辑读
标签:读书笔记   原理   数据库
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23