我在2012年提出了这个问题:TSQLQuery only streams first 1MB of data correctly for large strings
我想让问题保持简单,所以不要将更多细节附加到另一个问题,希望人们再次看一下,这是一个只有核心细节的新问题。
问题摘要
TSQLConnection...MaxBobSize
有两种设置。使用-1
丢失数据(一个错误),并使用X MB
内存不足:
TSQLConnection.Params.Values['MaxBlobSize'] := '-1'
,使TSQLQuery
查看db中每个var...(max)
字段的数据长度,并分配与每个字段的数据长度匹配的缓冲区。正确设置每个缓冲区中的前1,048,576个字节,然后将剩余字节设置为NULL(0x00
)。因此,数据丢失。- 醇>
TSQLConnection.Params.Values[MaxBlobSize] := 'X MB'
使TSQLQuery
为查询中返回的每个X MB
字段预分配指定的var...(max)
RAM。X MB
必须足够大才能容纳最大的var...(max)
对象。即使在10MB
,具有3个var...(max)
字段和100行的查询也会预先分配3GB
RAM来为查询提供服务,即使实际数据要小得多。如果机器用完RAM,用户会看到“灾难性故障”。
详情
2012年,我们与Embarcadero开了一个事件来修复第1号漏洞。他们说使用X MB
而不是-1
,这会导致我们的用户体验条件#2。我们继续使用MaxBlobSize := -1
希望Embarcadero能够解决问题#1,或者我们的用户永远不会超过1MB的限制。
用户将10MB图像上传到数据库,并且很可能再次发生。当他们检索10MB图像时,前1MB显示正确,图像的其余部分丢失。完整的10MB图像正确存储在数据库中。所以用户已经遇到了错误#1。
这个问题在Delphi Seattle(XE10)中仍然存在,正如这个简单的测试案例所证明的那样。我使用WireShark验证了来自db的流量包括所有字段数据。
将SQLConnection1: TSQLConnection
添加到表单,设置以访问数据库:
将SQLConnection1.Params['MaxBlobSize']
设置为-1
。
Button1: TButton
代码添加OnClick()
:procedure TForm1.Button1Click(Sender: TObject);
var
qry: TSQLQuery;
procedure save(fn: string);
var
data: TBytes;
fs: TFileStream;
begin
fs := TFileStream.Create('c:\' + fn + '.txt', fmCreate);
try
data := qry.FieldByName(fn).AsBytes;
if data <> nil then
fs.WriteBuffer(data[0], Length(data));
finally
FreeAndNil(fs);
end;
end;
begin
SQLConnection1.Open;
qry := TSQLQuery.Create(nil);
try
qry.MaxBlobSize := -1;
qry.SQLConnection := SQLConnection1;
qry.SQL.Text := Concat(
'declare @s1 varchar(max), @s2 varchar(max) ',
'set @s1 = ''0123456789ABCDEF'' ',
'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 /* 128 bytes */ ',
'set @s1 = @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 /* 1,024 bytes */ ',
'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 /* 8,192 bytes */ ',
'set @s1 = @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 /* 65,536 bytes */ ',
'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 /* 524,288 bytes */ ',
'set @s1 = @s2 + @s2 /* 1,048,576 bytes */ ',
'set @s2 = @s1 + ''this is a test'' /* 1MB + 14 bytes */ ',
'set @s1 = @s1 + ''of the emergency broadcasting system'' /* 1MB + 36 bytes */ ',
'select @s2 as Plus14, @s1 as Plus36'
);
qry.Open;
save('Plus14');
save('Plus36');
finally
FreeAndNil(qry);
end;
SQLConnection1.Close;
end;
0x00
)。问题
由于用户在使用MaxBobSize := X MB
时看到内存不足问题,我们需要保留MaxBobSize := -1
。是否有任何建议或解决方案可以将MaxBlobSize
设置为-1
,继续使用TSQLConnection
和TSQLQuery
,然后访问所有字段数据,即使字段超出1MB?
如果无法使用上述组件,使用本机组件的另一种解决方案可能没问题。