posts - 188,comments - 176,trackbacks - 0

          在大型的數據庫應用中,我們經常會有針對表與表之間的關鍵建進行字段更新,那么在這個時候,我們就不能寫簡單的update來實現更新操作,而要針對具體的數據量來進行批量的update,下面幾個例子是常用的SQL,將其做個對比,歡迎大家提出更好,更高效的SQL實現。


          數據庫:Oracle 9i  測試工具:PL/SQL

          定義2張測試表:T1,T2
          T1--大表 10000條 T1_FK_ID
          T2--小表 5000條  T2_PK_ID
          T1通過表中字段ID與T2的主鍵ID關聯


          模擬數據如下:

          --T2有5000條記錄
          create table T2 as select rownum id, a.* from all_objects a where 1=0;
          //T2表的字段和all_objects表字段類型以及默認值一致,但索引初始化了,需要重新設置

          --創建主鍵ID,向T2表copy數據
          alter table T2 add constraint T2_PK_ID primary key (ID);
          insert /*+ APPEND */ into T2 select rownum id, a.* from all_objects a where rownum<=5000;
           
          --T1有10000條記錄          
          create table T1 as select rownum sid, T2.* from T2 where 1=0;

          -- 創建外鍵ID,向T1表copy數據
          alter table T1 add constraint T1_FK_ID foreign key (ID) references t2 (ID);
          insert /*+ APPEND */ into T1 select rownum sid, T2.* from T2;
          insert /*+ APPEND */ into T1 select rownum sid, T2.* from T2;

          --更新Subobject_Name字段,初始為NULL
          update T2 set T2.Subobject_Name='StevenHuang'


          需求:我們希望能把T1表的Subobject_Name字段也全部更新成'StevenHuang',也就是說T1的10000條記錄都會得到更新,以下SQL語句均在PL/SQL命令窗口測試。

          方法一:
          寫PL/SQL,開cursor

          declare 
           l_varID 
          varchar2(20);
           l_varSubName 
          varchar2(30);
           
          cursor mycur is select T2.Id,T2.Subobject_Name from T2;
          begin 
           
          open mycur; 
           loop
                
          fetch mycur into l_varID,l_varSubName;
                
          exit when mycur %notfound;
                
          update T1 set T1.Subobject_Name = l_varSubName where T1.ID = l_varID;
           
          end loop;
           
          close mycur;
          end;

          ---耗時39.716s
          顯然這是最傳統的方法,如果數據量巨大的話(4000萬記),還會報”snapshot too old”錯誤退出,PL/SQL工具會掛掉

          方法二:
          用loop循環,分批update

          declare 
            i 
          number;
            j 
          number;
          begin
            i :
          = 1;
            j :
          = 0;
          select count(*into j from T1;
            loop
              
          exit when i > j;
              
          update T1 set T1.Subobject_Name = (select T2.Subobject_Name from T2 where T1.ID = T2.ID) where T1.ID >= i and T1.ID < 

          (i 
          + 1000);
              i :
          = i + 1000;
            
          end loop;
          end;

          --耗時0.656s,這里一共循環了10次,如果數據量巨大的話,雖然能夠完成任務,但是速度還是不能令人滿意。(例如我們將T1--大表增大到100000記錄 T2--小表增大到50000記錄,將耗時10.139s)

          方法三:
          --虛擬一張表來進行操作,在數據量大的情況下效率比方法二高很多.
             注:此語句下T1,T2表中必須有相應的主外建關聯,否則sql編譯不能通過.

          update (select T1.Subobject_Name A1,T2.Subobject_Name B1 from T1,T2 where T1.ID=T2.ID) set A1=B1; 

          --耗時3.234s (T1--大表增大到100000記錄 T2--小表增大到50000記錄)
          *以上所有操作都已經將分析執行計劃所需的時間排除在外

           
          轉:http://alex.bloghome.cn/posts/144915.html  
          注:以上傳載的文章中的SQL經過我測試,其結果和文章中的執行結果的時間是吻合的,有興趣的朋友可以自己測試一下。

          posted on 2007-12-28 20:11 cheng 閱讀(11472) 評論(0)  編輯  收藏 所屬分類: Oracle
          主站蜘蛛池模板: 灵丘县| 邵东县| 无为县| 鹤庆县| 太仓市| 张家口市| 达孜县| 海淀区| 潢川县| 红桥区| 安远县| 德化县| 霍邱县| 金湖县| 依安县| 连城县| 普洱| 阿克陶县| 林口县| 余干县| 绥芬河市| 莫力| 高台县| 那坡县| 沭阳县| 五台县| 富民县| 新余市| 洱源县| 内江市| 威宁| 南阳市| 科技| 姜堰市| 平舆县| 康马县| 西乌| 麻阳| 宜黄县| 无为县| 东乌珠穆沁旗|