作者:多盟乄丶 | 来源:互联网 | 2014-04-30 14:32
设计精良、性能出色的数据库引擎可以轻松地同时为成千上万的用户服务。而底气不足的数据库系统随着更多的用户同时拜访系统将大大下降其性能。最糟糕的情况下甚至可能导致系统
设计精良、性能出色的数据库引擎可以轻松地同时为成千上万的用户服务。而“底气不足”的数据库系统随着更多的用户同时拜访系统将大大下降其性能。最糟糕的情况下甚至可能导致系统的崩溃。
当然,并行拜访是任何数据库解决计划都最为器重的标题了,为懂得决并行拜访方面的标题各类数据库系统提出了各种各样的计划。SQL Server和Oracle两大DBMS也分辨采用了不同的并行处理方法。它们之间的本质差别在哪里呢?
并行拜访的标题
并行拜访呈现标题存在若干种情况。在最简略的情况下,数目超过一个的用户可能同时查询同一数据。就这种情况而言数据库的把持目标很简略:尽可能地为用户们供给快速的数据拜访。这对我们现在常见的数据库来说不成标题:SQL Server和Oracle都采用了多线程机制,它们当然能够一次处理多个恳求。
不过,在用户修正数据的情况下并行拜访标题就变得复杂起来了。显然,数据库通常只答应唯一用户一次修正特定的数据。当某一用户开端修正某块数据时, SQL Server和Oracle都能很快地锁定数据,禁止其他用户对这块数据进行更新,直到修正该数据的第1位用户完成其把持并提交交易(commit transaction)。但是,当某一位用户正在修正某块数据时假设另一位用户又正想查询该数据的信息时会产生什么情况呢?在这种情况下数据库治理系统又该如何动作呢?Oracle和SQL Server针对这一标题采用了不同的解决计划。
SQL Server方法
现在不妨假设有人开端修正SQL Server上存储的数据,于是这块数据立即被数据库锁定。数据锁定把持阻塞其他任何拜访该数据的连接——连查询把持都不会放过。于是,这块被锁定的数据只有在交易被提交或者回滚之后才干接收其他拜访把持。
下面用SQL Server随带的pubs示例数据库做一个简略示范。在Query Analyzer内打开两个窗口。在第1个窗口中履行下列SQL把持语句,更新pubs数据库中某一图书的价格:
以下为引用的内容:
use pubs go begin tran update titles set
price = price * 1.05 where title_id = 'BU2075'
由于代码中并没有履行commit语句,所以数据变动把持实际上还没有终极完成。接下来,在另一个窗口里履行下列语句查询titles数据表:
select title_id,title,price from titles order by title_id.
你什么成果也得不到。窗口底部的小地球图标会转个不停。尽管我在先前的把持中仅仅更新了一行,但是,select语句的履行对象却恰好包含了其数据正被修正的一行。因此,上面的把持不会返回任何数据,除非回到第1个窗口提交交易或者回滚。
SQL Server的数据锁定计划可能会下降系统的性能和效率。数据被锁定的时间越长,或者锁定的数据量越大,其他数据拜访用户就越可能不得不等候其查询语句的履行。因此,从程序员的角度来看,对SQL Server编程的时候应当尽量地把交易代码设计得既小又快。
在SQL Server的最近版本中,微软对SQL Server进行了某些修正,使其一次锁定的数据量大大减少,这是数据库设计中的一大重要改良。在6.5版及以前版本中,最少的数据锁定量是一页。哪怕你只在修正一行数据,而该行数据位于包含10行数据的一页上,则整页10行数据都会被锁定。显然,这么大的数据锁定量增加了其他数据拜访连接不得不等候数据修正完成的概率。在SQL Server 7中,微软引进了行锁定技巧,这样,目前的SQL Server只锁定实际正被转变的数据行。
SQL Server的解决计划听起来很简略,但实际上其幕后为供给足够的系统高性能而采用了很多措施。例如,假如你在同时修正多行数据,SQL Server则会把数据锁定范畴晋升到页级别乃至锁定全部数据表,从而不必针对每一记录跟踪和保护各自的数据锁。
Oracle方法
下面我们再看看Oracle数据库是如何实行类似把持的。首先,我打开一个SQLPlus实例履行下列查询语句(这个例子可以在Oracle 9i中示例中找到)。这个实例称做查询实例:
以下为引用的内容:
select first_name, last_name, salary
from hr.employees where department_id = 20;
代码返回两行数据,然后,再打开另一个SQLPlus实例——更新实例来履行以下命令:
以下为引用的内容:
SQL> update hr.employees 2 set salary = salary * 1.05 3
where 4 department_id = 20 5 /
代码履行后回复消息称两行数据已被更新。
留心,以上代码中并没有像在SQL Server示例那样键进“begin tran”字样的代码。Oracle的SQLPlus隐含启用交易(你还可以模仿SQL Server的行动,设置“autocommit to on”主动地提交交易)。接下来我们在SQLPlus更新实例中再履行同查询实例一样的select语句。
成果明白地表明:Michael和Pat的薪水都增加了,然而这个时候我还没有提交数据变更交易。Oracle不需要用户等候数据更新实例中把持被提交,它径直返回Michael和Pat的查询信息,但实际上返回的是数据更新开端之前的数据视图!
这时候,熟悉SQL Server的人可能会说了,在查询中设置(NOLOCK)不也能达到同样的后果吗?可是,对SQL Server而言,在数据映像之前是不能获取数据的。指定(NOLOCK)实际上只是得到了没有提交的数据。Oracle的方法则供给了数据的一致视图,所有的信息都是针对交易的、基于存储数据快照的。
假如在SQLPlus的更新实例中提交更新交易在查询实例中就能看到薪水数据产生变更。假如在查询实例中重新运行先前的查询语句,那么Oracle将返回新的薪水数值。
存储数据快照
说了半天,在给用户显示先前版本的数据的同时,Oracle是如何答应其他用户修正数据的呢?实在,只要某一用户启动了一宗修正数据的交易,之前的数据映像就会被写到一个特别的存储区域。这种“前映像”用来向任何查询数据的用户供给一致的数据库视图。这样,当其他用户在修正数据的时候,在以上的测试中我们就能看到尚未产生变更的薪金数据。
这个特别的存储区域在哪里呢?这个标题的答案就跟你正在应用的Oracle版本有关了。在 Oracle 8i及其以前版本中会为这一目标创立特别的回滚段。然而,这种举动会给数据库治理员(DBA)带来治理和调剂数据段的工作累赘。例如,DBA必需断定为此需要的数据段的数目以及大小等。假如回滚段没有准确配置,那么对交易而言它们就可能不得不排队等候回滚段中呈现必要的数据空间。
Oracle 9i就不同了,这是Oracle的最新版本,Oracle实现了一种新特征,这就是所谓的undo表空间,它有效地打消了以上的治理复杂性。固然回滚段仍然可以持续应用,但是,DBA现在可以选择创立undo表空间的方法令Oracle自己治理“前映像”的复杂空间分配。
Oracle的这种方法对程序员具有重要意义。由于回滚空间不是无限的,所以,更新交易的数据快照会代替先前交易的映像。因此,假如必要的回滚段被其他交易的映像笼罩的话。运行时间较长的查询把持就可能产生“ snapshot too old”错误。