FireDAC 查询 RecordCountMode
FireDAC Query RecordCountMode
我正在尝试配置一个 FireDAC TFDQuery 组件,以便它按需以不超过 500 条的批次获取记录,但我需要它来报告查询的总记录数,而不仅仅是获取的记录数记录。 FetchOptions
配置如下:
FetchOptions.AssignedValues = [evMode, evRowsetSize, evRecordCountMode, evCursorKind, evAutoFetchAll]
FetchOptions.CursorKind = ckForwardOnly
FetchOptions.AutoFetchAll = afTruncate
FetchOptions.RecordCountMode = cmTotal
FetchOptions.RowSetSize = 500
这立即 returns table 中的所有记录,而不仅仅是 500。我尝试将 RecsMax
设置为 500,这可以限制获取的记录,但是 RecordCount
查询只显示500不是总数。
FireDAC 帮助文件指出将 RecordCountMode
设置为“cmTotal”会导致 FireDAC 发出
SELECT COUNT(*) FROM (original SQL command text).
不是有bug就是我做错了什么!
我看不到我可以更改哪些其他属性。我对 RowSetSize
和 RecsMax
之间的关系感到困惑,并且没有找到澄清的帮助文件。
我尝试使用 AutoFetchAll
的属性(再次对此属性的用途感到困惑),但注意到它被设置为 afAll
我将其设置为 afTruncate
看看这是否会有所作为,但事实并非如此。
我已经用 FDTable
组件和 FDQuery
组件测试了 FetchOptions
' fmOnDemand
Mode
。两者都具有相同的 FetchOptions
设置,即 RowSetSize
=50。通过网络服务器获取的数据集中有 425,000 行。
FDTable
按预期执行。它只加载 50 个元组,而且几乎是立即完成的。当按 Ctrl+End 到达 DBGrid 显示的末尾时,它仅加载 100 个元组。滚动时它很少加载超过 100 个元组。对内存的影响可以忽略不计。但是滚动很慢。
FDQuery
加载 50 个元组,但需要大约 35 秒才能完成,并在此过程中消耗超过 0.5GB 的内存。如果您按 Ctrl+Home 移动到连接的 DBGrid 的末尾,它几乎会立即执行此操作,并在此过程中加载整个 table 并进一步消耗 700MB 内存。
我也尝试过 CachedUpdates
。上面的结果关闭 CachedUpdates
。打开时,对 FDQuery
的性能没有任何影响(仍然很差),但是对于 FDTable
它导致它在启动时加载整个 table,占用了半个时间分钟并消耗 1.2GB 内存。
看起来 fmOnDemand
模式实际上只适用于 FDTable
且 CachedUpdates
关闭并且根本不适合 table 与 FDQuery
一起使用.
我使用 fmOnDemand
与 postgreSQL 和 MySQL 的测试结果基本相同。使用 FDTable fmOnDemand
只下载它需要的内容限制在 RowSetSize
。 RowSetSize
为 50 时,它最初会下载 50 个元组,无论你滚动到哪里,它都不会下载超过 111 个元组(尽管这无疑取决于连接的 DBGrid
的大小。如果你断开连接FDTable
它最初从数据源下载 50 个元组,如果您随后导航到基础 table 中的任何记录,它只下载一个元组并丢弃所有其他数据。
FDQuery
in 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;
我正在尝试配置一个 FireDAC TFDQuery 组件,以便它按需以不超过 500 条的批次获取记录,但我需要它来报告查询的总记录数,而不仅仅是获取的记录数记录。 FetchOptions
配置如下:
FetchOptions.AssignedValues = [evMode, evRowsetSize, evRecordCountMode, evCursorKind, evAutoFetchAll]
FetchOptions.CursorKind = ckForwardOnly
FetchOptions.AutoFetchAll = afTruncate
FetchOptions.RecordCountMode = cmTotal
FetchOptions.RowSetSize = 500
这立即 returns table 中的所有记录,而不仅仅是 500。我尝试将 RecsMax
设置为 500,这可以限制获取的记录,但是 RecordCount
查询只显示500不是总数。
FireDAC 帮助文件指出将 RecordCountMode
设置为“cmTotal”会导致 FireDAC 发出
SELECT COUNT(*) FROM (original SQL command text).
不是有bug就是我做错了什么!
我看不到我可以更改哪些其他属性。我对 RowSetSize
和 RecsMax
之间的关系感到困惑,并且没有找到澄清的帮助文件。
我尝试使用 AutoFetchAll
的属性(再次对此属性的用途感到困惑),但注意到它被设置为 afAll
我将其设置为 afTruncate
看看这是否会有所作为,但事实并非如此。
我已经用 FDTable
组件和 FDQuery
组件测试了 FetchOptions
' fmOnDemand
Mode
。两者都具有相同的 FetchOptions
设置,即 RowSetSize
=50。通过网络服务器获取的数据集中有 425,000 行。
FDTable
按预期执行。它只加载 50 个元组,而且几乎是立即完成的。当按 Ctrl+End 到达 DBGrid 显示的末尾时,它仅加载 100 个元组。滚动时它很少加载超过 100 个元组。对内存的影响可以忽略不计。但是滚动很慢。
FDQuery
加载 50 个元组,但需要大约 35 秒才能完成,并在此过程中消耗超过 0.5GB 的内存。如果您按 Ctrl+Home 移动到连接的 DBGrid 的末尾,它几乎会立即执行此操作,并在此过程中加载整个 table 并进一步消耗 700MB 内存。
我也尝试过 CachedUpdates
。上面的结果关闭 CachedUpdates
。打开时,对 FDQuery
的性能没有任何影响(仍然很差),但是对于 FDTable
它导致它在启动时加载整个 table,占用了半个时间分钟并消耗 1.2GB 内存。
看起来 fmOnDemand
模式实际上只适用于 FDTable
且 CachedUpdates
关闭并且根本不适合 table 与 FDQuery
一起使用.
我使用 fmOnDemand
与 postgreSQL 和 MySQL 的测试结果基本相同。使用 FDTable fmOnDemand
只下载它需要的内容限制在 RowSetSize
。 RowSetSize
为 50 时,它最初会下载 50 个元组,无论你滚动到哪里,它都不会下载超过 111 个元组(尽管这无疑取决于连接的 DBGrid
的大小。如果你断开连接FDTable
它最初从数据源下载 50 个元组,如果您随后导航到基础 table 中的任何记录,它只下载一个元组并丢弃所有其他数据。
FDQuery
in 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;