FDQuery导致内存不足异常

问题描述 投票:5回答:3

我有一个拥有300万条记录的Firebird数据库。我的FetchOptions是禁用了RowsetSize := 1000FetchAll。我在本地主机上工作。

我没有问题可以逐页浏览,但是当我单击DBNavigator中的“ 转到最后一条记录”按钮时,会引发“ 内存不足”异常。

如果将UniDirectional属性设置为True,则没有问题。但是,移至最后一条记录会使应用程序冻结30-40秒。

问题和解决方案是什么?

delphi out-of-memory firebird firedac
3个回答
3
投票

问题是您的方法确实消耗了所有可用的内存,并且由于出现“内存不足”错误而被正确通知。所有记录均从服务器获取并保存在内存中。操作系统无法为您的应用分配更多资源。

该怎么办?只是避免加载数百万条记录。无论如何,您的用户将无法遍历/浏览/检查该庞大数据集中的每条记录。

要考虑的选项:

  • 检索用户记录所需的,限制/过滤数据集
  • 仅从服务器源数据中选择仅需要的字段
  • 使用单向避免在单遍方案中进行本地缓存

0
投票

当FireDAC查询设置为单向时,它将在访问记录后从内存中删除记录。这样可以确保不会发生内存溢出。

移至最后一条记录的时间延迟是由于访问了每个中间记录,这显然需要一些时间。


0
投票

解决方案是使用TFDTable数据集而不是默认的一个TFDQuery。 TFDTable数据集支持实时数据窗口模式。在这种模式下,数据集是双向的,因此可以与可视组件(例如TDBGrid)一起使用。与TFDQuery相比,差异是旧记录被丢弃。每次即时数据集仅在内存中保留2 * FetchOptions.RowsetSize记录(默认值2 * 50 = 100条记录),即进入表数据的窗口。当应用程序浏览表数据时,FireDAC会自动滚动或将“实时数据”窗口定位到所需位置。这提供了以下好处:

  • 与单向数据集类似,最大程度地减少了内存使用并允许您处理大数据量。
  • 与单向数据集相比,启用双向导航。
  • 始终提供最新数据,减少了刷新数据集的需要。
  • 不会延迟获取所有结果集数据,这是执行排序,记录位置,跳转到最后一条记录所需的,等等。Filter属性,范围过滤,IndexFieldNames和IndexName属性,Locate和Lookup方法,键定位,设置RecNo,设置书签等,是通过其他SELECT命令或通过为主SELECT命令设置其他短语来执行的。更改Filter,IndexFieldNames或IndexName之后,数据集中的当前位置也可以更改。要保留当前位置,请在更改之前保存一个书签,并在更改之后恢复它。

在LDW模式下,将Filter属性值原样替换为WHERE短语。根据设计,LDW模式始终将ORDER BY短语应用于SELECT命令。正确的LDW工作的关键要求是:

  • 表必须具有唯一键或主键。有关更多详细信息,请参见唯一标识字段。
  • 服务器端排序规则和客户端排序规则必须相同。否则,TFDTable可能会产生重复的行并引发“唯一键冲突”错误。

尽管FireDAC在LDW模式下最大程度地减少了生成和执行的SQL命令的数量,但它仍然比TFDQuery产生更大的数据库负载。因此,应用程序开发人员应谨慎选择何时使用TFDTable和LDW模式。

设置LDW模式

当满足以下所有条件时,将使用LDW模式:

  • 默认情况下,CachedUpdates为False。
  • FetchOptions.Unidirectional默认为False。
  • FetchOptions.CursorKind设置为ckAutomatic或ckDynamic(ckAutomatic是默认值)。
  • 表具有主键或唯一键。

否则,使用标准模式。

更多信息可以在Embarcadero文档中找到:http://docwiki.embarcadero.com/RADStudio/Berlin/en/Browsing_Tables_(FireDAC)#Live_Data_Window_Mode

© www.soinside.com 2019 - 2024. All rights reserved.