幾種提昇 MDAC 應用程式效能的方法

資料來源:http://www.reocities.com/huanlin_tsai/faq/n012.txt

1.在記錄的迴圈當中使用預先連結的欄位物件

  參考下面的範例:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    fldID, fldName, fldAge: TField;
  begin
    fldID := ADODataSet1.FieldByName('ID');
    fldName := ADODataSet1.FieldByName('Name');
    fldAge := ADODataSet1.FieldByName('Age');
    ADODataSet1.First;
    while not ADODataSet1.Eof do
    begin
      writeln(fldID.AsString);
      writeln(fldName.AsString);
      writeln(fldAge.AsString);
      ADODataSet1.Next;
    end;
    ADODataSet1.Close;
  end;

2.除非必要,否則不要使用 cursor-based 的方式更新資料

  雖然使用 SQL 命令來更新資料在某些情況下並不適合,你還是應該盡量
  使用這種方式,經由 recordset 物件 (TADODataSet 及其後代) 來更新
  資料雖然方便,但所必須付出的代價也較大,儘管 SQL 命令比較難以使
  用,但是絕對值得。

3.使用帶輸出參數的預儲程序取代只傳回一筆記錄的 Select 敘述

  當你知道 query 傳回的結果集只有一筆記錄時,你可以使用帶輸出參數
  的預儲程序取代開啟一個 recordset。
  當你開啟一個 recordset 時,傳回的結果集包含了資料以及 metadata
  ,通常 metadata 的資料量蠻大的,所以你可能會想用一個帶輸出參數
  的預儲程序。

  Sub SingletonSp()

    Dim cmd As New Command
   
    cmd.ActiveConnection =
      "Provider=SQLOLEDB;DataSource=sureshk1;Database=pubs;" & _
      "User Id=sa;Password=;"
   
    cmd.CommandText = "GetAuthorName"
    cmd.CommandType = adCmdStoredProc
   
    cmd.Parameters.Append cmd.CreateParameter(
      "Id", adChar, adParamInput, 11)
    cmd.Parameters.Append cmd.CreateParameter(
      "FName", adChar, adParamOutput, 30)
    cmd.Parameters.Append cmd.CreateParameter(
      "LName", adChar, adParamOutput, 30)
   
    cmd(0) = "172-32-1176"
    cmd.Execute
    Debug.Print cmd(1), cmd(2)

  End Sub

  Sub SingletonSelect()

    Dim rs As New Recordset
   
    rs.ActiveConnection =
      "Provider=SQLOLEDB;Data Source=sureshk1;Database=pubs;" & _
      "User Id=sa;Password=;"
    rs.Source = "select au_fname, au_lname from authors where" & _
      " au_id = '172-32-1176'"
    rs.Open
   
    Debug.Print rs!au_fname, rs!au_lname

End Sub


4.如果你必須使用 cursor,對傳回一筆記錄的結果集使用 Collect 方法

  Recordset::get_Collect 及 Recordset::set_Collect 方法可以讓你
  不用透過欄位物件而快速的存取欄位值,這種方法最適合用在只傳回一
  筆記錄的結果集。

  Sub Collect()

    Dim rs As New Recordset
   
    rs.ActiveConnection =
      "Provider=SQLOLEDB;Data Source=sureshk1;Database=pubs;" & _
      "User Id=sa;Password=;"
    rs.Source = "select au_id, au_fname, au_lname from authors" & _
      " where au_lname = 'Green'"
    rs.Open
   
    Debug.Print rs.Collect(0), rs.Collect(1), rs.Collect(2)
    ' VBA shortcut
    Debug.Print rs!au_id, rs!au_fname, rs!au_lname

  End Sub

5.只取得你所要的資料

  Select * 的簡單使用容易讓人養成壞習慣,考慮只將你要的欄位 select
  進來,同時也要考慮用 where 來限制傳回的記錄數量。

6.小心選擇你的 cursor location

  如果你不需要捲動或者更新記錄,就使用 ADO 的內定值:
    CursorLocation = adUseServer
    CursorType = adOpenForwardOnly
    LockType = adLockReadOnly
  此內定值讓你最快速的存取只能向前捲動的結果集。
  把握一個原則: 根據需求做適當的設定,不要給多餘而不必要的功能。

  如果你需要前後移動記錄,就不要使用 adUseServer,ADO 將
  adUserServer 做為內定值是由於向後相容的考量。在大部分需要捲動
  的情況下,使用 client cursor 會比較適當,只有在比較特殊的情況
  下,像是資料量非常龐大的時候,就應該使用 server cursor。
  另外,如果你使用 client cursor,但是並不需要更新資料時,請將
  LockType 設定為 adLockReadOnly,如果你需要更新資料,client
  cursor 引擎必須取得額外的 metadata,而這會付出昂貴的代價。

  後端為 SQL Server 時應避免使用 Static 及 Keyset cursor,SQL
  Server 並不直接支援 Static 及 Keyset cursor,它必須複製資料到
  暫存資料表,因此降低了效能。

  註1:當 CursorLocation 為 adUseClient 時,ADO 會自動將 CursorType
      設定為 adOpenStatic,即使你設定成其他值,在開啟資料集時 ADO
      就會自動改為 adOpenStatic。
  註2:Microsoft Jet database engine 不支援 dynamic cursor,所以OLE
      DB Provider for Microsoft Jet 不支援 adLockDynamic cursor。
  註3:當 CursorType 為 adOpenForwardOnly 或 adOpenDynamic 時,
      Recordset 的 RecordCount 屬性總是等於-1。參考 http://
      support.microsoft.com/support/kb/articles/q194/9/73.asp

7.調整 Recordset 的 CacheSize 屬性 (TADODataSet.CacheSize)

  ADO 使用 Recordset 的 CacheSize 來決定要快取的記錄數量,當你在
  快取的記錄範圍內移動 cursor 時,ADO 會直接由快取中傳回資料,當
  你移出快取範圍時,ADO 會釋放快取,並且取得下一批快取記錄。
  那麼 CacheSize 要設定多少會有最佳效能呢? 答案是視情況而定。你
  應當嘗試用多個不同的 CacheSize 來找出讓你的應用程式表現最佳的
  設定值(建議值: 10)。

8.儘快釋放掉沒有使用的 ADO 物件

9.自行描述命令參數

  即 Delphi ADOExpress 的 TADOCommand.Parameters 屬性, 例如:

    with ADOCommand1.Parameters do
    begin
      Items[0].Name := 'ReturnValue';
      Items[0].DataType := ftInteger;
      Items[0].Direction := pdReturnValue;
    end;

10.使用原生 OLE DB Providers 

11.對唯讀資料集以及需要較長時間的處理可以切斷 client cursor 與
   connection 的連結以增進效能

   切斷 Recordset 連結是 client cursor 引擎的一項功能,當你在處
   理較費時的工作時可以利用這項功能,處理完之後可以再恢復連結。
   Delphi 的 TADODataSet 及其後代應該只要將 Connection 屬性設為
   nil 即可 (未驗證)。

12.不需要傳回結果集時使用 Connection 的 adExecuteNoRecords 選項

  當你使用這個選項時,ADO 不會建立 Recordset 物件,也不會設定任
  何 cursor 屬性。

  Delphi:

    TADOConnection.Execute(CommandText, eoExecuteNoRecords);

13.對於只使用一次的命令使用 Connection::Execute

  當你使用 Connection::Execute 方法執行只需一次的命令時,ADO 對
  此做了些效能最佳化。常見的使用時機是用在 IIS, ASP, 及 MTS 環境
  下,典型的步驟是: 開啟 connection,執行傳回或不傳回資料集的命
  令,處理結果集,然後關閉 connection。在這種情況下應該使用
  Connection::Execute 以取代 Recordset::Open 或 Command::Execute
  。當你使用 Connection::Execute 方法時,ADO 不會保留任何命令的
  狀態資訊,因此會獲得較好的效能。如果你需要較多功能的 cursor 或
  者你需要再執行 Execute 方法時帶參數的話,你仍然需要使用
  Recordset::Open 或 Command::Execute 方法。



參考文件

  http://www.microsoft.com/data/impperf.htm
  http://vbdata.iwarp.com/speed.htm

留言

這個網誌中的熱門文章

對於 Delphi 10.1 Berlin 推出的看法

IntraWeb 學習日記:【Login】