Why TFDMemTable is slower than TClientDataSet?

5.1k views Asked by At

The Embarcadero official said "TFDMemTable is faster than TClientDataSet",But I Make an little speed test and TFDMemtable slower than TClientDataset (Delphi XE7).

{
Test 30k records
            TClientDataSet TFDMemTable
Append         1482ms      2153ms
SaveToFile     125ms       348ms        
SaveToStream   125ms       312ms
LoadFromFile   109ms       686ms
LoadFromStream 234ms       718ms 
}

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, FireDAC.Stan.Error,
  FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Data.DB,
  Datasnap.DBClient, Vcl.StdCtrls, Vcl.Samples.Spin, FireDAC.Stan.StorageBin;

type
  TForm1 = class(TForm)
    btnFDAppend: TButton;
    btnAppend: TButton;
    seCount: TSpinEdit;
    btnFDEmptyDataSet: TButton;
    btnEmptyDataSet: TButton;
    lblClientDataset: TLabel;
    lblFDMemTable: TLabel;
    btnSaveToFile: TButton;
    btnFDSaveToFile: TButton;
    btnLoadFromFile: TButton;
    btnFDLoadFromFile: TButton;
    btnSaveToStream: TButton;
    btnFDSaveToStream: TButton;
    btnFDLoadFromStream: TButton;
    btnLoadFromStream: TButton;
    lblRecordCount: TLabel;
    lblWhy: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure btnFDAppendClick(Sender: TObject);
    procedure btnAppendClick(Sender: TObject);
    procedure btnFDEmptyDataSetClick(Sender: TObject);
    procedure btnLoadFromFileClick(Sender: TObject);
    procedure btnSaveToFileClick(Sender: TObject);
    procedure btnFDSaveToFileClick(Sender: TObject);
    procedure btnFDLoadFromFileClick(Sender: TObject);
    procedure btnSaveToStreamClick(Sender: TObject);
    procedure btnFDSaveToStreamClick(Sender: TObject);
    procedure btnLoadFromStreamClick(Sender: TObject);
    procedure btnFDLoadFromStreamClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnEmptyDataSetClick(Sender: TObject);
  private
    FStartTime: DWORD;
    FFDStream, FCDSStream: TMemoryStream;
    FClientDataSet: TClientDataSet;
    FFDMemTable: TFDMemTable;

    function NewFDMemTable: TFDMemTable;
    function NewClientDataSet: TClientDataSet;

    procedure ShowDuration(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.btnFDAppendClick(Sender: TObject);
var
  I: Integer;
begin
  FStartTime := GetTickCount;
  FFDMemTable.DisableControls;
  try
    for I := 1 to seCount.Value do
    begin
      FFDMemTable.Append;
      FFDMemTable.FieldByName('ID').AsInteger := I;
      FFDMemTable.FieldByName('Status').AsString := 'Code' + IntToStr(i);
      FFDMemTable.FieldByName('Created').AsDateTime := Date();
      FFDMemTable.FieldByName('Volume').AsFloat := Random(10000);
      FFDMemTable.Post;
    end;

  finally
    FFDMemTable.EnableControls;
  end;
  ShowDuration(Sender);
end;

procedure TForm1.btnLoadFromFileClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FClientDataSet.LoadFromFile('CDS.dat');
  ShowDuration(Sender);
end;

procedure TForm1.btnSaveToFileClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FClientDataSet.SaveToFile('CDS.dat', dfBinary);
  ShowDuration(Sender);
end;

procedure TForm1.btnFDEmptyDataSetClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FFDMemTable.EmptyDataSet;
  ShowDuration(Sender);
end;

procedure TForm1.btnEmptyDataSetClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FClientDataSet.EmptyDataSet;
  ShowDuration(Sender);
end;

procedure TForm1.btnFDSaveToFileClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FFDMemTable.SaveToFile('FD.dat', sfBinary);
  ShowDuration(Sender);
end;

procedure TForm1.btnSaveToStreamClick(Sender: TObject);
begin
  FCDSStream.Clear;

  FStartTime := GetTickCount;
  FClientDataSet.SaveToStream(FCDSStream, dfBinary);
  ShowDuration(Sender);
end;

procedure TForm1.btnFDLoadFromFileClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FFDMemTable.LoadFromFile('FD.dat', sfBinary);
  ShowDuration(Sender);
end;

procedure TForm1.btnFDSaveToStreamClick(Sender: TObject);
begin
  FFDStream.Clear;
  FStartTime := GetTickCount;
  FFDMemTable.SaveToStream(FFDStream, sfBinary);

  ShowDuration(Sender);
end;

procedure TForm1.btnFDLoadFromStreamClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FFDStream.Position := 0;
  FFDMemTable.LoadFromStream(FFDStream, sfBinary);
  ShowDuration(Sender);
end;

procedure TForm1.btnLoadFromStreamClick(Sender: TObject);
begin
  FStartTime := GetTickCount;
  FCDSStream.Position := 0;
  FClientDataSet.LoadFromStream(FCDSStream);

  ShowDuration(Sender);
end;

procedure TForm1.btnAppendClick(Sender: TObject);
var
  I: Integer;
begin
  FStartTime := GetTickCount;
  FClientDataSet.DisableControls;
  try
    for I := 1 to seCount.Value do
    begin
      FClientDataSet.Append;
      FClientDataSet.FieldByName('ID').AsInteger := I;
      FClientDataSet.FieldByName('Status').AsString := 'Code' + I.ToString;
      FClientDataSet.FieldByName('Created').AsDateTime := Date();
      FClientDataSet.FieldByName('Volume').AsFloat := Random(10000);
      FClientDataSet.Post;
    end;

  finally
    FClientDataSet.EnableControls;
  end;
  ShowDuration(Sender);

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFDMemTable := NewFDMemTable;
  // FFDMemTable.FormatOptions.InlineDataSize := 10;
  FClientDataSet := NewClientDataSet;

  FCDSStream := TMemoryStream.Create;
  FFDStream := TMemoryStream.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FFDMemTable);
  FreeAndNil(FClientDataSet);
  FreeAndNil(FCDSStream);
  FreeAndNil(FFDStream);
end;

function TForm1.NewClientDataSet: TClientDataSet;
begin
  Result := TClientDataSet.Create(nil);
  with Result do
  begin
    FieldDefs.Add('ID', ftInteger, 0, False);
    FieldDefs.Add('Status', ftString, 10, False);
    FieldDefs.Add('Created', ftDate, 0, False);
    FieldDefs.Add('Volume', ftFloat, 0, False);
    CreateDataSet;
    LogChanges := False;
  end;
end;

function TForm1.NewFDMemTable: TFDMemTable;
begin
  Result := TFDMemTable.Create(nil);
  with Result do
  begin
    FieldDefs.Add('ID', ftInteger, 0, False);
    FieldDefs.Add('Status', ftString, 10, False);
    FieldDefs.Add('Created', ftDate, 0, False);
    FieldDefs.Add('Volume', ftFloat, 0, False);
    CreateDataSet;
    LogChanges := False;
  end;
end;

procedure TForm1.ShowDuration(Sender: TObject);
var
  s: string;
  idx: Integer;
begin
  s := TButton(Sender).Caption;
  idx := s.IndexOf('-');
  if idx > 0 then
    s := s.Substring(0, idx);

  TButton(Sender).Caption := Format('%s-%dms', [s, (GetTickCount - FStartTime)]);
end;

end.

This is test result screenshot:

enter image description here

This is the test application source.

0

There are 0 answers