为啥在嵌入式 HSQLDB 上运行更新查询会消耗大量内存?

Posted

技术标签:

【中文标题】为啥在嵌入式 HSQLDB 上运行更新查询会消耗大量内存?【英文标题】:Why does running an update query on an embedded HSQLDB consume a lot of memory?为什么在嵌入式 HSQLDB 上运行更新查询会消耗大量内存? 【发布时间】:2018-06-05 08:50:20 【问题描述】:

我正在使用 HSQLDB 2.4.1(嵌入缓存表)。我有一个大型数据库(大约 2100 万行。数据库大小为 5GB) 我正在尝试运行以下查询:

UPDATE TABLE_NAME SET COLUMN1=0

我尝试更改和使用这些属性,但最终此更新语句消耗了大量内存,就好像它将整个数据库复制到内存中一样。

    properties.setProperty("hsqldb.large_data" , "true");
    properties.setProperty("hsqldb.log_data" , "false");
    properties.setProperty("hsqldb.default_table_type" , "cached");
    properties.setProperty("hsqldb.result_max_memory_rows" , "50000");
    properties.setProperty("hsqldb.tx" , "mvcc");
    properties.setProperty("sql.enforce_tdc_update" , "false");
    properties.setProperty("shutdown" , "true");
    properties.setProperty("runtime.gc_interval" , "100000");

当我在 DBeaver 中执行此查询时,我注意到内存消耗显着增加并不断增加,直到达到 4GB 的 maxmem,此时应用程序因内存不足错误而崩溃。

PS:在相同的嵌入式 Derby 数据库上运行此精确查询大约需要 5 分钟,但最终返回并且 DBeaver 中的内存使用量保持在约 400mb 左右。

【问题讨论】:

【参考方案1】:

所有更新的行都加载到内存中直到提交。您可以根据主键和 LIMIT 子句分块更新。例如:

 UPDATE TABLE_NAME SET COLUMN1= 0 WHERE COLUMN1 != 0 AND (PK_ID > 1000000 AND PK_ID < 2000000) LIMIT 1000000

上面的语句显示了两种不同的技术来限制行。首先,通过使用索引列来限制;其次,在更新了许多行后使用 LIMIT 停止更新。

http://hsqldb.org/doc/2.0/guide/dataaccess-chapt.html#dac_update_statement

【讨论】:

鉴于 hsqldb.result_max_memory_rows=50000,这不应该意味着只能将 50000 行加载到内存中吗?还是在使用 UPDATE 查询时不尊重此属性? 没有。该设置仅适用于 SELECT 语句。

以上是关于为啥在嵌入式 HSQLDB 上运行更新查询会消耗大量内存?的主要内容,如果未能解决你的问题,请参考以下文章

测试通过 Mule JDBC 传输到嵌入式 HSQLDB 的插入,后续查询不返回任何结果

为啥此查询在 ODBC 表上运行但在本地表上运行时会失败?

为啥 STRAIGHT_JOIN 会消耗更多 CPU?

为啥 Gaze 会消耗高 CPU?

为啥我的 HSQLDB 表在磁盘上占用了太多空间?

在多个线程中执行 SQL 查询 (HSQLDB)