Gol*_*rol 6 delphi tclientdataset delphi-10-seattle
我最近开始注意到TClientDataSet很快用完了内存。我在生产中遇到一个问题,它无法加载大约60.000的数据集,这对我来说似乎很低。客户端数据集通过提供程序与ADODataSet连接,该加载良好。我单独运行该查询,并将结果输出到CSV,这给了我<30MB的文件。
因此,我进行了一个小测试,可以在客户端数据集中加载多达165K条记录,该记录具有一个字符串字段,其大小为4000。该字段的实际值只有3个字符,但这似乎并不结果很重要。
看起来每条记录至少占用了这4000个字符。4000 x 2字节x 165K记录= 1.3GB,因此开始接近32位内存限制。如果将其转换为备注字段,则可以轻松添加500万行。
program ClientDataSetTest;
{$APPTYPE CONSOLE}
uses SysUtils, DB, DBClient;
var
c: TClientDataSet;
i: Integer;
begin
c := TClientDataSet.Create(nil);
c.FieldDefs.Add('Id', ftInteger);
c.FieldDefs.Add('Test', ftString, 4000); // Actually claims this much space...
//c.FieldDefs.Add('Test', ftMemo); // Way more space efficient (and not notably slower)
//c.FieldDefs.Add('Test', ftMemo, 1); // But specifying size doesn't have any effect.
c.CreateDataSet;
try
i := 0;
while i < 5000000 do
begin
c.Append;
c['Id'] := i;
c['Test'] := 'xyz';
c.Post;
if (i mod 1000) = 0 then
WriteLn(i, c['Test']);
Inc(i);
end;
except
on e: Exception do
begin
c.Cancel;
WriteLn('Error adding row', i);
Writeln(e.ClassName, ': ', e.Message);
end;
end;
c.SaveToFile('c:\temp\output.xml', dfXML);
Writeln('Press ''any'' key');
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)
因此,问题本身有点广泛,但是我想为此提供解决方案,并能够通过使用字符串空间更有效地加载更大的数据集。字段很大的原因是因为它们可以包含注释。对于大多数记录而言,它们将是空的或较短的,因此这是巨大的空间浪费。
关于最后一点,我碰巧发现了这个问题,在评论中隐藏了该问题,提到了vgLib,但是我发现所有问题都是断开的链接,我什至不知道它是否可以解决这个问题。显然,MidasLib的C ++代码现在已经可用,但是由于它的1.5MB晦涩的代码,我认为在深入探讨之前可能值得在这里询问。;)
Blob 字段(备注)和常规字段存储和检索数据的方式有所不同。Blob 字段不在记录缓冲区中存储数据(请参阅 参考资料TBlobField.GetDataSize),并且在存储或检索该数据时使用一组不同的方法。
每条记录的大小通过调用返回TField.GetDataSize。对于TStringField,这是所需的字符串大小 + 1。
TCustomClientDataSet.InitBufferPointers使用它作为计算的一部分,其值FRecBufSize用作为 中的每个记录分配的内存大小TCustomClientDataSet.AllocRecordBuffer。
所以,回答你的问题: