DuckDB 0.6.0 发布公告

Author Avatar
Mark Raasveldt
2022-11-14 · 11 分钟

Image of white-headed duck

DuckDB 团队很高兴地宣布最新的 DuckDB 版本 (0.6.0) 已经发布。 此版本的 DuckDB 以 白头硬尾鸭(Oxyura leucocephala)命名,这是一种原产于欧亚大陆的濒危物种。

要安装新版本,请访问安装指南。 请注意,该版本仍在推出中,因此可能并非所有内容都已发布。 完整的发行说明可以在 GitHub 上找到。

0.6.0 版本的新特性

新版本包含对存储系统的许多改进、常规性能改进、内存管理改进和新功能。 以下是影响最大的更改摘要,以及实现这些功能的关联 PR。

存储改进

由于我们正在努力稳定存储格式并向 1.0 版本迈进,因此我们一直在积极改进我们的存储格式,包括许多压缩改进

乐观地写入磁盘。 在之前的 DuckDB 版本中,单个事务的数据首先加载到内存中,并且只有在提交时才写入磁盘。 虽然这在数据以适合内存的批次加载时效果很好,但在单个事务中加载大量数据时效果不佳,例如将一个非常大的文件摄取到系统中时。

此版本引入了乐观地写入磁盘。 在单个事务中加载大型数据集时,即使在 COMMIT 发生之前,数据也会被压缩并流式传输到数据库文件。 提交事务后,数据将已写入磁盘,并且无需进一步写入。 在回滚时,任何乐观地写入的数据都将被系统回收。

并行数据加载。 除了乐观地写入数据到磁盘外,此版本还包括对将数据并行加载到各个表中的支持。 这大大提高了在具有多个核心(即,所有现代机器)的机器上的数据加载性能。

以下是在具有 10 个核心的 M1 Max 上从 Parquet 文件加载 1.5 亿行 Taxi 数据集的加载时间的基准测试

版本 加载时间
v0.5.1 91.4 秒
v0.6.0 17.2 秒

DuckDB 支持两种模式 – order-preservingnon-order-preserving 并行数据加载。

保持顺序的加载会保留插入顺序,以便例如 CSV 文件中的第一行是 DuckDB 表中的第一行。 非保持顺序的加载不提供此类保证 – 而是可能在加载时重新排序数据。 默认情况下,使用保持顺序的加载,这涉及一些额外的簿记。 可以使用 SET preserve_insertion_order = false 语句禁用保留插入顺序。

压缩改进

FSST。 此版本中引入了 快速静态符号表压缩算法。 这种最先进的压缩算法使用字典压缩字符串内部的数据,同时保持对高效扫描和随机查找的支持。 这大大提高了具有许多唯一值但具有公共元素(例如,电子邮件地址或 URL)的字符串的压缩率。

下面显示了 TPC-H SF1 数据集的压缩率改进

压缩 大小
未压缩 761 MB
字典 510 MB
FSST + 字典 251 MB

Chimp。 包括 Chimp 压缩算法,它是轻量级浮点压缩领域中最先进的技术。 Chimp 是 Gorillas 的改进版本,它既实现了更好的压缩率,又实现了更快的解压缩速度。

PatasPatas 是一种新型浮点压缩方法,它通过优化 Chimp 算法中的单个案例来迭代 Chimp 算法。 虽然 Patas 通常具有比 Chimp 略低的压缩率,但它具有显着更快的解压缩速度,几乎与未压缩数据在读取速度上相匹配。

下面显示了一个数据集的压缩率,该数据集包含存储为 double (8 字节浮点数) 的城市温度

压缩 大小
未压缩 25.4 MB
Chimp 9.7 MB
Patas 10.2 MB

性能改进

DuckDB 旨在为各种工作负载提供非常高的性能。 因此,我们始终在努力提高各种工作负载的性能。 此版本也不例外。

并行 CSV 加载(实验性)。 在此版本中,我们推出了 一种新的实验性并行 CSV 读取器。 这大大提高了将大型 CSV 文件摄取到系统中的速度。 虽然我们已尽最大努力使并行 CSV 读取器具有鲁棒性 – CSV 解析是一个雷区,因为存在如此多种不同的文件 – 因此我们目前已将该读取器标记为实验性。

可以通过将 experimental_parallel_csv 标志设置为 true 来启用并行 CSV 读取器。 我们的目标是在未来的 DuckDB 版本中使并行 CSV 读取器成为默认读取器。

SET experimental_parallel_csv = true;

下面是一个包含 TPC-H 基准测试中的 lineitem 表的 720 MB CSV 文件的加载时间,

变体 加载时间
单线程 3.5 秒
并行 0.6 秒

并行 CREATE INDEX & 索引内存管理改进。 此版本中的索引创建也得到了显着加速,因为 CREATE INDEX 语句现在可以完全并行执行。 此外,通过 内联小型结构大大减少了 ART 完成的内存分配数量,这既减少了内存大小,又进一步提高了性能。

下面显示了在具有 1600 万个值的单个列上创建索引的计时。

版本 创建索引时间
v0.5.1 5.92 秒
v0.6.0 1.38 秒

并行 count(DISTINCT)。 包含 DISTINCT 聚合的聚合,最常用于精确的不同计数计算(例如,count(DISTINCT col))以前必须以单线程模式执行。 从 v0.6.0 开始,DuckDB 可以并行执行这些查询,从而大大提高了速度。

SQL 语法改进

SQL 是与 DuckDB 交互的主要方式 – 并且 DuckDB 尝试拥有易于使用的 SQL 方言。 此版本包含对 SQL 方言的进一步改进。

UNION 类型。 此版本引入了 UNION 类型,它允许在 DuckDB 中存储和查询和类型。 例如

CREATE TABLE messages (u UNION(num INTEGER, error VARCHAR));
INSERT INTO messages VALUES (42);
INSERT INTO messages VALUES ('oh my globs');
SELECT * FROM messages;
┌─────────────┐
│      u      │
├─────────────┤
│ 42          │
│ oh my globs │
└─────────────┘

和类型是强类型的 – 但它们允许表中的单个值表示为多种类型之一。 文档中的union 页面包含有关如何使用此新复合类型的更多信息。

FROM-first。 从此版本开始,DuckDB 支持使用 FROM 子句而不是 SELECT 子句来开始查询。 实际上,SELECT 子句现在是完全可选的,默认为 SELECT *。 这意味着以下查询现在在 DuckDB 中有效

-- SELECT clause is optional, SELECT * is implied (if not included)
FROM tbl;

-- first 5 rows of the table
FROM tbl LIMIT 5;

-- SELECT can be used after the FROM
FROM tbl SELECT l_orderkey;

-- insert all data from tbl1 into tbl2
INSERT INTO tbl2 FROM tbl1;

COLUMNS 表达式。 此版本增加了对 COLUMNS 表达式的支持,该表达式的灵感来自 ClickHouse 语法COLUMNS 表达式允许您在多个列上执行表达式或函数,而无需复制完整的表达式。

CREATE TABLE obs (id INTEGER, val1 INTEGER, val2 INTEGER);
INSERT INTO obs VALUES (1, 10, 100), (2, 20, NULL), (3, NULL, 300);
SELECT min(COLUMNS(*)), count(*) FROM obs;
┌─────────────┬───────────────┬───────────────┬──────────────┐
│ min(obs.id) │ min(obs.val1) │ min(obs.val2) │ count_star() │
├─────────────┼───────────────┼───────────────┼──────────────┤
│ 1           │ 10            │ 100           │ 3            │
└─────────────┴───────────────┴───────────────┴──────────────┘

COLUMNS 表达式支持所有星号表达式,包括 EXCLUDEREPLACE 语法。 此外,COLUMNS 表达式可以将正则表达式作为参数

SELECT COLUMNS('val[0-9]+') FROM obs;
┌──────┬──────┐
│ val1 │ val2 │
├──────┼──────┤
│ 10   │ 100  │
│ 20   │ NULL │
│ NULL │ 300  │
└──────┴──────┘

列表推导支持。 列表推导是定义列表操作的一种优雅而强大的方式。 DuckDB 现在还支持列表推导作为其 SQL 方言的一部分。 例如,以下查询现在有效

SELECT [x + 1 for x in [1, 2, 3]] AS l;
┌───────────┐
│     l     │
├───────────┤
│ [2, 3, 4] │
└───────────┘

DuckDB 中非常有效地实现了嵌套类型和结构,并且现在使用起来也更加优雅。

内存管理改进

在使用大型数据集时,内存管理始终是一个潜在的痛点。 通过使用流式执行引擎和缓冲区管理器,DuckDB 支持对大于内存的数据集执行许多操作。 DuckDB 还旨在支持中间结果不适合内存的查询,方法是使用磁盘溢出技术,并支持 高效的核外排序核外窗口函数核外哈希连接

此版本通过极大地优化 核外哈希连接来进一步改进了这一点,从而在数据超过内存限制时,性能下降更加平稳。

内存限制 (GB) 旧时间 (秒) 新时间 (秒)
10 1.97 1.96
9 1.97 1.97
8 2.23 2.22
7 2.23 2.44
6 2.27 2.39
5 2.27 2.32
4 2.81 2.45
3 5.60 3.20
2 7.69 3.28
1 17.73 4.35

jemalloc。 此外,此版本默认将 jemalloc 分配器与 Linux 版本的 DuckDB 捆绑在一起,这解决了标准 GLIBC 分配器不会将块返回给操作系统的一个未解决的问题,从而不必要地导致 Linux 版本上的内存不足错误。 请注意,此问题不会发生在 macOS 或 Windows 上,因此我们继续在那里使用标准分配器(至少目前是这样)。

Shell 改进

DuckDB 有一个命令行界面,该界面是从 SQLite 的命令行界面改编而来的,因此支持与 SQLite 非常相似的界面。 此博客文章中的所有表格都是使用 CLI 中的 .mode markdown 生成的。

DuckDB shell 还提供了 SQLite shell 的一些改进,例如语法突出显示,并且此版本包括一些新的好东西。

DuckBox 渲染。 此版本包括默认使用的 新的 .mode duckbox 渲染。 此框渲染适应 shell 的大小,并忽略列和行,以提供结果的更好概述。 它通过忽略中间的行来非常快速地渲染大型结果集。 这样,在 shell 中键入 SELECT * FROM tbl 不再会炸毁它。 实际上,现在可以使用它来快速了解数据集。

可以使用 .maxrows X 设置更改渲染的行数,并且可以使用 .mode box 命令切换回旧的渲染。

SELECT * FROM '~/Data/nyctaxi/nyc-taxi/2014/04/data.parquet';
┌───────────┬─────────────────────┬─────────────────────┬───┬────────────┬──────────────┬──────────────┐
│ vendor_id │      pickup_at      │     dropoff_at      │ … │ tip_amount │ tolls_amount │ total_amount │
│  varchar  │      timestamp      │      timestamp      │   │   float    │    float     │    float     │
├───────────┼─────────────────────┼─────────────────────┼───┼────────────┼──────────────┼──────────────┤
│ CMT       │ 2014-04-08 08:59:39 │ 2014-04-08 09:28:57 │ … │        3.7 │          0.0 │         22.2 │
│ CMT       │ 2014-04-08 14:59:22 │ 2014-04-08 15:04:52 │ … │        1.3 │          0.0 │          7.8 │
│ CMT       │ 2014-04-08 08:45:28 │ 2014-04-08 08:50:41 │ … │        1.2 │          0.0 │          7.2 │
│ CMT       │ 2014-04-08 08:00:20 │ 2014-04-08 08:11:31 │ … │        1.7 │          0.0 │         10.2 │
│ CMT       │ 2014-04-08 08:38:36 │ 2014-04-08 08:44:37 │ … │        1.2 │          0.0 │          7.2 │
│ CMT       │ 2014-04-08 07:52:53 │ 2014-04-08 07:59:12 │ … │        1.3 │          0.0 │          7.8 │
│ CMT       │ 2014-04-08 16:08:16 │ 2014-04-08 16:12:38 │ … │        1.4 │          0.0 │          8.4 │
│ CMT       │ 2014-04-08 12:04:09 │ 2014-04-08 12:14:30 │ … │        1.7 │          0.0 │         10.2 │
│ CMT       │ 2014-04-08 16:18:38 │ 2014-04-08 16:37:04 │ … │        2.5 │          0.0 │         17.5 │
│ CMT       │ 2014-04-08 15:28:00 │ 2014-04-08 15:34:44 │ … │        1.4 │          0.0 │          8.4 │
│  ·        │          ·          │          ·          │ · │         ·  │           ·  │           ·  │
│  ·        │          ·          │          ·          │ · │         ·  │           ·  │           ·  │
│  ·        │          ·          │          ·          │ · │         ·  │           ·  │           ·  │
│ CMT       │ 2014-04-25 00:09:34 │ 2014-04-25 00:14:52 │ … │        2.5 │          0.0 │         10.0 │
│ CMT       │ 2014-04-25 01:59:39 │ 2014-04-25 02:16:07 │ … │        3.5 │          0.0 │         21.0 │
│ CMT       │ 2014-04-24 23:02:08 │ 2014-04-24 23:47:10 │ … │        8.8 │          0.0 │         52.8 │
│ CMT       │ 2014-04-25 01:27:11 │ 2014-04-25 01:56:53 │ … │        4.6 │          0.0 │         27.6 │
│ CMT       │ 2014-04-25 00:15:46 │ 2014-04-25 00:25:37 │ … │        1.0 │          0.0 │         11.5 │
│ CMT       │ 2014-04-25 00:17:53 │ 2014-04-25 00:22:52 │ … │        1.3 │          0.0 │          7.8 │
│ CMT       │ 2014-04-25 03:13:19 │ 2014-04-25 03:21:50 │ … │        2.1 │          0.0 │         12.6 │
│ CMT       │ 2014-04-24 23:53:03 │ 2014-04-25 00:16:01 │ … │       2.85 │          0.0 │        31.35 │
│ CMT       │ 2014-04-25 00:26:08 │ 2014-04-25 00:31:25 │ … │        1.4 │          0.0 │          8.4 │
│ CMT       │ 2014-04-24 23:21:39 │ 2014-04-24 23:33:57 │ … │        1.0 │          0.0 │         11.5 │
├───────────┴─────────────────────┴─────────────────────┴───┴────────────┴──────────────┴──────────────┤
│ 14618759 rows (20 shown)                                                        18 columns (6 shown) │
└──────────────────────────────────────────────────────────────────────────────────────────────────────┘

上下文感知自动完成。 shell 现在还附带 上下文感知自动完成。 按 Tab 字符触发自动完成。 shell 自动完成四个不同的组:(1)关键字,(2)表名 + 表函数,(3)列名 + 标量函数,以及(4)文件名。 shell 查看 SQL 语句中的位置以确定要触发哪些自动完成。 例如

S -> SELECT

SELECT s -> student_id

SELECT student_id F -> FROM


SELECT student_id FROM g -> grades

SELECT student_id FROM 'd -> data/

SELECT student_id FROM 'data/ -> data/grades.csv

进度条。 DuckDB 已在查询中支持进度条一段时间,但它们始终是选择加入的。 在此版本中,我们 美化了进度条,并在 shell 中默认启用了它。 当运行超过 2 秒的查询时,将弹出进度条,并显示查询的预计完成时间。

COPY lineitem TO 'lineitem-big.parquet';
   32% ▕███████████████████▏                                        ▏ 

将来,我们的目标是在其他客户端中默认启用进度条。 现在,可以通过运行以下 SQL 查询手动完成此操作

PRAGMA enable_progress_bar;
PRAGMA enable_print_progress_bar;