第一部分:查询
本章主要讨论的是数据在进行查询运算的时候的一些评估以及优化的方法。然后我们其实是基于统计信息来估计各种方式的效率以及消耗的资源的(统计信息不是实时更新的,而是在数据库压力比较小的时候更新)。优化则是基于代价式的,基于启发式的(走一步看一步),现在的DBMS基本上都是二者结合。
每个磁盘和主存数据传送之间都是以块的数量来衡量的,包括每次针头的读取到磁盘上的内容所消耗的时间。在这之前我们先假定关系运算是要不断的访问磁盘的。并且我们会主动忽略写延迟的时间。
首先衡量查询算发的指标主要是磁盘存取时间,因为CPU的运转其实非常的快,相比于磁盘存取来说其实没有特别大的比较意义。我们有一个具体的统计模式。
下面我们来讨论不同算法的代价,首先是选择运算,分为文件扫描和索引文件扫描两种,前者还可以分为线性搜索算法和二分法搜索算法。然后是连接运算,嵌套循环连接算法和非嵌套循环连接算法以及一些其他的不用我们掌握的算法。
宏观上的代价可以根据实体化计算方法和流水线方法两种来区分。
查询优化的步骤就是,先得到最基本的查询算法,然后得到等价表达式使之达到最优,最后给新的表达式注释好算法、索引和执行方法。
第二部分:事务
事务就是一堆动作的集合,他们是不可分割的,要么一起做,要么一起不做。由于性能上的原因,DBMS经常要交叉的执行若干个事务,所以才提出了这么一个概念。
首先事务有ACID四种特性,分别是原子性、一致性、隔离性和持久性。原子性就是说事务里面的动作要么就一起做要么就都不做;一致性说的是事务对于里面的动作要保持一致;隔离性说的是事务之间的运行必须相互隔离,当某一事务在访问某一数据时,其他的事务就要根据并发控制管理器的管理与之隔离;持久性指的是一次事务对数据库的改变应该是永久的。
事务在五种状态之间来回切换,最基本的是运行状态,然后可以到部分提交状态或者失败状态,他们分别会进一步变成提交状态和中止状态,这两种状态都标志着数据库的停止运转。
事务发生故障了怎么办?
然后我们就要开始讲一个事务故障恢复的问题了,一共会发生四种类型的故障,事务故障、系统故障、介质故障和病毒。事务故障就是事务本身发生的错误,错了之后没办法,UNDO重新来,这种故障是用户不知道的,由DBMS自动完成;系统故障是系统出了问题,我们会根据日志文件记录的内容把过去的事务分成REDO队列和UNDO队列,其中完成但是未提交的放进REDO到时候直接可以提交结果,UNDO里面放的是还没有完成的,这些要像事务故障一样重新做;介质故障就是磁盘或者啥的坏掉了,这就没办法了,我们需要用到数据库的副本了,用到了数据库镜像(没有发生问题的时候可以用来做数据库并行处理),把数据库的备份调出来,然后根据我们的日志文件执行与系统故障相同的一系列操作。还有就是人工破坏的病毒。(影子数据库?副本?镜像?)
日志这个东西会在故障发生时就发生回滚,它记录着数据库各个事务的开始点和提交点,以及表、元组、属性和更新前后的值,到时候可以拿来调用。日志必须要严格按照顺序来,我们在修改数据库之前必须先修改日志不然的话就白弄了数据库出了故障日志还没写就查不到了。
但有时候恢复日志太麻烦,浪费很多不必要的检查时间,这个时候我们要引入一个check point来缓解这一问题,隔一段时间就设置一个检查点,只需要按点来检查。
第三部分:并发执行
并发控制会导致事务的隔离性不一定能保持,所以这个时候就需要DBMS的并发控制机制来实现,主要有两种方法,一个是封锁机制,让并发其中一个以某种算法开始等待,另一个是时间戳算法,让冲突中的某一个事务回滚。
封锁机制是规定事务必须要在想访问的数据上面加锁(向DBMS请求)才可以进行正常的访问。锁有共享锁和排他锁,而对于同一个数据的访问,除了两个排他锁可以一起之外,其他都不能并行。这样虽然可以实现一致性,但是会会导致解锁过早使得数据一致性出问题,也会导致死锁和饿死。其中,因为如果某个写事务过早的解锁提交,会导致数据的不一致,这个时候如果设置一个两段的解锁机制就可以防止这样的情况发生(因为如果解锁了,那么之后其他就不能读了)。然后,饿死是因为如果有一个共享锁先进入,然后另一个事务想要排他锁就需要等待,但是之后来的需要共享锁的就不用等待,这样如果后来的事务需求的全是共享锁,排他锁就不可以用了。解决死锁的问题,有预防和检测修复两种途径,其中预防有两种途径,一是受伤等待,二是等待回滚。检测恢复就是周期性检查死锁,检测到了就回滚一个或多个事务,考虑选哪个,滚多远,避免一直滚(饿死)。
时间戳排序协议,在事务开始之间按顺序分配一个时间戳。严格按照这个时间戳从小到大的顺序进行。然后还要设置一个W-TS和R-TS,一开始设置为0,然后由新的动作进来就做比较,如果小的话就回滚,大的话就替换然后执行,但是如果两个写指令,时间戳排在后面的先写了,那没关系,就放走吧,因为恢复了没有意义(这个是托马斯写规则)。
并发事务里面有一个隔离等级机制,从高到低分别是读未提交、读已提交、可重复读、可串行化。其中读未提交就是读了没提交,这样会不能重复度、有脏数据、有幻影。读已提交没有脏数据但是不能重复读,可重复读就只是有幻影,可串行化就是都可了,用了上述两种协议。