我正在尝试配置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命令文本)。
要么有错误,要么我做错了!
我看不到我可以更改的其他属性。我对RowSetSize
和RecsMax
之间的关系感到困惑,并且找不到澄清的帮助文件。
我尝试过使用AutoFetchAll
的属性(再次对该属性的用途感到困惑),但请注意,该属性已设置为afAll
,我将其设置为afTruncate
如果那会有所作为,但没有。
答案 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;