打开大型Access .MDB文件时如何防止OutOfMemory异常?

时间:2015-11-20 14:54:17

标签: delphi ms-access out-of-memory delphi-xe5

我正在尝试读取由另一个应用程序生成并存储在Microsoft Office Access .MDB文件中的数据。根据模型的大小(在另一个应用程序中),某些特定表中的记录数可以从几千到多一千万不等。在一个查询中打开整个表可能会导致大文件中出现Out of Memory异常。所以我在一些标准上拆分表,并在不同的查询中读取每个部分。但问题在于中等大小的文件,在一个查询中可以更快地读取,没有例外。

那么,我是正确的吗?我可以用另一种方式解决OutOfMemory问题吗?可以根据记录数选择一个提到的策略(1个查询或N个查询)吗?

顺便说一下,我正在使用DelphiXE5和Delphi的标准ADO组件。我需要表格的全部数据,不需要加入其他表格。我正在通过代码创建ADO组件,它们没有连接到任何可视控件。

修改

好吧,我的问题似乎不够明确。以下是一些更多细节,实际上是对评论中提出的问题或建议的回答:

这个.mdb文件没有真正的数据库;它只是结构化数据,所以没有写新数据,没有交易,没有用户交互,没有服务器,没有。第三方应用程序使用Access文件导出其计算结果。这些文件的总大小通常约为几百MB,但它们可以增长到2 GB。现在我需要在开始自己的计算之前将这些数据加载到Delphi数据结构中,因为在这些计算期间没有地方等待I / O.

我无法为x64编译这个项目,它非常依赖于一些与主可执行文件共享相同内存管理器的旧DLL,他们的作者永远不会发布x64版本。该公司尚未决定更换它们,并且在不久的将来不会改变。

而且,你知道,支持人员只是想告诉我们“解决这个问题”,而不是要求两千名客户“购买更多内存”。所以我必须对内存使用非常吝啬。

现在我的问题是:TADODataSet是否为获取此类数据提供了更好的内存管理?是否有任何属性阻止DataSet一次获取所有数据?

当我调用ADOTable1.open时,它开始分配内存并等待获取整个表,正如预期的那样。但是在for循环中读取所有这些记录将需要一段时间而且不需要拥有所有这些数据,另一方面,在读取之后不需要在内存中保留记录,因为没有在行中搜索。这就是我用一些查询拆分表的原因。现在我想知道TADODataSet是否可以处理这个或我正在做的是唯一的解决方案。

1 个答案:

答案 0 :(得分:0)

我在内存使用和已用时间方面做了一些尝试和错误,并提高了读取数据的性能。我的测试用例是一个包含5,000,000多条记录的表。每条记录有3个字符串字段和8个双打。没有索引,没有主键。我使用GetProcessMemoryInfo API来获取内存。

初始状态

Table.Open: 33.0 s | 1,254,584 kB  
Scrolling : +INF s | I don't know. But allocated memory doesn't increase in Task Manager. 
Sum       : -      | -

DataSet.DisableControls;

Table.Open: 33.0 s | 1,254,584 kB  
Scrolling : 13.7 s | 0 kB
Sum       : 46.7 s | 1,254,584 kB  

DataSet.CursorLocation:= clUseServer;

Table.Open: 0.0 s  | -136 kB  
Scrolling : 19.4 s | 56 kB
Sum       : 19.4 s | -80 kB  

DataSet.LockType:= ltReadOnly;

Table.Open: 0.0 s  | -144 kB  
Scrolling : 18.4 s | 0 kB
Sum       : 18.5 s | -144 kB  

DataSet.CacheSize:= 100;

Table.Open: 0.0 s  | 432 kB  
Scrolling : 11.4 s | 0 kB
Sum       : 11.5 s | 432 kB  

我还检查了 Connection.CursorLocarion Connection.IsolationLevel Connection.Mode DataSet.CursorType DataSet.BlockReadSize ,但他们没有做出明显的改变。

我还尝试使用TADOTableTADOQueryTADODataSet,与Jerry在评论中所说的here不同,ADOTable和ADOQuery的表现都优于ADODataSet。

应为每种情况决定分配给CacheSize的值,而不是任何更高的值会带来更好的结果。