我刚刚发现我的程序员实际上将整个SQLite数据库加载到列表中(select * from tablename)(用于搜索和过滤操作),而不是单独执行sql语句。当记录少于20,000 - 50,000时,这种方法很有效。但是一旦内存不足或超过一定数量的记录,Delph 7应用程序就会冻结。
改变这种方法为时已晚,因为我们深入到项目中并且已经部署了。我没有时间重做解决方案所以我需要找到一个“快速修复”来减少内存使用量并增加数据库中的记录数。我想知道是否可以将列表拆分成文件然后逐个处理?
已更新,以便将问题答案添加到问题
感谢您的回复。这里有一些关于如何将sqlite记录加载到记录中的代码片段,然后在整个应用程序中使用该记录。最多可以有200,000条记录,这会消耗大量内存。有没有办法缓冲文件中的记录?
type
TMyDatabase = class(TThread)
private
Owner: TComponent;
FSqldb: TSQLiteDatabase;
FSltb: TSQLIteTable;
.....
type
PMyMessageRec = ^TMyMessageRec;
TMyMessageRec = record
Id: integer;
RcptId: integer;
PhoneNumber: ShortString;
Text: string;
......
end;
procedure TMyDatabase.Execute;
........
begin
...........
FSltb := FSqldb.GetTable('SELECT * FROM Messages ORDER BY ID LIMIT ' + IntToStr(MaximumMessages));
try
Synchronize(SyncLoadAllMessages);
Synchronize(SyncLoadMessages);
finally
FSltb.Free;
end;
procedure TMyDatabase.SyncLoadAllMessages;
var MessRec: PMyMessageRec;
.......
begin
....
while not FSltb.EOF do
Begin
if TerminateAll then exit;
New(MessRec);
MessRec.Id := FSltb.FieldAsInteger(FSltb.FieldIndex['ID']);
MessRec.RcptId := FSltb.FieldAsInteger(FSltb.FieldIndex['RecipientId']);
MessRec.PhoneNumber := FSltb.FieldAsString(FSltb.FieldIndex['RecipientPhone']);
MessRec.Text := FSltb.FieldAsString(FSltb.FieldIndex['Text']);
MessRec.Charset := FSltb.FieldAsString(FSltb.FieldIndex['Charset']);
答案 0 :(得分:3)
“内存数据库”本身并不是一个糟糕的设计(市场上有很多产品)。对象关系映射器和对象缓存将此策略用于数据库的较小或较大部分以提高性能。
尝试将问题分为两部分,以获得短期和长期解决方案:
短期
长期
答案 1 :(得分:2)
这可能有所帮助,但它非常适用于切断头部的贴膏药!
/LARGEADDRESSAWARE
。然后交叉你的手指,希望4GB的地址空间,而不是2GB,就足够了!
答案 2 :(得分:2)
我会根据某些条件(如日期范围)向初始查询添加“WHERE”子句,以便您或您的应用可以控制初始结果集的大小。我使用DevExpress QuantumGrids,它将整个查询结果加载到内存中,以获得极大的灵活性和速度。 (DevExpress的东西很棒......)我在应用程序中放置了几个日期控件,我的用户可以与之交互,并为结果集设置StartDate和EndDate范围。这可以使性能受到一定的控制。
答案 3 :(得分:1)
即使你建议的解决方案是“改变这种方法”。你将以某种方式结束重构,最好使用SQL引擎尽可能多地进行过滤。
您没有描述使用的实际算法,但我假设您目前正在执行此操作:
在启动时将整个数据集加载到某种列表中。
让用户指定过滤条件。
调用一个传递过滤条件并在完整列表上运行的函数,返回另一个经过筛选和排序的列表。
如果是这样,您应该能够在步骤3重构。在步骤1中,只需创建一个空列表(这样就不会在对该列表的引用上抛出错误)。然后,在步骤3中,使用SQL进行所有过滤,或者如果进行过多的重构,请弄清楚如何从SQLite中获取部分过滤的列表到内存中间列表中,然后将现有的排序和过滤应用于该列表。
这应该将你的重构限制为单个函数(假设我猜错了程序的整体结构)。
答案 4 :(得分:0)
正如其他人指出的那样,如果没有更多细节,很难提出建议。这就是我的两分钱。
我的建议是使用分析器来确定“热点”的位置并关注这些热点。您可以从SmartBear获得免费的。
您没有提到您正在使用的列表类型。如果列表是设计中的根深蒂固,那么您可以编写一个包装器,其功能类似于来自调用者视角的列表,但在内部它依赖于参数化的select语句。