2017/06/07

自製簡單版加總計算 -- 使用 ClientDataSet

最近接到同事發來的一個問題,說是【在表單的某處增加一個加總欄位後,這支程式的速度就下降了】。

「 TClientDataSet 就可以做到的功能,但它的效能有這麼差嗎?」



抱著這樣的疑問,我開啟了這位仁兄的專案,他是這麼寫的:
LSum := 0;
while ClientDataSet1.Eof do
begin
  LSum := LSum + ClientDataSet1.Fields[n].AsInteger;
  ClientDataSet1.Next;
end;

while ClientDataSet2.Eof do
begin
  LSum := LSum + ClientDataSet2.Fields[n].AsInteger;
  ClientDataSet2.Next;
end;

Result := LSum;

這樣跟輪詢的方式好像差不多,為什麼不用更好的方法:

TClientDataSet 裡的 Aggregate Field 合計欄位功能

在 Field Editor 便可以輕鬆完成定義這個欄位,如果要 2 個 TClientDataSet 欄位要加總時也只需要這樣寫:

  LSum := Cds1AggregateField.Value + Cds2AggregateField.Value

動態產生的話,也不難,最終應該會以這樣的成果出現:
  LSum := ClientDataSet1.SumFieldFloat(FieldName) +
      ClientDataSet2.SumFieldFloat(FieldName);

以範例資料庫 employee.cds 裡的資料進行試算,結果如下,

修改前:1.0812692 sec

修改後:0.0010634 sec


驚人的速度提升!

至於為什麼 Aggregate 機制效能可以這麼高?
























追到 DSIntf.pas 時

function GetAggregateValue(
hAgg : hDSAggregate;
pValue : Pointer;
var bBlank : LongBool
): DBResult; stdcall;


看來這是藏在 Midas.dll 裡面,無解了。




........好吧,那這樣的程式碼要怎麼實現呢?

以下的程式碼,搭配 helper class 就可以解決這個問題啦!

function TClientDataSetHelper.SumFieldFloat(A_計算式: string): Extended;
var
  Agg: TAggregate;
begin
  Agg := Self.Aggregates.Add;
  Agg.Expression := Format('SUM(%s)', [A_計算式]);
  Agg.Active := True;
  Result := StrToFloat(Agg.Value);
  Self.Aggregates.Delete(Agg.Index);
end;

1 則留言:

  1. 您好 請問 function TClientDataSetHelper.SumFieldFloat(A_計算式: string): Extended; 整個程式架構要怎麼設計,是要新增一個unit 還是寫在form裡面 ,clientdataset 要怎麼呼叫他?? 謝謝

    回覆刪除