FireDAC查询RecordCountMode

时间:2018-08-17 12:32:27

标签: firedac

我正在尝试配置FireDAC TFDQuery组件,以便它按不超过500的批次按需获取记录,但是我需要它报告回查询的总记录数,而不仅仅是获取的记录数。 FetchOptions的配置如下:

FetchOptions.AssignedValues = [evMode, evRowsetSize, evRecordCountMode, evCursorKind, evAutoFetchAll]
FetchOptions.CursorKind = ckForwardOnly
FetchOptions.AutoFetchAll = afTruncate
FetchOptions.RecordCountMode = cmTotal
FetchOptions.RowSetSize = 500

这会立即返回表中的所有记录,而不仅仅是500。我尝试将RecsMax设置为500,这可以限制提取的记录,但是查询的RecordCount仅显示500,而不是总数

FireDAC帮助文件指出,将RecordCountMode设置为`cmTotal'会导致FireDAC发出

  

SELECT COUNT(*)FROM(原始SQL命令文本)。

要么有错误,要么我做错了!

我看不到我可以更改的其他属性。我对RowSetSizeRecsMax之间的关系感到困惑,并且找不到澄清的帮助文件。

我尝试过使用AutoFetchAll的属性(再次对该属性的用途感到困惑),但请注意,该属性已设置为afAll,我将其设置为afTruncate如果那会有所作为,但没有。

2 个答案:

答案 0 :(得分:0)

我已经用FetchOptions组件和fmOnDemand组件测试了Mode'FDTable FDQuery。两者的FetchOptions设置相同,即RowSetSize = 50。通过网络服务器获取的数据集中的425,000行。

FDTable的表现符合预期。它仅加载50个元组,并且几乎立即加载。当按Ctrl + End到达DBGrid显示的末尾时,它仅加载100个元组。滚动时很少加载超过100个元组。对内存的影响可以忽略不计。但是滚动速度很慢。

FDQuery加载50个元组,但是这样做大约需要35秒,并且在此过程中消耗了超过0.5GB的内存。如果按Ctrl + Home移到连接的DBGrid的末尾,它实际上会立即执行,并且在此过程中将加载整个表并消耗700MB的内存。

我还尝试了CachedUpdates。上方CachedUpdates处于关闭状态的结果。启用后,对FDQuery的性能完全没有影响(仍然很差),但是对于FDTable来说,这导致它在启动时加载了整个表,花费了半分钟以上的时间并消耗1.2GB的内存。

看来fmOnDemand模式仅在FDTable关闭的情况下仅在CachedUpdates下可用,根本不适合与FDQuery一起使用。

答案 1 :(得分:0)

我将fmOnDemand与postgreSQL和MySQL结合使用的测试结果基本相同。使用FDTable fmOnDemand仅下载RowSetSize所需的内容。 RowSetSize为50时,它最初下载50个元组,而无论您滚动到它的位置,其下载量都永远不会超过111个元组(尽管毫无疑问,这取决于所连接的DBGrid的大小。 FDTable最初从数据源下载50个元组,然后如果您导航到基础表中的任何记录,它将仅下载一个元组并丢弃所有其他数据。

FDQuery中的

fmOnDemand仅在打开时下载最初的50个元组,但是如果您通过RecNo进行导航,则会下载之间的每个元组。我本来希望它可以使用LIMIT和OFFSET命令来仅获取被请求的记录。

要为PostGre重新创建测试,您需要以下FireDAC组件:

object FDConnectionPG: TFDConnection
Params.Strings = (      
  'Password='
  'Server='
  'Port='
  'DriverID=PG')
ResourceOptions.AssignedValues = [rvAutoReconnect]
ResourceOptions.AutoReconnect = True    
end

object FDQueryPG: TFDQuery
Connection = FDConnectionPG
FetchOptions.AssignedValues = [evMode, evRowsetSize]    
end

object FDTable1: TFDTable
CachedUpdates = True
Connection = FDConnectionPG
FetchOptions.AssignedValues = [evMode, evRowsetSize, evRecordCountMode]
FetchOptions.RecordCountMode = cmFetched
end

如果您希望使用MYSQL重新创建,则基本上需要相同的FireDAC组件,但是FDConnection的设置如下:

object FDConnectionMySql: TFDConnection
Params.Strings = (
  'DriverID=MySQL'
  'ResultMode=Use')
ResourceOptions.AssignedValues = [rvAutoReconnect]
ResourceOptions.AutoReconnect = True   
end

您将需要一个编辑框,两个按钮,一个复选框,一个计时器和一个标签以及以下代码:

procedure TfrmMain.Button1Click(Sender: TObject);
begin
if not FDQueryPG.IsEmpty then
  begin
    FDQueryPG.EmptyDataSet;
    FDQueryPG.ClearDetails;
    FDQueryPG.Close;
  end;

if not FDTable1.IsEmpty then
  begin
    FDTAble1.EmptyDataSet;
    FDTable1.ClearDetails;
    FDTable1.Close;
  end;


lFetched.Caption := 'Fetched 0';
lFetched.Update;

if cbTable.checked then
  begin
    FDTable1.TableName := '[TABLENAME]';
    FDTable1.Open();
    lFetched.Caption := 'Fetched '+ FDTable1.Table.Rows.Count.ToString;
  end
else
  begin
    FDQueryPG.SQL.Text := 'Select * from [TABLENAME]';        
    FDQueryPG.open;
    lFetched.Caption := 'Fetched '+ FDQueryPG.Table.Rows.Count.ToString;
  end;
timer1.Enabled:=true;    
end;

procedure TfrmMain.Button2Click(Sender: TObject);
begin
  if cbTable.Checked then
   FDTable1.RecNo := strToInt(Edit1.Text)
  else
   FDQueryPG.RecNo := strToInt(Edit1.Text);
end;

procedure TfrmMain.cbTableClick(Sender: TObject);
begin
  timer1.Enabled := False;
end;

procedure TfrmMain.Timer1Timer(Sender: TObject);
begin
  if cbTable.checked then
    lFetched.Caption := 'Fetched '+ FDTable1.Table.Rows.Count.ToString
  else        
    lFetched.Caption:='Fetched '+FDQueryPG.Table.Rows.Count.ToString;
  lFetched.Update;
end;