一、关系查询处理和查询优化
关系数据库系统的查询处理
查询处理的步骤分为4个阶段:查询分析、查询检查、查询优化和查询执行。
查询语句(由此语句进行查询)
1、查询分析
首先对查询语句进行扫描、词法分析和语法分析。对SQL关键字、属性名和关系名等,进行语法检查和语法分析 ,即判断查询语句是否符合SQL语法规则。
2、查询检查
对合法的查询语句进行语义检查,即根据数据字典中有关的模式定义检查语句的数据库对象,如关系名、属性名是否存在和有效。
3、查询优化
查询优化和分为代数优化和物理优化:代数优化是指按照一定的规则,通过对关系代数表达式进行等价变换,改变代数表达式中操作的次序和组合,使查询执行更高效;
物理优化则是指存取路径和底层操作算法的选择。选择的依据可以是基于规则的,也可以是基于代价的,也可以是基于语义的。
4、查询执行
依据优化器得到的执行策略生成查询执行计划,有代码生成器(code generator)生成执行这个查询计划的代码,然后加以执行,回送查询结果;
实现查询操作的实例:(数据库优化的最终操作:尽量减少IO的块数)
1、选择操作的实现
(1)、简单的全表扫描算法(table scan)(全扫:io代价:总的块数m block + O(n)元组代价)
(2)、索引扫描算法(index scan)
通过索引先找到满足条件的元组指针,再通过元组指针在查询的基本表中找到数组;
2、连接操作的实现:(连接操作是查询处理中最常用也是最耗时的操作之一。)
(1)、嵌套循环算法(nested loop join):在实际实现中数据存取是按照数据块读入内存,而不是按照元组进行I/O的。
(2)、排序-合并算法(sort-merge join或merge join):1、如果参与连接的表没有排好序,首先对表按连接属性排序 。2、在取表中的连接属性,把它们表中的属性连接起来。
(3)、索引连接(index join)算法:(B+树 索引+基地址的方式)
(4)、hash join算法:以数组的方式:基地址+偏移(快);
关系数据库系统的查询优化
查询优化的优点不仅在于用户不必考虑如何最好的表达查询以获得较高的效率,而且在于系统可以比用户程序的“优化”做的更好,这是因为:(1)、优化器可以从数据字典中获取许多统计信息 (2)、如果数据库的物理统计信息改变了,系统可以自动对查询进行重新优化以选择相适应的执行计划。(3)、优化器可以考虑数百种不同的执行计划,而程序员一般只能考虑有限的几种可能性。
(4)、优化器中包括了许多复杂的优化技术,这些技术往往只有最好的程序员才能掌握。
总代价=I/O代价 +CPU代价 +内存代价+通信代价(数据结构:内存地址 ; 数据库:硬盘的逻辑地址)
代数优化
代数优化策略是通过对关系代数表达式的等价变换来提高查询效率。
1、连接,笛卡尔积的交换律
2、连接、笛卡尔积的结合律
3、投影的串接定律
4、选择的串接定律
5、选择与投影操作的交换律
6、选择与笛卡尔积的交换律
7、选择与并的分配律
8、选择与差运算的分配律
9、选择对自然连接的分配律
10、投影与笛卡尔积的分配律
11、投影与并的分配律
查询树的启发式优化
(1)、选择运算应尽可能先做
(2)、把投影运算和选择运算同时进行
(3)、把投影同其前或其后的双目运算结合起来
(4)、把某些选择同在它前面要执行的笛卡尔积结合起来成为一个连接运算。
(5)、找出公共子表达式。
物理优化
代数优化改变查询语句中操作的次序和组合,但不涉及底层的存取路径。物理优化就是要选择高效合理的操作算法或存取路径。
选择的方法可以是:
(1)、基于规则的启发式优化
(2)、基于代价估算的优化
(3)、两者结合的优化方法
二、数据库恢复技术
1、事务
所谓事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
事务和程序是两个概念。一般来讲,一个程序中包含多个事务。
在SQL中,定义的事务的语句一般有三条:(1)、BEGIN TRANSACTION (2)、COMMIT:即是提交事务的所有操作。将事务中所有对数据库的更新写回到磁盘上的物理数据库中去。 (3)、ROLLBACK:所有已完成的操作全部撤退,回滚到事务开始时的状态。
事务是恢复和并发控制的基本单位。
2、事务的ACID特性
原子性(Atomicity):事务是数据库的逻辑工作单位,事务中包括的诸操作要么是都做,要么都不做。
一致性(Consistency):事务执行的结果必须是使数据库从一个一致状态变到另一个一致性状态。
隔离性(Isolation):一个事务的执行不能被其他事务干扰。
持续性(Durability):也称永久性(Permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
3、故障的种类
(1)、事务内部的故障:例如运算溢出、并发事务放生死锁而被选中撤销该事务、违反了某些完整性限制而被终止等。事务故障意味着事务没有达到预期的终点,恢复程序要在不影响其他事务运行的情况下,强行回滚该事务,即撤销该事务已经作出的任何对数据库的修改,使得该事务好像根本没有启动一样,该类恢复操作称为事务撤销(UNDO)
(2)、系统故障:系统故障是指造成系统停止运转的任何事件,使得系统要重新启动。第一个:一些尚未完成的事务的结果可能已送入物理数据库,从而造成数据库可能处于不正确的状态,需要(UNDO);第二个:发生系统故障时,有些已完成的事务可能有一部分甚至全部留在缓冲区,尚未写回到磁盘上的物理数据库中,系统故障使得这些事务对数据库的修改部分或全部丢失,这也会使数据库处于不一致状态,因此应将这些事务已提交的结果重新写入数据库(REDO)。
(3)、介质故障
(4)、计算机病毒
总结:各类故障对数据库的影响有两种可能性,一是数据库本身被破坏,二是数据库没有被破坏,但数据可能不正确,这是由于事务的运行被非正常终止造成的。恢复的基本原理十分简单,冗余;利用别处的冗余数据进行重建。
4、恢复的实现技术
建立冗余数据最常用的技术是数据转储和登记日志文件(logging)。数据库恢复是将数据库从错状态恢复到某一已知的正确状态的功能。
4.1、数据转储
静态转储(停机更新)是在系统中无运行事务时进行的转储操作。
动态转储(不停机更新)是指转储期间允许对数据库进行存取或修改。缺点:转储结束时后援副本上的数据并不能保证正确有效。
海量转储是指每次转储全部数据库
增量转储则指每次只转储上一次转储后更新过的数据。
4.2、登记日志文件
日志文件的格式和内容
日志文件是用来记录事务对数据库的更新操作的文件;两种格式:已记录为单位的日志文件和以数据块为单位的日志文件
日志文件中需要登记的内容包括:1、各个事务的开始(BEGIN TRANSACTION)标记 2、各个事务的结束(COMMIT或ROLLBACK)标记 3、各个事务的所有更新操作。
每个日志记录的内容包括:事务标识,操作的类型,操作对象,更新前数据的旧值,更新后数据的新值;对于以数据块为单位的日志文件,日志记录的内容包括事务标识和被更新的数据块。
日志文件的作用:日志文件用于保存对数据的更新操作;
(1)、事务故障恢复和系统故障恢复必须用日志文件
(2)、在动态转储方式中必须建立日志文件,后备副本和日志文件结合起来才能有效地恢复数据库。
5、恢复策略
5.1、事务故障的恢复
(1)、反向扫描日志文件,查找该事务的更新操作。
(2)、对该事物的更新操作执行逆操作
(3)、继续反向扫描日志文件,查找该事务的其他更新操作,并做同样处理
(4)、如此处理下去,直到读到此事务的开始标记,事务故障恢复就完成了。
5.2、系统故障的恢复
(1)、正向扫描日志文件,找出在故障发生前已经提交的事务,将其事务标识记入重做队列(REDO-LIST)。同时找出故障发生时尚未完成的事务(这些事务只有BEGIN TRANSACTION记录,无相应的COMMIT记录),将其事务标识记入撤退队列(UNDO-LIST)。
(2)、反向扫描日志文件,对每个撤退事务的更新操作执行逆操作,将日志文件记录中“更新前的值”写入数据库。
(3)、对重做队列中的各个事务进行重做处理
6、具有检查点的恢复技术
具体的检查点(checkpoint)记录相关技术请查阅相关的书籍。
系统使用检查点方法进行恢复的步骤是:
(1)、从重新开始文件中找到最后一个检查点记录在日志文件中的地址,由该地址在日志文件中找到最后一个检查点记录。
(2)、由该检查点记录得到检查点建立时刻所有正在执行的事务清单ACTIVE-LIST.
UNDO-LIST:需要执行UNDO操作的事务集合
REDO-LIST:需要执行REDO操作的事务集合
把ACTIVE-LIST暂时放入UNDO-LIST队列,REDO队列暂为空。
(3)、从检查点开始正向扫描日志文件。1、如有新开始的事务Ti,把Ti暂时放入UNDO-LIST队列;2、如有提交的事务Tj,把Tj从UNDO-LIST队列移到REDO-LIST队列;直到日志文件结束;
(4)、对UNDO-LIST中的每个事务执行UNDO操作,对REDO-LIST中的每个事务执行REDO操作。
三、并发控制
事务可以一个一个地串行执行,即每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行。在单处理机系统中,事务的并行执行实际上是这些并行事务的并行操作轮流交叉运行。1、CPU时间切片 2、抢占式的运行:谁抢到CPU,谁运行。
并发操作带来的数据不一致性包括丢失修改(lost update)、不可重复读(non-repeatable read)、读“脏”数据(dirty read).
具体的操作可以参考相关的资料
并发控制的主要技术有封锁(locking)、时间戳(timestamp)、乐观控制法(optimistic scheduler)和多版本并发控制(multi-version concurrency control,MVCC)等。
封锁
基本的封锁类型有两种:排它锁(exclusive locks,简称X锁)和共享锁(share locks,简称S锁)。
排他锁又称为写锁:若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事物都不能再对A加上任何类型的锁,直到T释放A上的锁为止。这就保证了其他事务在T释放A上的锁之前不能在读取和修改A。
共享锁又称为读锁:若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加上S锁,而不能加X锁,直到T释放A上的S锁为止。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
排他锁和共享锁的相容矩阵(compatibility matrix)
Y=Yes,相容的请求 |N=No,不相容的请求
封锁协议(通过协议维护一致性)
1、一级封锁协议
一级封锁协议是指,事务T在修改数据R之前必须先对其加X锁,直到事务结束才是释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。
一级封锁协议可防止丢失修改,并保证事务T是可恢复的。但是不能保证可重复读和不读“脏”数据。
2、二级封锁协议
二级封锁协议是指,在一级封锁协议基础上增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。
但是它不能保证可重复读。
3、三级封锁协议
三级封锁协议是指,在一级封锁协议的基础上增加事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
活锁和死锁
活锁:某一线程有可能是永远处于等待的情况。
死锁:T1在等待T2,而T2又在等待T1的局面,T1和T2两个事务永远不能结束,形成死锁。
死锁的预防:(1)、一次封锁法:一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行。
(2)、顺序封锁法
死锁的诊断与解除:(1)、超时法 (2)、等待图法
封锁的粒度
封锁对象的大小称为封锁粒度(granularity)。封锁对象可以是这样一些逻辑单元:属性值、属性值得集合、元组、关系、索引项、整个索引直至整个数据库;也可以是这样一些物理单元:页(数据页或索引页)、物理记录等。
多粒度封锁:显示封锁是应事务的要求直接加到数据对象上的锁;隐式封锁是应该数据对象没有被独立加锁,是由于其上级结点加锁而使该数据对象加上锁。
意向锁
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。
1、IS锁
如果对一个数据对象加IS锁,表示它的后裔结点拟(意向)加S锁。
2、IX锁
如果对一个数据对象加IX锁,表示它的后裔结点拟(意向)加X锁。
3、SIX锁
如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX=S+IX。
数据锁的相容矩阵
Y=Yes,表示相容的请求 N=No,表示不相容的请求
来源:oschina
链接:https://my.oschina.net/u/4314127/blog/3655507