HSQLDB:为现有数据库启用 LOB 压缩
Posted
技术标签:
【中文标题】HSQLDB:为现有数据库启用 LOB 压缩【英文标题】:HSQLDB: enable LOB compression for existing database 【发布时间】:2015-07-20 18:49:50 【问题描述】:我正在使用嵌入式 HSQLDB 2.3.2 实例将 XML 文档作为 LOB 存储一段时间,该应用程序与文档应该结束的位置有间歇性连接。
为了限制 HSQBDL 的 .lobs 文件大小增长,我通过 documentation 中提到的 jdbc 连接 URL 启用了 LOB 压缩(使用 hsqldb.lob_compressed=true),但是从我最近发现这个 URL 参数没有效果怎么样。
如果我正确理解 HSQLDB JDBC URL 解析代码,org.hsqldb.persist.Logger#setVariables() 应该在某个时候检查 HsqlDatabaseProperties.hsqldb_lob_file_compressed 以设置 propCompressLobs,就像它对 LOB 加密和 cryptLobs 所做的那样,但从不这样做.
在 URL 中使用此类参数创建的数据库中的 database.script 文件没有提及 LOB 压缩,尽管有 URL 参数,并且不压缩 LOB。
我尝试在打开数据库后立即发出“SET FILES LOB COMPRESSED TRUE”语句,这对于全新的数据库可以正常工作(lob 被压缩,database.script 提到 LOB 压缩)。
当我使用现有数据库之一尝试此操作时,由于现有 LOB 出现错误(错误消息是“正在使用的数据文件”)。我理解这背后的原因,因为压缩所有 LOB 可能需要一段时间,并且可能是一个运行时间很长的操作,如果中断可能会使数据库处于不良状态。
我认为我可以解决这个限制,因为有时会删除 XML 文档(在它们最终被发送之后),所以理论上数据库在某些时候是空的 LOB。
不幸的是,这个错误也发生在空数据库上,因为已删除 LOB 的未使用 LOB 条目,我假设它们保留在那里以回收 .lobs 文件空间。似乎负责允许 LOB 压缩模式更改的 org.hsqldb.persist.Logger#setLobFileCompressed() 方法仅检查 SYSTEM_LOBS.LOB_IDS 中的条目数,无论它们当前是否正在使用。
根据我的阅读,没有办法清除已删除的 LOB 条目(例如减少 .lobs 文件大小),因此基本上即使当前存储在 LOB 中的所有 XML 文档都已发送并从数据库中清除,这也不是启用压缩的好时机,因为已删除的 LOB 会留下阻止启用压缩的足迹。
没有留下任何文档时关闭数据库,销毁它,创建一个新的数据库,然后手动发出 lob 压缩语句,我看不到任何方法可以为具有现有数据库的应用程序启用 LOB 压缩。
我不是特别喜欢那个看起来有点骇人听闻的选项。
我还没有尝试过 2.3.3,但从我看到的 sources 来看,在那个版本中看起来并没有好转。
还有其他方法可以可靠地启用现有 HSQLDB 数据库的 LOB 压缩吗?甚至是“空”的?
【问题讨论】:
【参考方案1】:URL 上的压缩设置只有在创建数据库时才有效。可以在没有 lob 历史的空数据库上执行 SQL 设置。
在支持非压缩 lob 数据的 2.0 版之后很长时间才添加压缩功能。无法更改现有数据库的设置。
如果数据库中没有 lob,您应该能够执行 CHECKPOINT,然后使用 SQL 设置。如果这不起作用,还有下一个选项。
如果数据库没有 lob(但可以有其他数据),您可以关闭数据库,然后编辑 .script 文件并删除 SYSTEM_LOBS 的 INSERT INTO ...
条目并添加出现在新数据库。如果这样做,您也应该删除 .lobs 文件。
您可以使用 SQL 选择表格 SYSTEM_LOBS 表来检查它们的内容,但不能修改它们。
【讨论】:
如果可能的话,我想避免弄乱数据库文件。当我知道没有任何 LOB 然后插入您提到的行时,是否可以从 LOB_IDS 和 LOBS 中删除,或者这是一个在线数据库的坏主意? 此外,连接属性实际上没有任何影响,即使在新数据库上也是如此。尝试使用以下 URL 从 DatabaseManagerSwing 打开一个独立的数据库:jdbc:hsqldb:file:C:/db/test.db;shutdown=true;sql.syntax_ora=true;hsqldb.default_table_type=cached;hsqldb.nio_data_file=false;hsqldb.tx=mvcc;hsqldb.lob_compressed=true;
然后只需执行 SHUTDOWN。以这种方式创建的数据库在其 test.db.script 中没有 SET FILES LOB COMPRESSED TRUE
,并且 LOB 不会被压缩。
创建时未应用 URL 属性。这将在下一次软件更新中得到纠正。我已经添加到关于使用 SQL 的答案中。
真的不喜欢弄乱脚本,对我来说,要么是 SQL,要么是删除并创建数据库。我正在查看存储过程CALL SYSTEM_LOBS.DELETE_UNUSED_LOBS(9223372036854775807);
和CALL SYSTEM_LOBS.MERGE_EMPTY_BLOCKS();
。这些确实很好地清理了 lob 表。奇怪的是CHECKPOINT
已经应该这样做了,但显然它只是在usageChanged 为假时返回。也许 LobManager.adjustUsageCount() 应该将 LobManager.usageChanged 设置为 true 以便清除 LOB 删除? AFAICT deleteLobs() 不再被调用,它确实设置了usageChanged。【参考方案2】:
我找到了一种仅使用 SQL 就可以可靠地执行此操作的方法,无论数据库是新数据库还是已经看到一些活动的现有数据库。
确保有 0 个使用select count(*) from SYSTEM_LOBS.LOB_IDS
的现有 LOB
在具有 LOB 的任何表中插入一行,以便将 LobManager usageChanged 设置为 true。
提交。
删除刚刚创建的行。
再次提交。
执行CHECKPOINT
,以便清理所有 lob 元数据。由于最近添加了 LOB,因此检查点实际上会运行 LobManager.deleteUnusedLobs() 并清理未使用的 lob 条目。
使用SET FILES LOB COMPRESSED TRUE
启用压缩。这现在有效,因为 SYSTEM_LOBS.LOB_IDS 表中不再有任何内容。
如果您想可靠地修剪由于压缩未激活而变得巨大的 HSQLDB .lobs 文件:
插入带有 LOB 的另一行,以便 HSQLDB 可以计算 lob 空间使用情况(当检查点期间没有 LOB 时,LobManager.getLobUseLimit 不起作用) 提交 再次执行CHECKPOINT
,以便 lob 文件被修剪以适应使用情况。
删除您在检查点之前创建的行。
提交
【讨论】:
以上是关于HSQLDB:为现有数据库启用 LOB 压缩的主要内容,如果未能解决你的问题,请参考以下文章
使用 Hibernate 更新 HSQLDB 上的 LOB/BLOB 值会产生数据异常