FDQuery Out of Memory错误

时间:2017-11-02 12:41:37

标签: delphi out-of-memory firebird firedac

我有一个火鸟数据库(300万条记录) 我的查询设置是: fetchAll:=禁用; rowsetsize:1000; 我在localhost上工作。

当我逐页浏览时没问题。 但是当我点击dbnavigator上的“转到最后一条记录”按钮时,它会抛出“内存不足”错误。

如果我将单向属性设置为“ true ”,则没有问题。但这一次,在进行最后一次记录时,应用程序会冻结30-40秒。

问题和解决方案是什么?

提前致谢。

3 个答案:

答案 0 :(得分:2)

问题在于您的方法确实消耗了所有可用内存,并且通过“内存不足”来正确通知您。错误。所有记录都从服务器获取并保存在内存中。操作系统无法为您的应用程序分配更多内容。

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

要考虑的选项:

  • 根据用户记录检索,限制/过滤数据集
  • 仅从服务器源数据中选择所需的字段
  • 使用单向来避免一次性场景中的本地缓存

答案 1 :(得分:1)

解决方案是使用 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/Rio/en/Browsing_Tables_(FireDAC)#Live_Data_Window_Mode

答案 2 :(得分:0)

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

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