英文文献翻译综合.docx
《英文文献翻译综合.docx》由会员分享,可在线阅读,更多相关《英文文献翻译综合.docx(23页珍藏版)》请在冰点文库上搜索。
英文文献翻译综合
毕业设计(论文)
外文翻译
题目切记,不同的约束
可得到一致的结果
专业计算机科学与技术
班级07级计科1班
学生宋龙
指导教师王家伟
重庆交通大学
2011年
切记,不同的约束可以得到一致的结果
——作者:
汤姆凯特
我们的技术专家读取一个一致的时间戳,使用正确的约束,并修改旧的并没有索引的外键。
我所理解的一致性:
事实上,一个单查询返回一个结果,是完全符合一致性的在一些时间戳上,但最近我发现了一些奇怪想象,一个特定查询将返回不一致的结果,在不同的时间戳上其返回的行中包含了数据库中的值。
为什么会这样?
这个查询是一个针对单表的简单查询,是调用的一个能打开运行其它查询的PL/SQL的函数。
这是一个有趣的问题。
首先,所谓的一致性就是要确保展示在每个人面前的页面都是。
然后我将展开这个问题,并提出解决这个问题的办法和如何对其加以纠正。
第一,在Oracle数据库中读取一致性是执行的每个查询的属性。
它可以确保在提交给应用程序的结果集中的每一行均来自于数据库的同一点的时间。
如果一个简单的查询语句,如:
SELECT*FROMa_really_big_table,需要一个小时来完成,从查询将会一致timewise到最后一行从查询返回的第一行返回那这个查询从第一行到最后一行所返回的时间戳都是一致的。
举个例子来说,假设这个“really_big_table”是一个ACCOUNTS表,表的两列分别是ACCONTNO(账号)和BLANCE(余额)。
此外,假定表中的数据是这样,在执行查询之前:
ACCOUNT#
BALANCE
123
$500
456
$200
.....这中间有几百万行数据
….
789
$300
这样我有一张数据量非常大的表(ACCOUNTS)和一个查询(SELECT*FROMACCOUNTS),这个查询将会花费一个小时来读取第一行(ACCOUNTNO=‘123’)到最后一行(ACCOUNTNO=‘789’)的数据。
对于完全相同的行数不用全部读取,当然,可以使用逐渐扫描全表来代替。
得到的结果应该是一些的时间戳的数据库中存在的结果集。
(这似乎是合理的,不是吗?
有一个答案存在?
)
由于在Oracle数据库中读取此数据,在查询开始的时候它将会随时作检查以确定其当前的时间戳。
但是不同的是,读取一致性可以用来确保结果集的时间戳是查询开始的时间(不过后来我要提到另一种方式来设置时间戳的值)。
如果从表中数据的数据库读取,表示为查询开始后被修改的数据,例如:
数据可能仍被锁定另一个事务,或它可能已更改并由另一个事务提交,在该语句开始Oracle数据库将利用撤消或回滚信息的方式来返回到以前的版本。
例如:
假设你的程序正在查询ACCOUNTS表,你的程序读取并打印第一行ACCOUNTNO=‘123’和用户的BALANCE的总和为500美元。
现在假设你要在你的报告中打印出更多的数据有2,3行或者更多,假如有人使用自动取款机从帐户123向帐户789转移100美元,并已经完成了这个操作。
那最后一行现在来看应该是这样的:
789
$400
当你花了近一个小时来查询直到查询到最后一行的数据,将会发生什么?
它真的能打印出ACCOUNTNO='789'账户的余额为400美元?
通过使用Oracle,我们知道是不能的(我100%的同意这个观点)。
如果你的查询在ACCOUNTNO=‘789’账户的余额为400美元,那你将会收到一份报告显示你有100美元将会永远存在银行。
因为在报告中会显示第一行和最后一行的账户会有同样的钱增加。
对于这个问题,在查询开始的时候数据就已经改变了,Oracle数据库回滚掉这个改变,回滚需要花费更多的时间(因为在最后的这一个小时中它的数据可能被多次修改)直到回滚到查询开始前提交的版本。
回滚完成后会将第一行后最后一行余额的值返回给你。
查询是这样的,其它的操作也如此!
假设你要查询的不是每一行的BALANCE(余额)而是查询ACCOUNTS表中BALANCE(余额)的总和。
那你得到的查询结果只有一行(而不是几百万行),但是它仍然需要花费非常多的时间去计算(去读取每一行的BALANCE(余额)的值并逐行累起来)。
在这种情况下,可能会有更多关于读取一致性的运用。
在你作求余额总和查询的时候,在你读取了第一条记录的BLANCE(余额)为500美元之后和读取最后一条记录的BLANCE(余额)为300美元之前,有人做了100美元的转账操作,没有读取一致性,如果你只是读取了最后一行的BLANCE(余额)的值(例如:
400美元),那返回的SUM(BALANCE)将会比实际的值多了100美元。
在资产负债表上这是一个明显的错误。
返回了一个错误的值,Oracle数据库应该返回同一个时间戳上的BALANCE的合计值。
这个值应该是使用ACCOUNTNO=‘789’账户的余额300美元来计算,而不是转账后的400美元来计算。
现在,让我假设你在自己的SQL声明中写一个PL/SQL函数,它的功能是查询表t的列,例如:
selecta,b,c,f(x)fromt,wherea,b,c,andx。
执行后你看到的返回的第一行的数据和最后一行的数据不一致,听起来这不应该会在Oracle数据库中发生的。
好吧,我们不在这里违反规则的读取一致性,因为每一个查询都是在读取一致性下执行的。
然而,每一个查询的读取一致性都是对其自身默认的情况下执行的。
如果您使用SQL来执行一个函数,反过来调用自己的SQL文,默认情况下每个查询执行读取本身的一致性与而非原始的SQL驱动,我可以通过拷贝EMP和DEPT表从SCOTT库中来轻松证明我的观点。
我知道这个DEPT表中有4个部门,EMP表中有14个职员,有3个人在部门10中,5个人在部门20中,6个人在部门30中。
没人认在部门40中。
我写一个一段逻辑代码在PL/SQL中计算每个部门的职员人数(在PL/SQL函数中返回结果):
SQL>createorreplace
functionf(p_deptnoinnumber)
returnnumber
2as
3l_cntnumber;
4begin
5selectcount(*)
6intol_cnt
7fromemp
8whereemp.deptno=p_deptno;
9
10do_work_in_another_transaction();
11
12returnl_cnt;
13end;
14/
函数创建完成。
关于函数中调用的其它过程:
DO_WORK_IN_ANOTHER_TRANSACTION().,这是我为这个实例写的一个存储过程,为数据库中其他用户要做类似的操作(修改正在读取的数据)和条件该业务时调用。
在实际操作中,假如有其它的用户要修改我正在读取的数据时,这个存储过程就可以实现这个操作。
SQL>createsequencesstartwith8000;
顺序创建完成。
SQL>createorreplaceprocedure
do_work_in_another_transaction
2as
3pragmaautonomous_transaction;
4begin
5foriin1..4
6loop
7insertintoemp(empno,deptno)
8values(s.nextval,i*10);
9endloop;
10commit;
11end;
12/
过程创建完成。
每次调用该过程,我在每一个部门中添加一个职员,然后提交,现在我们来查询我的数据,我将SELECT出DEPTNO和DNAME列从DEPT表中,并调用我写的函数(F)来得到每个部门的总人数通过DEPTNO,显示读取一致性的影响。
我将得到一个正确的总人数,通过使用标量子查询SELECTCOUNT(*)在我的函数中调用它自身。
SQL>selectdeptno,dname,
2(selectcount(*)
3fromemp
4whereemp.deptno=
dept.deptno)cnt1,
5f(deptno)cnt2
6fromdept
7/
DEPTNODNAMECNT1CNT2
—————————————————————————————————
10ACCOUNTING33
20RESEARCH56
30SALES68
40OPERATIONS03
注意CNT1和CNT2之间的不同,这清楚的指出了读取一致性的问题。
标量子查询在外部查询的2到4行,它是在外部查询自身的同一个时间戳上运行的。
因为它是父查询的一部分所以它共享了父简单查询相同的时间戳。
但需要注意这个函数运行同样的SQL代码所得到的结果,对于第一行,人数的统计值是正确的(CNT1和CNT2中都返回的是3),这是因为在更新之前这个结果已经得到了。
但是在结果集的第二行中,人数统计值的差值是1(CNT1为5,CNT2为6)。
这说明在得到结果之前已经做了INSERT和COMMIT操作(通过调用DO_WORK_IN_ANOTHER_TRANSACTION()存储过程),该过程在DEPTNO=20的部门中添加了一个新的职员。
第三行显示这个结果的差值增加到了2(CNT1为6,CNT2为8),最后一行显示这个结果的差值增加为3(CNT1为0,CNT2为3)。
每一行的返回的结果显示了函数(F)中不同的读取一致计数。
而不是从标量的子查询中得到。
在这个事例中每一个SQL语句都是读取一致性的(没有避免),但是每一个查询作为一个独立的声明来执行,它读取一致性是读取的它自身执行开始的时间,而不是SQL声明的开始时间。
那么在SQL声明开始的时候通过运行独立的SQL语句和PL/SQL可以得到多个不同的读取一致性,你需要读取你所有声明的读取一致性吗?
我认为最好的办法是读取第一次调用PL/SQL时的读取一致性。
我有一个口头禅是“如果你可以通过一个SQL声明来实现,那就去做吧”。
在此事例中,这里不需要通过PL/SQL来说实现,因为它会给系统造成不必要的开销(调用PL/SQL可以衡量开销)因为它可以通过直接查询得到结果。
实际上,消减查询会使其返回读取不一致的结果。
另外一种有效的方法是使用序列化(适当的时候可以设为只读)事务(参考不同的隔离级别的说明)。
使用序列化事务,所有SQL声明都将在事务开始的时候执行,在这事务期间你不会看到有提交的操作只读它们自己提交。
这可以确保你事务中的所有SQL语句都是使用同一个时间戳。
所以现在你可以从做这个事例(在你的项目中从新创建表EMP和DEPT)然后再执行查询:
SQL>settransactionisolation
事务级别
事务集;
SQL>selectdeptno,dname,
2(selectcount(*)
3fromemp
4whereemp.deptno=
dept.deptno)cnt1,
5f(deptno)cnt2
6fromdept
7/
DEPTNODNAMECNT1CNT2
—————————————————————————————————
10ACCOUNTING33
20RESEARCH55
30SALES66
40OPERATIONS00
CNT1和CNT2将会是有同样的时间戳—它们是读取一致的。
这个查询将会返回一致的结果集直到你提交该事务。
然后你可以在上面看到其他事务的业务。
另外一种办法是使用回闪查询,这并不是广泛的应用。
因此,它只有你第一次使用外部父查询的地方才适用。
在这种情况下,你将不得不通过as-of时间或者SCN(系统更改编号)和函数中的DEPTNO一样。
然后外部父查询及其它的查询执行一贯地都使用的是同样的as-of时间。
简单的来说,对于我来说最好的办法是使用单个的SQL声明(这样可以通过调用PL/SQL可以避免写重复的SQL代码)如果你担心代码的维护(你可以隐藏掉维护的计数功能)我建议你使用视图。
你可以很容易地使用视图来隐藏重复适用的代码像调用一个函数一样。
我举一个简单的例子,我甚至不会使用视图和标量查询,然而:
SQL>selectdept.deptno,dept.dname,
count(emp.empno)
2fromdeptleftouterjoinemp
3on(dept.deptno=emp.deptno)
4groupbydept.deptno,dept.dname
5orderbydept.deptno
6/
DEPTNODNAMECOUNT(EMP.EMPNO)
————————————————————————————
10ACCOUNTING3
20RESEARCH5
30SALES6
40OPERATIONS0
这只是一个简单的单查询,简单的大容量的SQL语句。
它将始终是读取一致。
表和列约束
什么是表级和列级的约束?
为什么我们不能添加NONULL来作表级的约束?
列级约束的范围是仅是列的定义,一个表级的约束,在另外一方面,我们可以在表里看到每一列。
这就是这两种约束之间的不同。
许多列级的约束,可以在表级别表示,NOTNULL约束的除外。
但方过来就不可以了。
这并不意味着所有的约束都在表级别表示,而是有可能在表级别表示它们所有约束。
这是我强烈的意见,列级约束应该使用,除非它不能用。
这样的话,如果你能列级表示你所有的约束,那你可以这样表示列约束。
一个列约束在语法上市清晰的,这是很明显的,因为它可以应用于单个的列中。
这是非常有意义的,因此要在列级使用约束。
使用表级约束就意味着要包含到多个的列。
你可以通过约束的定义得到条件的信息。
如果你有一个列的约束,你知道它只是影响单个的列,因此你可以不用管它。
在另外一方面,遵循这一思想,如果你有一个表级的约束,你知道这意味着你必须使用它来定义至少其中的两列。
至于它们的运行实现,列和表级约束是相同的。
没有运行时表级约束和列级约束的差异。
可能会有人指出在数据库中NOTNULL约束在技术可以实施在CHECK约束。
例如:
如果你创建了下面这张表:
SQL>createtablet
2(xintnotnull,
3yintcheck(yisnotnull),
4zint,
5constraintz_check
check(zisnotnull)
6);
表创建;
你会发现这三个约束的最终数据字典中能找到很多相同的地方。
SQL>selectconstraint_type,
2search_condition
3fromuser_constraints
4wheretable_name='T';
CSEARCH_CONDITION
———————————————————————————
C"X"ISNOTNULL
Cyisnotnull
Czisnotnull
CHECK约束是通过NOTNULL约束来实现的(检查它的CONSTRAINT_TYPE是不是C)。
不要让这一事实诱使您向使用CHECK约束来验证的列不是空。
不过,如果列是为空的,事实上,你可以使用NOTNULL约束。
因为优化器确认不存在空值,但不是检查检查约束您编写自己的存在不为空。
例如:
如果你为表创建索引X,您将看到,使用该索引优化程序可以执行的COUNT(*),如清单1中所示。
代码清单1:
优化器知道X是NOTNULL.SQL>设置自动跟踪的说明
SQL>createindext_x_idxont(x);
Indexcreated.
SQL>select/*+index_ffs(tt_x_idx)*/count(*)fromt;
COUNT(*)
———————————————
0
——————————————————————————————————|Id|Operation|Name|Rows|Cost(%CPU)|Time|
————————————————————————————————————————————————————————————————————
|0|SELECTSTATEMENT||1|2(0)|00:
00:
01|
|1|SORTAGGREGATE||1||
|2|INDEXFASTFULLSCAN|T_X_IDX|1|2(0)|00:
00:
01|
可是,如果你用索引Y替换该索引,你将看到优化程序无法使用这种新的索引执行COUNT(*),清单2所示.
代码清单2:
优化器不知道Y是NOTNULL.
SQL>dropindext_x_idx;
Indexdropped.
SQL>createindext_y_idxont(y);
Indexcreated.
SQL>select/*+index_ffs(tt_y_idx)*/count(*)fromt;
COUNT(*)
———————————————
0
———————————————————————————————————————————————————————————————————
|Id|Operation|Name|Rows|Cost(%CPU)|Time|
———————————————————————————————————————————————————————————————————
|0|SELECTSTATEMENT||1|2(0)|00:
00:
01|
|1|SORTAGGREGATE||1|||
|2|TABLEACCESSFULL|T|1|2(0)|00:
00:
01|
在第一种情况中,使用索引X,优化程序知道X不为空因此X索引指出表中的每一行,所以它可以安全的通过索引的行计数.而第二种情况,使用索引Y,优化程序并不知道Y不为空,因为CHECK没有提供足够的信息使优化器知道.因为空项不是到Oracle数据库中B树索引而且由于Y由优化程序假定允许空值,优化程序不可以使用索引Y,因为假定索引可能不指向表中的行.
这说明了为什么要用具体.在表约束中要尽可能的使用更特定的列级约束,当维护者稍后检查架构时约束的选择的系统信息要传递给维护者.你要使用更具体的NOTNULL约束对等效的CHECK约束,因为在优化程序在分析时,它传递更详细的的信息.
英文文献:
OnConsistentResults,DifferentConstraints,andUnlearning
ByTomKyte
Ourtechnologistreadsasofaconsistentpointintime,usestherightconstraint,andrevisesoldlearningonunindexedforeignkeys.
Iunderstandreadconsistency—thefactthataresultsetreturnedbyasinglequeryisentirelyconsistentwithrespecttosomepointintime—butrecentlyI’venoticedsomethingstrange.Acertainqueryisreturninginconsistentresults:
therowsreturnedcontainvaluesfromthedatabaseasofdifferentpointsintime.Whyisthis?
Thequeryisasimplequeryagainstasingletable,anditcallsaPL/SQLfunction,whichinturnrunsanotherquery.
Thisisaninterestingquestion.FirstI’llmakesureeveryoneisonthesamepageanddemonstratewhatreadconsistencymeans.ThenI’lldemonstratethisissueandsuggestsomeapproachestocorrectit.
First,readconsistencyisanattributeofeveryqueryeverexecutedinOracleDatabase.Itensuresthateveryrowinaresultsetpresentedtoanapplicationcomesfromthedatabaseasofthesamepointintime.IfasimplequerysuchasSELECT*FROMa_really_big_tabletakesonehourtocomplete,thefirstrowreturnedfromthequerywillbeconsistenttimewisewithrespecttothelastrowreturnedfromthequery.Forexample,supposethe“reallybigtable”isanACCOUNTStableandhascolumnsACCOUNT#andBALANCE.Further,assumethatthedatainthetablelookslikethisbeforethequeryisexecuted:
ACCOUNT#
BALANCE
123
$500
456
$200
…millionsofrowshere
….
789
$300
So,Ihaveaverylargetable(ACCOUNTS)andaquery(SELECT*FROMACCOUNTS)thatwilltakeanhour