原始数据库里面
client_id      fund_account
100006        100006
疑问1 :我再plsql里面分别执行以下语句
   
   update clientrelation set fund_account=100007 where client_id=100006;
   上面执行之后,等待3秒,是否修改的记录一定已经写入了数据文件里面?
疑问2:
    上面的事务不提交,我在同一个页面执行select * from clientrelation ; 发现查询出来的fund_account确实已被修改为100007.
但我重新打开一个sql窗口,再执行select * from clientrelation ; 发现查询出来的fund_account并未改变,还是100006.
这是否是因为oracle不允许脏读,所以新开窗口查询的是undo里面的记录? 那为何以前窗口里面select * from clientrelation ;查出改后的记录?
疑问3:
我看网上说redo是在SGA有缓存区的,那undo有么,假如更新了大量条数据。redo缓存区不够,那执行undo redo的顺序是怎样的?

解决方案 »

  1.   

    1、执行完 update 后,只是修改了内存中的数据,不会写到数据库中的;
    2、一个会话未提交的数据,另一个会话是查不到的;
    3、UNDO 的不够的话,会有经典错误提示, ORA-01555
      

  2.   

    1、不一定,但是这个修改的redo日志可能已经写入了在线日志,除非因为某些原因,LGWR陷入了等待,因为LGWR 3秒内会写online redo,当然这只是LGWR写的其中一个条件,其他还有提交/回滚、log buffer 1/3写、1M写等等。只要redo持久化了并保证不丢失,那么这次修改就不会丢失;2、未提交之前,其他会话肯定无法读到修改的记录,你的想法是对的,oracle默认的事务隔离级别就是read commited;3、参考10g后的imu,这东西很复杂,非三言两语说的清。
      

  3.   


    对于第一点我有疑问,应该是LGWR将redo buffer中的信息写入到物理文件之后 ,DBWR会立刻把脏数据区里面的放到硬盘上吧,我有一个体验就是 往一个空表里面插入20W条记录,插入很慢,但提交commit很快。我觉得再commit之前数据应该就已经更新到硬盘里面了对于第二点的话。我想知道update不提交的话,同一个会话内select是从哪里查的数据
      

  4.   


    我的意思是LGWR 3秒内会写online redo,后面应该就会调用DBWN写入硬盘, 除了别其他事务锁住表了之外,应该3秒内能把修改的数据更新到硬盘上吧
      

  5.   


    我的意思是LGWR 3秒内会写online redo,后面应该就会调用DBWN写入硬盘, 除了别其他事务锁住表了之外,应该3秒内能把修改的数据更新到硬盘上吧还是那个答案:不一定,写日志和写脏数据是由不同的后台进程来实现的,LGWR没有指挥DBWR的功能,而且这样,会严重影响LGWR写日志的效率,相反的,DBWR倒是反而有指挥LGWR的功能,LGWR触发其中有一个很容易被人遗忘的条件,那就是:在某条redo保护的脏数据被DBWR写入数据文件文件前,LGWR必须将相关redo从log buffer刷入online redo log。这两个后台进程,其实都有自己的节奏,和你表锁了不锁是完全风牛马不相及的事情。上面提到了数据不丢失之类的话语,主要想说的就是:oracle是通过日志来保证不丢数据更改的,只要日志写入磁盘,那么这次更改就不会丢失(还有个前提:硬件不损坏),在一个某时刻的磁盘数据基础上,可以应用这些保存着更改的redo,从而做到数据更改不丢失,可以说,从功能上来讲,和DBWR写不写脏数据完全没关系。其实你可以光想想啊:如果3秒内脏数据就要写入数据文件,那是多么大的开销!在一个繁忙的系统中——有些数据块会被频繁的访问,你更新的数据所在的数据块又可能有几十条甚至上百条的记录,在访问数据块(注意是访问,select同样需要读取buffer cache,除非某些特定的场景,可能会直接物理读,比如打开了并行)的时候,如果buffer cache中没有,那么就又会出现一次物理读,Oracle会愿意干这样的事情吗?
      

  6.   


    我的意思是LGWR 3秒内会写online redo,后面应该就会调用DBWN写入硬盘, 除了别其他事务锁住表了之外,应该3秒内能把修改的数据更新到硬盘上吧
    没有commit 之前,只是修改内存的数据,
    commit 后,只写日志(确认日志)。同一个会话更新完以后再查询数据,会从内存中查询(会话的专属内存)
      

  7.   


    我的意思是LGWR 3秒内会写online redo,后面应该就会调用DBWN写入硬盘, 除了别其他事务锁住表了之外,应该3秒内能把修改的数据更新到硬盘上吧
    没有commit 之前,只是修改内存的数据,
    commit 后,只写日志(确认日志)。同一个会话更新完以后再查询数据,会从内存中查询(会话的专属内存)没有commit之前,更改过的数据也有可能已经写入数据文件的 
      

  8.   

    1、没有commit的数据有可能在内存中,也有可能被写到了文件中,commit是改变数据的逻辑状态,而不是物理状态。你写一个1000万记录的查询,内存可以撑爆,但oracle没问题,因为此时已经写到了硬盘中
    2、同一个事务下能看到,另外启动一个session,就看不到了,这恰好说明了事务隔离
    3、假如更新了大量条数据,redo缓存区不够,redo有日志文件,再不够了还有archive,不怕的。undo不够就有报错。
      

  9.   

    1.修改不提交等待3s 
    修改的数据会记录到redo log file中,但不写入到数据文件中
    2.其他会话可不可见和事物的隔离级别有关,oracle默认的事物隔离级别是read commit (提交读) 所以其他会话不能看到修改的
    如果事物隔离级别为read uncommit (未提交读)那么在其他会话可以看到修改
    3.有缓存区
    --DML 更新数据操作:
    1. 创建一个改变向量描述undo数据块的改变;
    2. 创建改变向量,描述数据块的改变;
    3. undo改变向量存入IMU日志缓冲区
    4. 将每条重做改变向量写到私有redo区(private log buffer)
    6. 将IMU 记录和Pirvate log buffer记录合并成一条改变记录,结束事务
    7.将重做改变记录复制到日志缓冲区,并改变这个块。