⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
存储版本和格式

兼容性

向后兼容性

向后兼容性指的是较新版本的 DuckDB 读取由较旧版本的 DuckDB 创建的存储文件的能力。0.10 版本是 DuckDB 首次在存储格式中支持向后兼容性的发布。DuckDB v0.10 可以读取和操作由前一个 DuckDB 版本——DuckDB v0.9——创建的文件。

对于未来的 DuckDB 版本,我们的目标是确保从本次发布开始,之后发布的任何 DuckDB 版本都能够读取由之前版本创建的文件。我们希望确保文件格式完全向后兼容。这让您可以保留存储在 DuckDB 文件中的数据,并保证您能够读取这些文件,而无需担心文件是用哪个版本写入的,也无需在不同版本之间转换文件。

向前兼容性

向前兼容性指的是较旧版本的 DuckDB 读取由较新版本的 DuckDB 生成的存储文件的能力。DuckDB v0.9 部分向前兼容 DuckDB v0.10。DuckDB v0.10 创建的某些文件可以被 DuckDB v0.9 读取。

向前兼容性是尽力而为提供的。尽管存储格式的稳定性很重要,但我们未来仍希望对存储格式进行许多改进和创新。因此,向前兼容性有时可能会(部分)中断。

如何在存储格式之间迁移

当您更新 DuckDB 并打开旧的数据库文件时,可能会遇到关于存储格式不兼容的错误消息,并指向本页面。要将您的数据库迁移到新格式,您只需要旧版本和新版本的 DuckDB 可执行文件。

用旧版本的 DuckDB 打开您的数据库文件,并运行 SQL 语句 EXPORT DATABASE 'tmp'。这将允许您将当前使用的数据库的整个状态保存到 tmp 文件夹中。tmp 文件夹的内容将被覆盖,因此请选择一个空闲或尚未存在的目录。然后,启动新版本的 DuckDB 并执行 IMPORT DATABASE 'tmp'(指向之前填充的文件夹)来加载数据库,之后可以将其保存到您指定给 DuckDB 的文件中。

以下是一个实现此操作的 Bash 脚本(需要根据文件名和可执行文件位置进行调整)

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

在此之后,mydata.old.db 将保留旧格式,mydata.new.db 将包含相同的数据但采用可供更新的 DuckDB 版本访问的格式,而 tmp 文件夹将以通用格式作为不同的文件保存相同的数据。

有关语法的更多详细信息,请查阅 EXPORT 文档

显式存储版本

DuckDB v1.2.0 引入了 STORAGE_VERSION 选项,允许显式指定存储版本。使用此选项,您可以选择启用新的向前不兼容的功能

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

此设置指定了能够读取数据库文件的最低 DuckDB 版本。当数据库文件使用此选项写入时,生成的文件无法被比指定版本更旧的 DuckDB 发布版本打开。它们可以被指定版本以及所有更新版本的 DuckDB 读取。

如果您连接到 DuckDB 数据库,可以使用以下命令查询存储版本

SELECT database_name, tags FROM duckdb_databases();

这将显示存储版本

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

这意味着 file2 可以被过去的 DuckDB 版本打开,而 file1 仅与 v1.2.0(或未来版本)兼容。

在存储版本之间转换

要在 DuckDB v1.2.0+ 中将新格式转换为旧格式以实现兼容性,请使用以下序列

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

存储头部

DuckDB 文件以一个 uint64_t 开头,其中包含主头部的校验和,接着是四个魔术字节(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 上的更改日志。要查看更改每个存储版本的提交,请参阅提交日志

存储版本 DuckDB 版本
66 v1.3.x
65 v1.2.x
64 v0.9.x, v0.10.x, v1.0.0, v1.1.x
51 v0.8.x
43 v0.7.x
39 v0.6.x
38 v0.5.x
33 v0.3.3, v0.3.4, v0.4.0
31 v0.3.2
27 v0.3.1
25 v0.3.0
21 v0.2.9
18 v0.2.8
17 v0.2.7
15 v0.2.6
13 v0.2.5
11 v0.2.4
6 v0.2.3
4 v0.2.2
1 v0.2.1 及更早版本

压缩

DuckDB 使用轻量级压缩。请注意,压缩仅应用于持久性数据库,而不应用于内存实例

压缩算法

DuckDB 支持的压缩算法包括以下几种

磁盘使用情况

DuckDB 格式的磁盘使用情况取决于多种因素,包括数据类型和数据分布、所使用的压缩方法等。粗略估计,将 100 GB 未压缩的 CSV 文件加载到 DuckDB 数据库文件中将需要 25 GB 磁盘空间,而加载 100 GB 的 Parquet 文件将需要 120 GB 磁盘空间。

行组

DuckDB 的存储格式将数据存储在行组中,即数据的水平分区。这个概念等同于 Parquet 的行组。DuckDB 中的多项功能,包括并行性压缩,都基于行组。

故障排除

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

当您打开一个由不同于您正在使用的 DuckDB 版本写入的数据库文件时,可能会出现以下错误消息

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

该消息表示数据库文件是用较新版本的 DuckDB 创建的,并且使用了与用于读取该文件的 DuckDB 版本向后不兼容的功能。

有两种可能的解决方案

  1. 将您的 DuckDB 版本更新到最新的稳定版本。
  2. 使用最新版本的 DuckDB 打开数据库,将其导出为标准格式(例如 Parquet),然后使用任何版本的 DuckDB 导入。有关详细信息,请参阅 EXPORT/IMPORT DATABASE 语句