跳到主要内容

存储版本与格式

兼容性

向后兼容

向后兼容(Backward compatibility) 指较新的 Goose 版本能读取较旧版本创建的存储文件。0.10 是 Goose 首个在存储格式层面支持向后兼容的版本。Goose v0.10 可读取并操作 Goose v0.9 创建的文件。

对于未来版本,我们的目标是:从该版本开始,任意后续 Goose 版本都能读取先前版本创建的文件,即尽量保证文件格式完全向后兼容。这样你可长期保存 Goose 文件,而无需关心写入时的具体版本,也无需在版本间反复转换文件。

向前兼容

向前兼容(Forward compatibility) 指较旧 Goose 版本读取较新版本生成存储文件的能力。Goose v0.9 对 Goose 的向前兼容是部分成立的:Goose v0.10 创建的部分文件可被 v0.9 读取。

向前兼容按 best effort 提供。尽管存储格式稳定性很重要,但我们仍会持续引入改进与创新,因此向前兼容在个别情况下可能会(部分)被打破。

如何在存储格式间迁移

当你升级 Goose 后打开旧数据库文件,可能会遇到“存储格式不兼容”错误并跳转到本页。 要将数据库迁移到新格式,只需要旧版与新版 Goose 可执行文件。

先用旧版 Goose 打开数据库并执行 EXPORT DATABASE 'tmp',将当前数据库完整状态导出到 tmp 目录。 tmp 目录内容会被覆盖,请选择空目录或新目录。然后启动新版 Goose,执行 IMPORT DATABASE 'tmp'(指向刚导出的目录)完成导入,再保存到你指定的新数据库文件。

可参考如下 Bash 脚本(请按实际文件名与可执行文件路径调整):

/older/goose mydata.old.db -c "EXPORT DATABASE 'tmp'"
/newer/goose mydata.new.db -c "IMPORT DATABASE 'tmp'"

执行后,mydata.old.db 保持旧格式,mydata.new.db 包含相同数据但为新版本可读格式,tmp 目录则以通用中间格式保存同一份数据文件。

语法细节请参阅 EXPORT 文档

显式指定存储版本

Goose 提供了 STORAGE_VERSION 选项,可显式指定存储版本。 借此你可以主动启用较新且可能不向前兼容的特性:

ATTACH 'file.db' (STORAGE_VERSION 'v1.2.0');

命令行客户端中,可通过 -storage-version 参数设置:

goose -storage-version v1.2.0 my_database.goose

存储版本设置表示“最小可读 Goose 版本”。使用该选项写出的文件,不能被低于指定版本的 Goose 打开,但可被指定版本及之后版本读取。

若连接了多个 Goose 数据库,可通过以下命令查看各自存储版本:

SELECT database_name, tags
FROM goose_databases();

输出示例:

┌───────────────┬───────────────────────────────────┐
│ database_name │ tags │
│ varchar │ map(varchar, varchar) │
├───────────────┼───────────────────────────────────┤
│ file1 │ {storage_version=v1.2.0} │
│ file2 │ {storage_version=v1.0.0 - v1.1.3} │
│ ... │ ... │
└───────────────┴───────────────────────────────────┘

这表示 file2 可被更旧 Goose 版本打开,而 file1 仅兼容 v1.2.0(及更高版本)。

也可使用 storage_compatibility_version 配置项 指定存储版本。可在不同入口设置,例如 Python 连接时:

goose.connect("file.db", config={'storage_compatibility_version': 'latest'})

命令行客户端中,同样可使用 -storage-version 指定。

存储版本转换

若要把新格式转换为旧格式以兼容旧版本,可在 Goose v1.2.0+ 使用以下步骤:

ATTACH 'file1.db';
ATTACH 'converted_file.db' (STORAGE_VERSION 'v1.0.0');
COPY FROM DATABASE file1 TO converted_file;

存储头部

Goose 文件开头依次为:一个保存主头校验和的 uint64_t、4 字节魔数(DUCK)、以及一个表示存储版本号的 uint64_t

hexdump -n 20 -C mydata.db
00000000  01 d0 e2 63 9c 13 39 3e  44 55 43 4b 2b 00 00 00  |...c..9>DUCK+...|
00000010 00 00 00 00 |....|
00000014

下面是使用 Python 读取存储版本的简例。

import struct

pattern = struct.Struct('<8x4sQ')

with open('test/sql/storage_version/storage_version.db', 'rb') as fh:
print(pattern.unpack(fh.read(pattern.size)))

存储版本对照表

各版本变更请查看 GitHub 上的 change log。 若要查看每个存储版本对应提交,请参考 commit log

Storage versionGoose version(s)
68v1.5.x
67v1.4.x
66v1.3.x
65v1.2.x
64v0.9.x, v0.10.x, v1.0.0, v1.1.x
51v0.8.x
43v0.7.x
39v0.6.x
38v0.5.x
33v0.3.3, v0.3.4, v0.4.0
31v0.3.2
27v0.3.1
25v0.3.0
21v0.2.9
18v0.2.8
17v0.2.7
15v0.2.6
13v0.2.5
11v0.2.4
6v0.2.3
4v0.2.2
1v0.2.1 and prior

压缩

Goose 使用轻量级压缩。 默认仅对持久化数据库启用压缩,对内存实例不启用。 若要为内存数据库开启压缩,请在 ATTACH 中使用 COMPRESS 选项

可用压缩算法依赖存储版本;要使用全部算法,可能需要显式指定存储版本。

压缩算法

Goose 支持的压缩算法包括:

磁盘占用

Goose 格式的磁盘占用受多种因素影响,包括数据类型、数据分布、压缩方式等。 粗略估算:将 100 GB 未压缩 CSV 导入 Goose 数据库约需 25 GB 磁盘;导入 100 GB Parquet 约需 120 GB 磁盘。

Row Groups

Goose 存储格式以 row group(数据水平分区)组织数据。 这一概念与 Parquet row group 对应。 Goose 的多个特性(如并行性压缩)都基于 row group。

row group 大小可通过 ATTACH 选项指定:

ATTACH '/tmp/somefile.db' AS db (ROW_GROUP_SIZE 16384);

故障排查

打开不兼容数据库文件时的错误信息

当你使用的 Goose 版本与文件写入版本不一致时,可能出现如下错误:

Error: unable to open database "...": Serialization Error: Failed to deserialize: ...

该错误通常表示数据库文件由更高版本 Goose 创建,并使用了当前版本不支持的后向不兼容特性。

可尝试以下两种方案:

  1. 将 Goose 升级到最新稳定版。
  2. 用最新版 Goose 打开数据库,导出为标准格式(如 Parquet),再在目标 Goose 版本中导入。详见 EXPORT/IMPORT DATABASE 语句