DuckDB 0.7.0 发布公告
DuckDB 团队很高兴地宣布最新版本的 DuckDB (0.7.0) 已发布。此版本的 DuckDB 以“拉布拉多”命名,名称来源于北美洲原生的拉布拉多鸭 (Camptorhynchus labradorius)。
要安装新版本,请访问安装指南。完整的发行说明可以在 GitHub 上找到。
0.7.0 中的新内容
新版本包含对 JSON 支持的许多改进,新的 SQL 功能,数据摄取和导出的改进以及其他新功能。以下是最重要的更改的摘要,以及实现这些功能的已链接 PR。
数据摄取/导出改进
JSON 摄取。 此版本引入了 read_json
和 read_json_auto
方法。 这些可用于将 JSON 文件摄取为表格格式。 类似于 read_csv
, read_json
方法需要指定模式,而 read_json_auto
使用采样从文件中自动推断 JSON 的模式。 支持 换行符分隔的 JSON 和常规 JSON。
FROM 'data/json/with_list.json';
id | name |
---|---|
1 | [O, Brother,, Where, Art, Thou?] |
2 | [Home, for, the, Holidays] |
3 | [The, Firm] |
4 | [Broadcast, News] |
5 | [Raising, Arizona] |
分区 Parquet/CSV 导出。 DuckDB 已经可以摄取 Hive 分区 Parquet 和 CSV 文件一段时间了。 在此版本之后,DuckDB 也将能够使用 PARTITION_BY
子句写入 Hive 分区数据。 这些文件可以本地或远程导出到 S3 兼容的存储。 这是一个本地示例
COPY orders TO 'orders' (FORMAT parquet, PARTITION_BY (year, month));
这将导致 Parquet 文件写入以下目录结构中
orders
├── year=2021
│ ├── month=1
│ │ ├── file1.parquet
│ │ └── file2.parquet
│ └── month=2
│ └── file3.parquet
└── year=2022
├── month=11
│ ├── file4.parquet
│ └── file5.parquet
└── month=12
└── file6.parquet
并行 Parquet/CSV 写入。 通过并行 Parquet 和 CSV 写入器支持,此版本中 Parquet 和 CSV 写入速度大大提高。
格式 | 旧 | 新 (8T) |
---|---|---|
CSV | 2.6 秒 | 0.4 秒 |
Parquet | 7.5 秒 | 1.3 秒 |
请注意,目前并行写入目前仅限于非插入顺序保留 - 可以通过将 preserve_insertion_order
设置为 false 来切换。 在未来的版本中,我们的目标是减轻这种限制,并对并行插入顺序保留写入进行排序。
多数据库支持
附加功能。 此版本增加了将多个数据库附加到同一 DuckDB 实例的支持。 这可以轻松地在单独的 DuckDB 数据库文件之间传输数据,并且还允许将来自单独数据库文件的数据合并到单个查询中。 也可以附加远程 DuckDB 实例(例如,存储在 GitHub 等网络可访问位置)。
ATTACH 'new_db.db';
CREATE TABLE new_db.tbl (i INTEGER);
INSERT INTO new_db.tbl SELECT * FROM range(1000);
DETACH new_db;
请参阅文档以获取更多信息。
SQLite 存储后端。 除了增加对附加 DuckDB 数据库的支持外,此版本还增加了对可插拔数据库引擎的支持。 这允许扩展定义自己的数据库和目录引擎,这些引擎可以附加到系统中。 附加后,引擎可以支持读取和写入。SQLite 扩展利用此功能为 SQLite 数据库文件添加对 DuckDB 的本机读/写支持。
ATTACH 'sqlite_file.db' AS sqlite (TYPE sqlite);
CREATE TABLE sqlite.tbl (i INTEGER);
INSERT INTO sqlite.tbl VALUES (1), (2), (3);
SELECT * FROM sqlite.tbl;
使用此功能,可以附加,查询和修改 SQLite 数据库文件,就像它们是本机 DuckDB 数据库文件一样。 这允许在 SQLite 和 DuckDB 之间快速传输数据,并允许您使用 DuckDB 丰富的 SQL 方言来查询存储在 SQLite 表中的数据。
新的 SQL 功能
Upsert 支持。 通过 ON CONFLICT
子句以及与 SQLite
兼容的 INSERT OR REPLACE
/INSERT OR IGNORE
语法,此版本增加了Upsert 支持。
CREATE TABLE movies (id INTEGER PRIMARY KEY, name VARCHAR);
INSERT INTO movies VALUES (1, 'A New Hope');
FROM movies;
id | name |
---|---|
1 | 星球大战:新希望 |
INSERT OR REPLACE INTO movies VALUES (1, 'The Phantom Menace');
FROM movies;
id | name |
---|---|
1 | 星球大战:魅影危机 |
请参阅文档以获取更多信息。
Lateral Joins。 此版本增加了对lateral joins的支持。 Lateral joins 是相关子查询的更灵活的变体,可以更轻松地处理嵌套数据,因为它们允许更容易地展开嵌套数据。
Positional Joins。 虽然 SQL 正式建模无序集,但实际上数据集的顺序确实经常具有意义。 当将数据加载到表中或将数据导出回文件时,以及在没有相应的 ORDER BY
子句的情况下执行诸如 LIMIT
之类的查询时,DuckDB 提供了围绕维护行顺序的保证。
为了提高对此用例的支持,此版本引入了 POSITIONAL JOIN
。 这种新的连接类型不是连接行的值,而是基于它们在表中的位置连接行。
CREATE TABLE t1 AS FROM (VALUES (1), (2), (3)) t(i);
CREATE TABLE t2 AS FROM (VALUES (4), (5), (6)) t(k);
SELECT * FROM t1 POSITIONAL JOIN t2;
i | k |
---|---|
1 | 4 |
2 | 5 |
3 | 6 |
Python API 改进
查询构建。 通过允许查询关系,此版本引入了使用 Python API 更轻松地进行增量查询构建。 这使您可以将长 SQL 查询分解为多个较小的 SQL 查询,并允许您轻松检查查询中间结果。
>>> import duckdb
>>> lineitem = duckdb.sql('FROM lineitem.parquet')
>>> lineitem.limit(3).show()
┌────────────┬───────────┬───────────┬───┬───────────────────┬────────────┬──────────────────────┐
│ l_orderkey │ l_partkey │ l_suppkey │ … │ l_shipinstruct │ l_shipmode │ l_comment │
│ int32 │ int32 │ int32 │ │ varchar │ varchar │ varchar │
├────────────┼───────────┼───────────┼───┼───────────────────┼────────────┼──────────────────────┤
│ 1 │ 155190 │ 7706 │ … │ DELIVER IN PERSON │ TRUCK │ egular courts abov… │
│ 1 │ 67310 │ 7311 │ … │ TAKE BACK RETURN │ MAIL │ ly final dependenc… │
│ 1 │ 63700 │ 3701 │ … │ TAKE BACK RETURN │ REG AIR │ riously. regular, … │
├────────────┴───────────┴───────────┴───┴───────────────────┴────────────┴──────────────────────┤
│ 3 rows 16 columns (6 shown) │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
>>> lineitem_filtered = duckdb.sql('FROM lineitem WHERE l_orderkey>5000')
>>> lineitem_filtered.limit(3).show()
┌────────────┬───────────┬───────────┬───┬────────────────┬────────────┬──────────────────────┐
│ l_orderkey │ l_partkey │ l_suppkey │ … │ l_shipinstruct │ l_shipmode │ l_comment │
│ int32 │ int32 │ int32 │ │ varchar │ varchar │ varchar │
├────────────┼───────────┼───────────┼───┼────────────────┼────────────┼──────────────────────┤
│ 5024 │ 165411 │ 444 │ … │ NONE │ AIR │ to the expre │
│ 5024 │ 57578 │ 84 │ … │ COLLECT COD │ REG AIR │ osits hinder caref… │
│ 5024 │ 111009 │ 3521 │ … │ NONE │ MAIL │ zle carefully saut… │
├────────────┴───────────┴───────────┴───┴────────────────┴────────────┴──────────────────────┤
│ 3 rows 16 columns (6 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
>>> duckdb.sql('SELECT min(l_orderkey), max(l_orderkey) FROM lineitem_filtered').show()
┌─────────────────┬─────────────────┐
│ min(l_orderkey) │ max(l_orderkey) │
│ int32 │ int32 │
├─────────────────┼─────────────────┤
│ 5024 │ 6000000 │
└─────────────────┴─────────────────┘
请注意,所有内容都是延迟评估的。 在执行最终查询之前,不会从磁盘读取 Parquet 文件 - 并且查询会完全优化。 执行分解的查询将与一次执行长 SQL 查询一样快。
Python 摄取 API。 此版本增加了几个熟悉的,遵循其他库使用的标准约定的数据摄取和导出 API。 这些函数也发出关系 - 可以再次直接查询。
>>> lineitem = duckdb.read_csv('lineitem.csv')
>>> lineitem.limit(3).show()
┌────────────┬───────────┬───────────┬───┬───────────────────┬────────────┬──────────────────────┐
│ l_orderkey │ l_partkey │ l_suppkey │ … │ l_shipinstruct │ l_shipmode │ l_comment │
│ int32 │ int32 │ int32 │ │ varchar │ varchar │ varchar │
├────────────┼───────────┼───────────┼───┼───────────────────┼────────────┼──────────────────────┤
│ 1 │ 155190 │ 7706 │ … │ DELIVER IN PERSON │ TRUCK │ egular courts abov… │
│ 1 │ 67310 │ 7311 │ … │ TAKE BACK RETURN │ MAIL │ ly final dependenc… │
│ 1 │ 63700 │ 3701 │ … │ TAKE BACK RETURN │ REG AIR │ riously. regular, … │
├────────────┴───────────┴───────────┴───┴───────────────────┴────────────┴──────────────────────┤
│ 3 rows 16 columns (6 shown) │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
>>> duckdb.sql('SELECT min(l_orderkey) FROM lineitem').show()
┌─────────────────┐
│ min(l_orderkey) │
│ int32 │
├─────────────────┤
│ 1 │
└─────────────────┘
Polars 集成。 此版本增加了与 Polars DataFrame 库紧密集成的支持,类似于我们与 Pandas DataFrames 的集成。 可以使用 .pl()
函数将结果转换为 Polars DataFrames。
import duckdb
duckdb.sql('SELECT 42').pl()
shape: (1, 1)
┌─────┐
│ 42 │
│ --- │
│ i32 │
╞═════╡
│ 42 │
└─────┘
此外,可以使用 SQL 接口直接查询 Polars DataFrames。
import duckdb
import polars as pl
df = pl.DataFrame({'a': 42})
duckdb.sql('SELECT * FROM df').pl()
shape: (1, 1)
┌─────┐
│ a │
│ --- │
│ i64 │
╞═════╡
│ 42 │
└─────┘
fsspec 文件系统支持。 此版本增加了对fsspec 文件系统 API的支持。fsspec 允许用户定义自己的文件系统,他们可以将其传递给 DuckDB。 然后,DuckDB 将使用此文件系统来读取和写入数据。 这支持 DuckDB 尚未原生支持的存储后端,例如 FTP。
import duckdb
from fsspec import filesystem
duckdb.register_filesystem(filesystem('gcs'))
data = duckdb.query("SELECT * FROM read_csv_auto('gcs:///bucket/file.csv')").fetchall()
有关更多信息,请查看指南
存储改进
Delta 压缩。 使用新的 delta 和 delta 常量压缩改进了存储中数值的压缩。 当压缩等间距的值时,此压缩方法特别有效。 例如,数字序列(1, 2, 3, ...
)或时间戳,它们之间具有固定的间隔(12:00:01, 12:00:02, 12:00:03, ...
)。
结语
完整的发行说明可以在GitHub 上找到。 我们要感谢所有贡献者为改进 DuckDB 所做的辛勤工作。