全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5384
推到 Plurk!
推到 Facebook!

[請教]多筆資料快速寫入資料庫

 
peipei36
一般會員


發表:8
回覆:51
積分:16
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-03-13 23:03:19 IP:61.59.xxx.xxx 未訂閱
請教各位先進們... 若我有一百筆甚至更多的資料要寫入資料庫~ 例如,我有一個CheckListBox讓user可以核選資料, 我要將user核選的資料(可能對應到資料庫table的客戶編號)寫回資料庫, 可以不要「一筆一筆」寫入資料庫嗎?因為這樣好像速度會很慢... 不曉得應以什麼方式處理這樣的問題... 感謝大家幫忙!! 發表人 - peipei36 於 2002/03/13 23:04:20
領航天使
站長


發表:12216
回覆:4186
積分:4084
註冊:2001-07-25

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-03-13 23:27:13 IP:61.219.xxx.xxx 未訂閱
引言: 請教各位先進們... 若我有一百筆甚至更多的資料要寫入資料庫~ 例如,我有一個CheckListBox讓user可以核選資料, 我要將user核選的資料(可能對應到資料庫table的客戶編號)寫回資料庫, 可以不要「一筆一筆」寫入資料庫嗎?因為這樣好像速度會很慢... 不曉得應以什麼方式處理這樣的問題... 感謝大家幫忙!! 發表人 - peipei36 於 2002/03/13 23:04:20
您可以將TQuery的Cache Update打開, 例用Start transaction .... update sql applyupdate end transaction 如此雖然程式內容為一筆一筆處理,但對資料庫來講是一整筆交易, 如此效能會高! 不過筆數太多時,不宜全部塞入一個交易中, 因為資料庫中的覆原區塊(Rollback)有限的,會弄暴的,建議一個交易中不要超過1000筆SQL指令 若還有問題歡迎post程式大家來嘗試如何寫出最有效率的轉入程式 ~~~Delphi K.Top討論區站長~~~
------
~~~Delphi K.Top討論區站長~~~
peipei36
一般會員


發表:8
回覆:51
積分:16
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-03-14 04:31:02 IP:211.74.xxx.xxx 未訂閱
感謝站大幫忙...努力試試! 另外,交易是否意謂著必須全部成功or全部失敗?! 假若原來的問題,記錄的是大量筆數的資料,但可以允許些許資料遺漏, 例如,可能記錄的只是坐標or顏色的變化... (也就是1000筆的資料允許幾筆寫回資料庫失敗..) 同樣交由交易處理嗎?!或者有其他的方式處理?! ps.不好意思,觀念還不大清楚,並無具體程式碼... 文字表達不清,請海涵^^~
scottliou
版主


發表:16
回覆:56
積分:47
註冊:2002-03-14

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-03-14 10:16:02 IP:61.70.xxx.xxx 未訂閱
使用transaction對於無DBA的資料庫使用者而言常常會因為本身資料庫 RollBack Block開放空間的問題而導致失敗,所以如果可允許些許資料 遺漏時可使用下列方法    table.cachedUpdates=>true;    with table do bgein   try   i:=1;   try     AppendRecord([..,..,..,....]);   except   end;     if i =1000 then //每1000筆commit一次     begin       CommitUpdates;       i:=0;     end;    inc(i);   finally     CommitUpdates;   end; end; 這樣速度應該可以吧!! 請自已試試看!!.....    ~~~~~~~~~~~~~~~~ 有夢想最美......    [優良回覆]
------
~~~~~~~~~~~~~~~~
有夢想最美......
peipei36
一般會員


發表:8
回覆:51
積分:16
註冊:2002-03-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2002-03-14 10:29:33 IP:211.74.xxx.xxx 未訂閱
謝謝scottliou幫忙... 我試試...
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2002-03-14 10:48:20 IP:202.123.xxx.xxx 未訂閱
引言: 感謝站大幫忙...努力試試! 另外,交易是否意謂著必須全部成功or全部失敗?! 假若原來的問題,記錄的是大量筆數的資料,但可以允許些許資料遺漏, 例如,可能記錄的只是坐標or顏色的變化... (也就是1000筆的資料允許幾筆寫回資料庫失敗..) 同樣交由交易處理嗎?!或者有其他的方式處理?! ps.不好意思,觀念還不大清楚,並無具體程式碼... 文字表達不清,請海涵^^~
寫個迴路, 一筆一筆的寫回Database, 有何困難? 成功的就從你所說的 CheckListBox 中除去, Error 的保留, 就這樣。 發表人 - Diviner 於 2002/03/14 10:49:02
------
--
小卜子
peipei36
一般會員


發表:8
回覆:51
積分:16
註冊:2002-03-13

發送簡訊給我
#7 引用回覆 回覆 發表時間:2002-03-19 01:51:32 IP:61.59.xxx.xxx 未訂閱
不好意思..最近有點事耽擱了...到現在才試... 我試了站大& scottliou 您們的方法... 但是,不管在本機的Access或網路(區網)的SQL Server.. 速度竟然都是 直接Post > Transaction > CacheUpdates... (本機access 2000;OS=98  區網sql server 2000;OS=2000pro)
   // 測試結果(資料300筆):
   //     1. 本機 access => Transaction = 1.26 s
   //                       CacheUpdate = 3.74 s
   //                              Post = 0.55 s
   //     2. 區網 SQL Server 200x =>
   //                       Transaction = 0.88 s
   //                       CacheUpdate = 3.02 s
   //                              Post = 0.55 s
不知是不是我的程式碼有問題?!還是另有什麼該注意的?! 能否請大家再幫我看看!!感謝您們哦~^^ 程式碼不大,但感覺很佔篇幅,我另放在[url="http://210.240.6.173/~robert/download/testCacheUpd.zip"]這裡(zip,4.48KB)[/url]...謝謝大家的幫忙!! ps. 程式碼中,CacheUpdates依照scottliou上次提的方式;Transaction我還不 熟...不知這樣寫對不對(湊得很硬^^~)!! 另外,感謝Diviner您的幫忙...我本來是直接用Post...但覺得速度很慢.. 因此想看是不是有比較有效率的方式.... ★另外,如果用 CheckListBox1.Items.SaveToFile('xxx') 的方式, 再透過database 將文字檔匯入不知會不會快些?!大家能提供點意見嗎?!thx~ (只是想到...我還不清楚如何轉檔..) ↓↓感謝站大~我完全不會介意的(原僅是怕佔版面^^~).. ↓↓ 另外,CacheUpdate與Transaction我真的是搞不大清楚, ↓↓ 謝謝您的說明,我這幾天要將Help好好KK了~thx~ 發表人 - peipei36 於 2002/03/19 21:56:26
領航天使
站長


發表:12216
回覆:4186
積分:4084
註冊:2001-07-25

發送簡訊給我
#8 引用回覆 回覆 發表時間:2002-03-19 20:53:41 IP:192.168.xxx.xxx 未訂閱
引言: // 測試結果(資料300筆): // 1. 本機 access => Transaction = 1.26 s // CacheUpdate = 3.74 s // Post = 0.55 s // 2. 區網 SQL Server 200x => // Transaction = 0.88 s // CacheUpdate = 3.02 s // Post = 0.55 s 不知是不是我的程式碼有問題?!還是另有什麼該注意的?!
很有趣的話題! 1.Access非Database Server的資料庫,所以對Transaction處理較差,先不論 2.SQL Server 2000 的post居然比Transaction快,我用您的程式測也是如此 但我發現您在CacheUpdate的按鈕程式中將table1.cacheupdate=true, 之後再去測post,結果是因為 post未將結果寫入,只是放在Cache而已,速度當然快,不信的話您先跑post再跑Transaction就知道了 3.SQL Server 2000 的CacheUpdate居然比Post慢,我測也是如此, 您在CacheUpdate的程式中用CommitUpdates,而不是用Cacheupdate. 您可能把Transaction與CacheUpdate混為一談了: 1.Transaction為Database Server內部提供的整筆交易存入資料庫用, 用來確保資料的一致性,例如在:Master/Detail的出貨記錄上, 出貨表頭(Master)的Table必須與出貨內容(Detail)的Table同進退, 若其中有一個Table有Insert上的問題時,必需兩個Table一起Rollback, 都沒問題才一起Commit,不可有頭無尾或有尾無頭! 2.Cacheupdate為Delphi的BDE內部做的Buffer(這個Buffer就是Paradox), 大部份用來在User即時輸入資料的各欄位時增進效能用,通常在存檔的功能 上將之前所有的修改一起ApplyUpdate,因ApplyUpdate為BDE自己處理SQL指令, 所以會有很多繞道的SQL指令做法! 不知這樣說明會不會很難懂? 我將您的原始程式列出,請網友們"大家來找碴",看看還有那些地方是錯誤的寫法! (請peipei36網友不要介意,站長是想大家一起來成長)

unit Unit2;    interface    uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Db, DBTables, StdCtrls, CheckLst;    type
  TForm1 = class(TForm)
    Button1: TButton;
    Table1: TTable;
    CheckListBox1: TCheckListBox;
    Button3: TButton;
    Button2: TButton;
    Query1: TQuery;
    Database1: TDatabase;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;    var
  Form1: TForm1;    implementation
{$R *.DFM}    procedure TForm1.Button1Click(Sender: TObject);
  var i,nCnt,ntmpPos:integer;
      ctmpStr:string;
      t1:TDateTime;
begin
  table1.Close;
  table1.EmptyTable;     // delete all records
  table1.Open;
  table1.CachedUpdates := true;
  t1 := now;      with table1 do
    begin
      for i:=1 to CheckListBox1.Items.Count do
        begin
          try
            nCnt:=1;
            try
              if CheckListBox1.Checked[i] then
                begin
                  ctmpStr := CheckListBox1.Items[i];
                  ntmpPos := AnsiPos(' ',ctmpStr);
                  AppendRecord([Copy(ctmpStr,1,ntmpPos-1),Copy(ctmpStr,ntmpPos 1,Length(ctmpStr))]);
                end;
            except
            end;
            if nCnt =1000 then //¨C1000µ§commit¤@¦¸
              begin
                CommitUpdates;
                nCnt:=0;
              end;
            Inc(nCnt);
          finally
            CommitUpdates;
          end;
        end;
    end;
  Label2.Caption := floatToStr((now-t1)*86400);
end;    procedure TForm1.Button3Click(Sender: TObject);
  var i,ntmpPos:integer;
      ctmpStr:string;
      t1:TDateTime;
begin
  table1.Close;
  table1.EmptyTable;
  table1.open;
  t1 := now;
  for i:=0 to CheckListBox1.Items.Count-1 do
    begin
      if CheckListBox1.Checked[i] then
        begin
          ctmpStr := CheckListBox1.Items[i];
          ntmpPos := AnsiPos(' ',ctmpStr);
          table1.Append;
          table1.Fields[0].AsString := Copy(ctmpStr,1,ntmpPos-1);
          table1.Fields[1].AsString := Copy(ctmpStr,ntmpPos 1,Length(ctmpStr));
          table1.Post;
        end;
    end;
  Label3.Caption := floatToStr((now-t1)*86400);
  table1.close;
end;    procedure TForm1.FormActivate(Sender: TObject);
  var i:integer;
begin
  for i:=0 to checklistbox1.Items.Count-1 do
    checkListBox1.Checked[i] := true;
end;    procedure TForm1.Button2Click(Sender: TObject);
  var i,nCnt,ntmpPos:integer;
      ctmpStr,ctmpSql:string;
      t1:TDateTime;
begin
  table1.Close;
  table1.EmptyTable;     // delete all records
  table1.Open;
  Database1.Open;
  Query1.CachedUpdates := true;
  t1 := now;      try
    if Database1.InTransaction then
      Database1.Rollback;
    Database1.StartTransaction;
    nCnt:=1;
    for i:=0 to CheckListBox1.Items.Count-1 do
      begin
        if CheckListBox1.Checked[i] then
          begin
            ctmpStr := CheckListBox1.Items[i];
            ntmpPos := AnsiPos(' ',ctmpStr);
            ctmpSql := 'INSERT INTO ZZZ1 VALUES('''     // for SQL server -> into dbo.ZZZ1
                       Copy(ctmpStr,1,ntmpPos-1)   ''','''
                       Copy(ctmpStr,ntmpPos 1,Length(ctmpStr))   ''')';
            Database1.Execute(ctmpSql);
          end;
        if nCnt =1000 then //¨C1000µ§commit¤@¦¸
          begin
            try
              Database1.Commit;
              nCnt:=0;
            except
              Database1.Rollback;
            end;
          end;
        Inc(nCnt);
      end;
  finally
    try
      Database1.Commit;
    except
      Database1.Rollback;
    end;
  end;      Label1.caption := floatToStr((now-t1)*86400);
end;    end.
[/code]    ~~~Delphi K.Top討論區站長~~~
        
------
~~~Delphi K.Top討論區站長~~~
skylin
一般會員


發表:0
回覆:2
積分:0
註冊:2002-04-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2002-04-15 11:31:38 IP:61.219.xxx.xxx 未訂閱
TQuery1.LockType=ltBatchOptimistic; 批次存檔(多筆一起) 非常好用,繼承DataSet的屬性,you can look about 'DataSet'function
terrychen
尊榮會員


發表:90
回覆:794
積分:501
註冊:2003-05-01

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-07-22 11:53:35 IP:61.221.xxx.xxx 未訂閱
skylin兄 可否說清楚一點TQuery1.LockType=ltBatchOptimistic; 批次存檔(多筆一起) 如何使用
系統時間:2024-05-06 6:12:11
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!