假设银行系统有一个表,某一列为账户存款余额,数据量假设为五千万条。
现在要求统计表内所有账户余额总和;
假设查询需要20分钟,13:00开始查询,13:20才能查询结束,
但是13:10的时候有一个事务,要将第1000万条数据余额扣减5000,将第4000万条数据增加4800,
问:查询结果是否准确?
请详细分析。
有Oracle、DB2、SqlServer都懂的朋友还可以分析一下各种数据库在这个处理上有何不同。
不要怕分数不够,还可以补加。
谢谢各位!

解决方案 »

  1.   

    oracle应该会根据归档的日志查询到13:20之前提交了数据库的所有的记录。
      

  2.   

    oracle 和 sql server 数据库默认都可以保证语句级的读一致性,也就是保证在查询语句执行期间所查询的数据保持一致。但是,oracle 和 sql server 所使用的技术有差别。
    oracle 使用的“多版本模型”(undo 段)来确保读一致性,其关键在于合理设置事务提交后 undo 段的保留时间(undo_retention)。
    对于 lz 提出的场景,
    如果更新事务执行的时间较长,超过了 13:20(似乎不太可能哦),那么其更改数据对应 undo 段将一致保留(因为事务没有提交),对查询就没有什么影响。
    如果更新事务执行的时间很短(如只有几秒),那么查询语句是否可以读取到一致的数据,就取决于 undo 段保留时间,如果设置的太短,那么 undo 段就有可能被其他事务覆盖,查询语句将可能无法读取到一致的数据。sql server 默认使用的“锁机制”来确保读一致性。对于 lz 提出的场景,查询语句会在查询期间对所查询的记录保持 s 锁,其会阻止更新事务对这些记录的修改,也就是说,更新事务要一致等到查询执行完毕才会被执行。
    但是,在 sql server 2005 及以上版本,sql server 可以使用“行版本控制”(快照事务)来确保读一致性——通过在 tempdb 数据库中存储修改数据原先的版本。但是当 TEMPDB 数据库已满时,更新操作将停止生成行版本,但会继续;但是由于特定的行版本不存在,查询操作可能会失败。因此,其确保查询可以取到一致的数据的关键在于为 tempdb 数据库分配足够的空间。db2 太高级,就不了解了。
      

  3.   

    不脏读是数据库管理系统的最起码要求。
    oracle、db2、sqlserver都支持一致性读取
    对于oracle来说,13:10查询数据时,数据立即被“冻结“在这一时刻
    (实际上,这是通过undo段来实现的)。
    13:20查询统计出的数据也是13:10那一刻的帐户余额之和。
      

  4.   

    别的数据库原理我没研究,说说oracle.
    oracle是多版本的数据库,写数据也不会阻塞读数据,因此保证了读数据的准确性。
    无论你并发不并发,你的查询,求和运算都是没有问题的,但是他的查询结果是对应一个具体的版本的。
      

  5.   

    在orcle中查询的开始时间是13:00 到13:20 结束,在13:00时数据没有发生变化,所以select捞出来的数据是13:00这个时间点的数据,而不会用13:10这个时间点更新的数据
      

  6.   

    不需要冻结呀,oracle是根据scn来的。
      

  7.   

    scn是啥?
    本新鸟不懂……
      

  8.   

    你的oracle的undo空间足够的话,当推进到中间变化的2行时,它会根据undo段自动的去查13:00那个时间的数值的sqlserver的话,在这个事务开始的时候,会给表数据加上共享锁(行,键,或者升级为表锁),根据你汇总数据的group by条件,如果是某些键,sqlserver可能会用到键锁,尽量只锁定你需要的这部分数据.转账事务可以读取,但不能修改第一个事务放置了共享锁的数据.你13:10开始的转账事务会堵在那,直到13:20你的汇总钱的事务完成