[OLAP] DuckDB : 开源免费的、面向嵌入式场景、列式存储的分析型数据库

0 序

  • DuckDB 是近期非常火的一款 AP 数据库,其独特的定位很有趣。甚至有数据库产品考虑将其纳入进来,作为分析能力的扩展。

考虑到项目中一个数据处理场景,就此调研一二。

  • DuckDB 的爆火,也给所有盲目追逐“大数据”的技术人敲响了警钟:
  • DuckDB 是一场复古的叛逆,也是一场属于单机的复仇。它告诉我们:在算力爆炸的今天,小,即是快;简,即是强。
  • 我们被云厂商和大数据鼓吹者洗脑太久了,总觉得不搞个集群、不弄个微服务,架构就不够“高大上”。但技术的本质是解决问题,而不是制造复杂度。
  • 重要结论:
  • DuckDB := 数据分析领域的 SQLLite (列式存储)

适合分析 / 列压缩 / 每一列在磁盘和内存中以分块数组的形式存储
内存局部性优化 / 读取查询速度更快

  • 适用于:单机/嵌入式场景

物联网/移动端/个人PC端/中小企业(TB级以下数据场景,尤其是数百GB级以下)

1 概述:DuckDB

DuckDB 介绍

产品定位与产生背景

  • DuckDB 是一个诞生于2018年,开源免费的、面向嵌入式场景的、列式存储的、In-ProcessOLAP 数据库。
  • 产生背景:2019 年, SIGMOD 有一篇 Demo 论文介绍 DuckDB:an embedded analytical database。随着单机内存的变大,大部分 OLTP 数据库都能在内存中放得下,而很多 OLAP 也有在单机就能搞定的趋势。单台服务器的内存很容易达到 TB,加上 SSD,搞个几十甚至上百 TB 很容易。DuckDB 就是为了填补这个空白而生的。
  • 定位:一款单机版/嵌入式分析型数据库 (数据分析领域的 SQLLite,但其底层是列式存储
  • Slogan : DuckDB 是一个分析式的 SQL 数据库管理系统
  • https://github.com/duckdb/duckdb
  • 主要编程语言: C/C++

image

  • 支持多种数据格式的导入与导出:
  • csv / excel / json / parquet 等本地文件格式
  • http(s) / s3 等远程文件格式

开源情况

  • DuckDB 采用 较为宽松的 MIT 协议开源。

其作为荷兰 CWI 数据库组的一个项目,学术气息比较浓厚,项目的组织很有教科书的感觉,架构很清晰,所以非常适合阅读学习。
从 OSS Insight 拉个一个 Star 数对比,可以看到 DuckDB 发展非常迅速。

https://ossinsight.io/analyze/duckdb/duckdb#overview

image

DuckDB 主要特点

  • DuckDB是一个免费的、开源的、面向单机的(嵌入式/非分布式的)数据库管理系统,专为【数据分析】和【在线分析处理】而设计。

这意味着以下几点:

  • 它是免费的开源软件,因此任何人都可以使用和修改代码。
  • 它是面向单机的/嵌入式的。

这意味着DBMS(数据库管理系统)与使用它的应用程序在同一进程中运行。这使得它快速且易于使用。

  • 它针对【数据分析】和【OLAP】(在线分析处理)进行了优化,而不仅仅是像典型数据库那样只针对事务数据。

这意味着数据【按列】而不是【按行】组织以优化聚合和分析。

  • 它支持【标准SQL】,因此可以在数据上运行查询、聚合、连接和其他SQL函数。
  • 它在【进程中运行】,即在应用程序本身内运行,而不是作为单独的进程运行。这消除了进程间通信的开销。

SQLite一样,它是一个简单的基于文件的数据库。因此,不需要单独安装服务器。只需将库包含在应用程序中即可。

主要优点

  • 易于安装、部署和使用。没有需要配置的服务器,可在应用程序内部嵌入运行,这使得它易于集成到不同编程语言环境中。
  • 尽管它很简单,但DuckDB具有丰富的功能集。它支持完整的SQL标准、事务、二级索引,并且与流行的数据分析编程语言如 Python 和 R 集成良好。
  • 免费的,任何人都可以使用和修改它,这降低了开发人员和数据分析师采用它的门槛。
  • 兼容性很好,几乎无依赖性,甚至可在浏览器中运行。
  • 具有灵活的扩展机制,这对于直接从 CSV、JSON、Parquet、MySQL 或直接从 S3 读取数据特别重要,能够大大提高开发人员的体验。
  • 可提供数据超出内存限制但小于磁盘容量规模下的工作负载,这样分析工作可通过 "便宜"的硬件来完成。

2 安装部署篇

  • DuckDB 安装部署过程相当简单,且支持多种部署模式:

image

CLI / Python / Go / Java / Nodejs / C/C++ / R / Rust / ODBC

简言之,DuckDB 提供了非常简单的安装方法,可从官网 https://duckdb.org/install/ 直接下载安装解压即可使用。此外,DuckDB 还可以内置在多种开发语言中使用。

安装 CLI by Windows(Powershell)

DuckDB 可以通过 PSDuckDB 模块与 PowerShell 无缝集成,从而实现从 PowerShell 环境中高效执行分析性 SQL 查询。

  • 以管理员权限打开 PowerShell :
PS C:\Windows\system32> Install-Module PSDuckDB                                                                                                                                                                                                                                                                                                         需要使用 NuGet 提供程序来继续操作
PowerShellGet 需要使用 NuGet 提供程序“2.8.5.201”或更高版本来与基于 NuGet 的存储库交互。必须在“C:\Program
Files\PackageManagement\ProviderAssemblies”或“C:\Users\EDY\AppData\Local\PackageManagement\ProviderAssemblies”中提供 NuGet 提供程序。也可以通过运行
'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force' 安装 NuGet 提供程序。是否要让 PowerShellGet 立即安装并导入 NuGet 提供程序?
[Y] 是(Y)  [N] 否(N)  [S] 暂停(S)  [?] 帮助 (默认值为“Y”): Y

不受信任的存储库
你正在从不受信任的存储库安装模块。如果你信任该存储库,请通过运行 Set-PSRepository cmdlet 更改其 InstallationPolicy 值。是否确实要从“PSGallery”安装模块?
[Y] 是(Y)  [A] 全是(A)  [N] 否(N)  [L] 全否(L)  [S] 暂停(S)  [?] 帮助 (默认值为“N”): Y

PS C:\Windows\system32>
  • 安装完成后,输入 psduckdb 即可使用
PS C:\Windows\system32> psduckdb
Welcome to PSDuckDB! 01/02/2026 09:02:51
Connected to an in-memory database
PSDuckDB: show databases;

database_name
-------------
memory


PSDuckDB: show tables
PSDuckDB: select 1 as tmp_a

tmp_a
-----
    1

PSDuckDB:
PSDuckDB: exit
PS C:\Windows\system32>

安装 CLI by Windows(解压即安装)

  • 下载后解压 zip 安装包,双击打开 duckdb.exe 即可使用

https://duckdb.org/install/?platform=windows&environment=cli

D:\Program\DuckDB-CLI\duckdb.exe

image

3 工作原理与架构篇

数据库架构

image

  • DuckDB 数据库可分为多个组件:Parser、Logical Planner、Optimizer、Physical Planner、Execution Engine、Transaction and Storage Managers

Parser

  • DuckDB SQL Parser 源自 Postgres SQL Parser。

Logical Planner

  • 其包含了两个过程 binder、plan generator。前者是解析所有引用的 schema 中的对象(如 table 或 view)的表达式,将其与列名和类型匹配。后者将 binder 生成的 AST 转换为由基本 logical query 查询运算符组成的树,就得到了一颗 type-resolved logical query plan。

Optimizer

优化器部分,会采用多种优化手段对 logical query plan 进行优化,最终生成 physical plan。例如,其内置一组 rewrite rules 来简化 expression tree,例如执行公共子表达式消除和常量折叠。针对表关联,会使用动态规划进行 join order 的优化,针对复杂的 join graph 会 fallback 到贪心算法会消除所有的 subquery。

Execution Engine

DuckDB 最开始采用了基于 Pull-based 的 Vector Volcano 的执行引擎,后来切换到了 Push-based 的 pipelines 执行方法。DuckDB 采用了向量化计算来来加速计算,具有内部实现的多种类型的 vector 以及向量化的 operator。另外出于可移植性原因,没有采用 JIT,因为 JIT引擎依赖于大型编译器库(例如LLVM),具有额外的传递依赖。

Transactions

DuckDB 通过 MVCC 提供了 ACID 的特性,实现了HyPer专门针对混合OLAP OLTP系统定制的可串行化MVCC 变种 。该变种立即 in-place 更新数据,并将先前状态存储在单独的 undo buffer 中,以供并发事务和 abort 使用。

Persistent Storage

DuckDB 使用面向读取优化的 DataBlocks 存储布局(单个文件)。逻辑表被水平分区为 chunks of columns,并使用轻量级压缩方法压缩成 physical block 。每个块都带有每列的min/max 索引,以便快速确定它们是否与查询相关。此外,每个块还带有每列的轻量级索引,可以进一步限制扫描的值数量。

4 使用指南篇

(本地)数据导入和导出

  • 推荐文献
  • 支持的数据导入与导出场景
SELECT * FROM read_csv('input.csv');
COPY tbl TO 'output.csv' (HEADER, DELIMITER ',');
SELECT 
    size, parse_path(filename), content
FROM read_text('test/sql/table_function/files/*.txt');
SELECT * FROM read_xlsx('test_excel.xlsx');
COPY tbl TO 'output.xlsx' WITH (FORMAT xlsx);
SELECT * FROM read_json_auto('input.json');
# COPY (SELECT * FROM range(3) tbl(n)) TO 'output.json';
{"n":0}
{"n":1}
{"n":2}

# COPY (SELECT * FROM range(3) tbl(n)) TO 'output.json' (ARRAY);
[
        {"n":0},
        {"n":1},
        {"n":2}
]

https://duckdb.org/docs/stable/guides/network_cloud_storage/http_import

SELECT * FROM read_parquet('input.parquet');
SELECT * FROM read_parquet('https://domain/path/to/file.parquet');
SELECT * FROM read_parquet('s3://{bucketName}/path/to/file.parquet');
COPY (SELECT * FROM tbl) TO 'output.parquet' (FORMAT parquet);
SELECT * FROM read_parquet('input.parquet');

DuckDB 支持使用该协议。目前支持以下格式:file:

  • file:/some/path(host完全省略)
  • file:///some/path(空主)
  • file://localhost/some/path (localhost作为host)

请注意,以下格式不被支持,因为它们是非标准的:

  • file:some/relative/path(相对路径)
  • file://some/path(双斩路径)
    此外,该协议目前不支持远程(非本地主机)主机。

Parquet 专章

  • 查看 parquet 文件的数据
D select * from read_parquet("D:\Program-Data\DuckDB\datasources\tb_demo.parquet") limit 10
col_0|col_1|col_2|col_3|
-----+-----+-----+-----+
    1|    2|    3|    4|
    5|    6|    7|    8|
    9|   10|   11|   12|
   13|   14|   15|   16|
  • 查询多个parquet文件的数据 (当数据结构(定义)一致时, 支持多个文件读.)
-- read 3 parquet files and treat them as a single table    
SELECT * FROM read_parquet(['file1.parquet', 'file2.parquet', 'file3.parquet']);
Wildcard Description
* matches any number of any characters (including none)
? matches any single character
[abc] matches one character given in the bracket
[a-z] matches one character from the range given in the bracket
-- read all files that match the glob pattern    
SELECT * FROM read_parquet('test/*.parquet');    

-- Read all parquet files from 2 specific folders    
SELECT * FROM read_parquet(['folder1/*.parquet','folder2/*.parquet']);
  • 查看 parquet 文件的元数据

文件路径 / 列名 / 列序 / 列类型 / 压缩算法(zstd / snappy / ...) / ...

D SELECT * FROM parquet_metadata("D:\Program-Data\DuckDB\datasources\tb_demo.parquet")
file_name                                         |row_group_id|row_group_num_rows|row_group_num_columns|row_group_bytes|column_id|file_offset|num_values|path_in_schema|type |stats_min|stats_max|stats_null_count|stats_distinct_count|stats_min_value|stats_max_value|compression|encodings                 |index_page_offset|dictionary_page_offset|data_page_offset|total_compressed_size|total_uncompressed_size|key_value_metadata|bloom_filter_offset|bloom_filter_length|min_is_exact|max_is_exact|row_group_compressed_bytes|geo_bbox|geo_types|
--------------------------------------------------+------------+------------------+---------------------+---------------+---------+-----------+----------+--------------+-----+---------+---------+----------------+--------------------+---------------+---------------+-----------+--------------------------+-----------------+----------------------+----------------+---------------------+-----------------------+------------------+-------------------+-------------------+------------+------------+--------------------------+--------+---------+
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|           0|                 4|                    4|            476|        0|          0|         4|col_0         |INT64|1        |13       |               0|                    |1              |13             |SNAPPY     |PLAIN, RLE, RLE_DICTIONARY|                 |                     4|              46|                  117|                    119|{}                |                   |                   |true        |true        |                         1|        |NULL     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|           0|                 4|                    4|            476|        1|          0|         4|col_1         |INT64|2        |14       |               0|                    |2              |14             |SNAPPY     |PLAIN, RLE, RLE_DICTIONARY|                 |                   121|             163|                  117|                    119|{}                |                   |                   |true        |true        |                         1|        |NULL     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|           0|                 4|                    4|            476|        2|          0|         4|col_2         |INT64|3        |15       |               0|                    |3              |15             |SNAPPY     |PLAIN, RLE, RLE_DICTIONARY|                 |                   238|             280|                  117|                    119|{}                |                   |                   |true        |true        |                         1|        |NULL     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|           0|                 4|                    4|            476|        3|          0|         4|col_3         |INT64|4        |16       |               0|                    |4              |16             |SNAPPY     |PLAIN, RLE, RLE_DICTIONARY|                 |                   355|             397|                  117|                    119|{}                |                   |                   |true        |true        |                         1|        |NULL     |
  • 查询 parquet 文件的数据结构(定义)
-- fetch the column names and column types    
D DESCRIBE SELECT * FROM "D:\Program-Data\DuckDB\datasources\tb_demo.parquet";    
column_name|column_type|null|key|default|extra|
-----------+-----------+----+---+-------+-----+
col_0      |BIGINT     |YES |   |       |     |
col_1      |BIGINT     |YES |   |       |     |
col_2      |BIGINT     |YES |   |       |     |
col_3      |BIGINT     |YES |   |       |     |


-- fetch the internal schema of a parquet file    
D SELECT * FROM parquet_schema("D:\Program-Data\DuckDB\datasources\tb_demo.parquet");   
file_name                                         |name  |type |type_length|repetition_type|num_children|converted_type|scale|precision|field_id|logical_type|duckdb_type|
--------------------------------------------------+------+-----+-----------+---------------+------------+--------------+-----+---------+--------+------------+-----------+
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|schema|     |           |REQUIRED       |           4|              |     |         |        |            |           |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|col_0 |INT64|           |OPTIONAL       |            |              |     |         |        |            |BIGINT     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|col_1 |INT64|           |OPTIONAL       |            |              |     |         |        |            |BIGINT     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|col_2 |INT64|           |OPTIONAL       |            |              |     |         |        |            |BIGINT     |
D:\Program-Data\DuckDB\datasources\tb_demo.parquet|col_3 |INT64|           |OPTIONAL       |            |              |     |         |        |            |BIGINT     |
  • 将 parquet 文件的数据插入本地表
-- insert the data from the parquet file in the table    
INSERT INTO people SELECT * FROM read_parquet('test.parquet');    
    
-- create a table directly from a parquet file    
CREATE TABLE people AS SELECT * FROM read_parquet('test.parquet');    
  
-- or  
COPY tbl FROM 'input.parquet' (FORMAT PARQUET);
  • 创建parquet文件视图
-- create a view over the parquet file    
CREATE VIEW people AS SELECT * FROM read_parquet('test.parquet');    
    
-- query the parquet file    
SELECT * FROM people;

(远程)网络与云存储

S3 Parquet Import

  • 推荐文献
  • 前提条件
  • 要从 S3 加载 Parquet 文件,需要 httpfs 扩展名。这可以通过SQL命令安装。这个程序只需要运行一次 INSTALL 命令:
INSTALL httpfs;

image

  • 要加载扩展以供使用,请使用SQL命令:
LOAD httpfs;

image

  • 凭据与配置

加载扩展后,设置凭证和S3区域读取数据:httpfs

-- 创建 SECRET
CREATE OR REPLACE SECRET s3_secret_qiniu ( -- or 持久化存储密钥: CREATE PERSISTENT SECRET s3_secret_qiniu (
    TYPE s3
    -- , PROVIDER config -- (可选配置项) 作用: 当遇到 s3: 协议的 http 文件时,默认使用此 secret
    , ENDPOINT 's3.cn-south-1.qiniucs.com' -- 's3.oss-cn-beijing.aliyuncs.com' (阿里云为例)
    , KEY_ID 'R534353545DrQp0ipYngKsey' -- 'AKIAIO3535355AMPLE'
    , SECRET '02xSD945454545gl4543535sD' -- 'wJalrXUtnF353535DENG/bPxRfiCYEXAMPLEKEY'
    
    -- , REGION 'cn-south-1' -- 如 'us-east-1' (可选配置项)
    -- , SCOPE 's3://{bucketName}' -- (可选配置项)
);

-- 查看 secret
SELECT * FROM duckdb_secrets();

-- 删除 secret
-- DROP SECRET s3_secret_qiniu; -- 或 删除持久化的密钥: DROP PERSISTENT SECRET s3_secret_qiniu;

:注:默认情况下,会将持久化的密码信息(未加密)写入 ~/.duckdb/stored_secrets 目录。要更改秘密目录,请执行

SET secret_directory = 'path/to/my_secrets_dir';
  • 查询远程对象存储中指定 parquet 文件的数据
-- 从s3查询 parquet 文件的数据
select * from read_parquet('s3://{bucketName}/dataset/tb_demo.parquet')

/**
col_0|col_1|col_2|col_3|
-----+-----+-----+-----+
    1|    2|    3|    4|
    5|    6|    7|    8|
    9|   10|   11|   12|
   13|   14|   15|   16|
**/

image

参数管理

  • 查看参数
D select name,value from duckdb_settings();
name                                       |value
-------------------------------------------+-----
Calendar                                   |grego
TimeZone                                   |Asia/
access_mode                                |autom
allocator_background_threads               |false
allocator_bulk_deallocation_flush_threshold|512.0
allocator_flush_threshold                  |128.0
allow_community_extensions                 |true 
allow_extensions_metadata_mismatch         |false
allow_persistent_secrets                   |true 
allow_unredacted_secrets                   |false
allow_unsigned_extensions                  |false
allowed_directories                        |[]   
allowed_paths                              |[]   
arrow_large_buffer_size                    |false
arrow_lossless_conversion                  |false
arrow_output_list_view                     |false
...
disabled_optimizers                        |     
duckdb_api                                 |jdbc 
dynamic_or_filter_threshold                |50   
enable_curl_server_cert_verification       |true 
...
  • 修改参数
D set threads=10;
  • 查看单个参数
D SELECT current_setting('threads') AS threads;
+---------+
| threads |
+---------+
| 10    |
+---------+

Pragma 扩展

  • PRAGMA 语句是DuckDBSQLite中采用的SQL扩展。
  • PRAGMA语句可以以与常规SQL语句类似的方式发出。
  • PRAGMA命令可能会改变数据库引擎的内部状态,并可能影响引擎的后续执行或行为

数据库信息

  • 数据库信息
-- 数据库信息
D PRAGMA database_list;
+------+------+---------------------------------------+
| seq  | name |                 file                  |
+------+------+---------------------------------------+
| 1080 | file | ...file.db                            |
+------+------+---------------------------------------+
或:
seq|name  |file|
---+------+----+
592|memory|    |
  • 查看数据库信息(大小)
-- 数据库信息(大小)
D CALL pragma_database_size();
+---------------+---------------+------------+--------------+-------------+-------------+----------+--------------+--------------+
| database_name | database_size | block_size | total_blocks | used_blocks | free_blocks | wal_size | memory_usage | memory_limit |
+---------------+---------------+------------+--------------+-------------+-------------+----------+--------------+--------------+
| file          | 512.0 KiB     | 262144     | 2            | 2           | 0           | 0 bytes  | 256.0 KiB    | 25.0 GiB     |
+---------------+---------------+------------+--------------+-------------+-------------+----------+--------------+--------------+

查看表信息

  • 查看所有表信息
-- 所有表信息
D PRAGMA show_tables;
+------+
| name |
+------+
| t1   |
| t2   |
| test |
+------+
  • 查看表详细信息
-- 表详细信息
D PRAGMA show_tables_expanded;
+----------+--------+------+--------------+--------------------+-----------+
| database | schema | name | column_names |    column_types    | temporary |
+----------+--------+------+--------------+--------------------+-----------+
| file     | main   | t1   | [a, b]       | [INTEGER, INTEGER] | false     |
| file     | main   | t2   | [a, b]       | [INTEGER, INTEGER] | false     |
| file     | main   | test | [i]          | [INTEGER]          | false     |
+----------+--------+------+--------------+--------------------+-----------+
  • 表结构
-- 表结构
D PRAGMA table_info('t1');
+-----+------+---------+---------+------------+-------+
| cid | name |  type   | notnull | dflt_value |  pk   |
+-----+------+---------+---------+------------+-------+
| 0   | a    | INTEGER | false   |            | false |
| 1   | b    | INTEGER | false   |            | false |
+-----+------+---------+---------+------------+-------+

查看函数信息

  • 查看函数信息
-- 函数信息
D PRAGMA functions;
D PRAGMA functions;
┌────────────┬─────────┬────────────────────────┬─────────┬─────────────┬──────────────┐
│    name    │  type   │       parameters       │ varargs │ return_type │ side_effects │
│  varchar   │ varchar │       varchar[]        │ varchar │   varchar   │   boolean    │
├────────────┼─────────┼────────────────────────┼─────────┼─────────────┼──────────────┤
│ !__postfix │ SCALAR  │ [INTEGER]              │         │ HUGEINT     │ false        │
│ !~~        │ SCALAR  │ [VARCHAR, VARCHAR]     │         │ BOOLEAN     │ false        │
│ !~~*       │ SCALAR  │ [VARCHAR, VARCHAR]     │         │ BOOLEAN     │ false        │
│ %          │ SCALAR  │ [SMALLINT, SMALLINT]   │         │ SMALLINT    │ false        │
│ %          │ SCALAR  │ [UBIGINT, UBIGINT]     │         │ UBIGINT     │ false        │
│ %          │ SCALAR  │ [UINTEGER, UINTEGER]   │         │ UINTEGER    │ false        │

版本与平台

-- 版本与平台
D PRAGMA version;
+-----------------+------------+
| library_version | source_id  |
+-----------------+------------+
| v0.10.1         | 4a89d97db8 |
+-----------------+------------+

D PRAGMA platform;
+---------------+
|   platform    |
+---------------+
| windows_amd64 |
+---------------+

其他(Profiling/Optimizer/StorageInfo)

-- Profiling
PRAGMA enable_profiling;
SET profiling_mode = 'detailed';
SET enable_profiling = 'query_tree';    logical query plan:
SET enable_profiling = 'query_tree_optimizer';    physical query plan:
PRAGMA disable_profiling;

-- Optimizer
PRAGMA disable_optimizer;
PRAGMA enable_optimizer;

-- Storage Info
D PRAGMA storage_info('t1');
+--------------+-------------+-----------+-------------+------------+--------------+-------+-------+--------------+------------------------------------------------------+-------------+------------+----------+--------------+--------------+
| row_group_id | column_name | column_id | column_path | segment_id | segment_type | start | count | compression  |  stats                                               | has_updates | persistent | block_id | block_offset | segment_info |
+--------------+-------------+-----------+-------------+------------+--------------+-------+-------+--------------+------------------------------------------------------+-------------+------------+----------+--------------+--------------+
| 0            | a           | 0         | [0]         | 0          | INTEGER      | 0     | 3     | Uncompressed | [Min: 1, Max: 3][Has Null: false, Has No Null: true] | false       | true       | 1        | 0            |              |
| 0            | a           | 0         | [0, 0]      | 0          | VALIDITY     | 0     | 3     | Constant     | [Has Null: false, Has No Null: true]                 | false       | true       | -1       | 0            |              |
| 0            | b           | 1         | [1]         | 0          | INTEGER      | 0     | 3     | Uncompressed | [Min: 1, Max: 3][Has Null: false, Has No Null: true] | false       | true       | 1        | 16           |              |
| 0            | b           | 1         | [1, 0]      | 0          | VALIDITY     | 0     | 3     | Constant     | [Has Null: false, Has No Null: true]                 | false       | true       | -1       | 0            |              |
+--------------+-------------+-----------+-------------+------------+--------------+-------+-------+--------------+------------------------------------------------------+-------------+------------+----------+--------------+--------------+

性能调优

  • DuckDB 性能调优主要涉及到参数、执行计划等。

尤其是观察 filter 和 projections 下推。
这里简单说明下使用 Explain 命令查看执行计划

查看执行计划

-- 查看执行计划
D explain select deptno,count(*) from big_emp group by deptno;

┌─────────────────────────────┐
│┌───────────────────────────┐│
││       Physical Plan                             ││
│└───────────────────────────┘│
└─────────────────────────────┘
┌───────────────────────────┐
│         PROJECTION                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│__internal_decompress_integ                           │
│     ral_integer(#0, 1)                           │
│             #1                            │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│   PERFECT_HASH_GROUP_BY                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│             #0                            │
│        count_star()                           │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         PROJECTION                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│           deptno                            │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         PROJECTION                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│__internal_compress_integra                           │
│     l_usmallint(#0, 1)                           │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         SEQ_SCAN                             │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│          big_emp                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│           deptno                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│        EC: 1000000                            │
└───────────────────────────┘


-- 关闭优化器后,再观察看下
D PRAGMA disable_optimizer;
D explain select deptno,count(*) from big_emp group by deptno;

┌─────────────────────────────┐
│┌───────────────────────────┐│
││       Physical Plan                            ││
│└───────────────────────────┘│
└─────────────────────────────┘
┌───────────────────────────┐
│       HASH_GROUP_BY                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│             #0                            │
│        count_star()                           │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         PROJECTION                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│           deptno                            │
└─────────────┬─────────────┘
┌─────────────┴─────────────┐
│         SEQ_SCAN                             │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│          big_emp                            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                 │
│        EC: 1000000                            │
└───────────────────────────┘

密钥管理

  • 推荐文献
  • 支持管理的密钥类型
密钥类型 服务 / 协议 扩展
azure Azure Blob 存储 azure
ducklake DuckLake ducklake
gcs Google Cloud Storage httpfs
http HTTP 和 HTTPS httpfs
huggingface Hugging Face httpfs
mysql MySQL mysql
postgres PostgreSQL postgres
r2 Cloudflare R2 httpfs
s3 AWS S3 httpfs

插件管理

别名:扩展管理

  • 推荐文献

查看插件

  • 获取扩展列表,请使用 duckdb_extensions 函数
SELECT 
	extension_name, installed, description
FROM duckdb_extensions();
扩展名称 已安装 描述
arrow Apache Arrow 和 DuckDB 之间的零拷贝数据集成
autocomplete 在 Shell 中添加自动补全支持

此列表将显示哪些扩展可用、哪些扩展已安装版本以及安装位置等信息。
此列表包含大多数(但并非所有)可用的核心扩展。有关完整列表,请参阅我们维护的核心扩展列表

image

内置扩展

  • DuckDB 的二进制分发版标准包含一些内置扩展。它们静态链接到二进制文件中,可以直接使用。

例如,要使用内置的 json 扩展来读取 JSON 文件

SELECT * FROM 'test.json';
  • 为了使 DuckDB 分发包轻量化,只有少数必需的扩展是内置的,具体取决于不同的分发版本。

哪个扩展在哪个平台上是内置的,已在核心扩展列表中说明。

image

安装更多扩展

  • 可以通过SQL命令安装DuckDB的扩展插件,这类插件程序一般只需要运行一次。
  • 要使非内置扩展在 DuckDB 中可用,需要执行两个步骤
  • 扩展安装是下载扩展二进制文件并验证其元数据的过程。

在安装过程中,DuckDB 会将下载的扩展和一些元数据存储在本地目录中。DuckDB 随后可以从该目录中按需加载扩展。这意味着安装只需进行一次。

  • 扩展加载是将二进制文件动态加载到 DuckDB 实例中的过程。

DuckDB 会在本地扩展目录中搜索已安装的扩展,然后加载它以使其功能可用。这意味着每次重新启动 DuckDB 时,所有已使用的扩展都需要(重新)加载。

  • 使 DuckDB 执行可安装扩展的安装和加载步骤有两种主要方法:显式方式和通过自动加载

显式 INSTALL 和 LOAD

  • 在 DuckDB 中,扩展也可以显式安装和加载。非自动加载和可自动加载的扩展都可以通过这种方式安装。要显式安装和加载扩展,DuckDB 提供了专用的 SQL 语句 LOAD 和 INSTALL。例如,要安装和加载 spatial 扩展,请运行
INSTALL spatial;
LOAD spatial;

使用这些语句,DuckDB 将确保 spatial 扩展已安装(如果已安装则忽略 INSTALL 语句),然后继续 LOAD spatial 扩展(如果已加载则再次忽略该语句)。

扩展存储库

  • 可以选定要安装扩展的存储库,方法是将 FROM repository 附加到 INSTALL / FORCE INSTALL 命令。此存储库可以是别名,例如 community,也可以是作为单引号字符串提供的直接 URL。
  • 安装/加载扩展后,可以使用 duckdb_extensions 函数获取更多信息。

自动加载扩展

  • 对于许多 DuckDB 的核心扩展,不需要显式加载和安装。DuckDB 包含一个自动加载机制,可以在核心扩展在查询中使用时立即安装和加载它们。例如,当运行
SELECT
    *
FROM 'https://raw.githubusercontent.com/duckdb/duckdb-web/main/data/weather.csv';
  • DuckDB 将自动安装并加载 httpfs 扩展。无需显式的 INSTALL 或 LOAD 语句。

  • 并非所有扩展都可以自动加载

这可能有多种原因:一些扩展会对正在运行的 DuckDB 实例进行多项更改,使得自动加载在技术上尚不可能。对于其他扩展,由于它们修改 DuckDB 行为的方式,更倾向于用户在使用前显式选择加入该扩展。
要查看哪些扩展可以自动加载,请查看核心扩展列表。

社区扩展

  • DuckDB 支持安装第三方社区扩展。
INSTALL avro FROM community;
  • 社区扩展由社区成员贡献,但它们在集中式存储库中构建、签名和分发。

更新扩展

  • 内置扩展由于其内置于 DuckDB 二进制文件的性质而与 DuckDB 版本绑定,而可安装的扩展可以且确实会接收更新。为确保所有当前安装的扩展都处于最新版本,请调用
UPDATE EXTENSIONS;
  • 有关扩展版本的更多详细信息,请参阅扩展版本控制页面。

开发扩展

  • 核心扩展使用的相同 API 也可用于开发扩展。这允许用户扩展 DuckDB 的功能,使其最适合其领域。用于创建扩展的模板可在 extension-template 存储库中找到。此模板还包含有关如何开始构建自己的扩展的一些文档。

使用扩展

  • 请参阅安装说明和高级安装方法页面。

Z FAQ for DuckDB

Q: DBeaver 连接 DuckDB

  • 数据库 - 新建数据库连接 - DuckDB - 下一步
    image

  • 路径(输入: :memory:) - 下一步

当然,也可输入持久化的duckdb数据库文件路径。

image

image

  • 下载 duckdb 驱动包

image

即安装完成:

image

  • 尝试使用
select version();
-- v1.4.3

select * from read_csv("D:\Program-Data\DuckDB\datasources\tb_student.csv")

image

tb_student.csv

id,name,birthdate,comment
1,jack,2005-07-01,""
2,jane,2004-09-28,""

Q: 使用 DuckLake 和 DuckDB 构建轻量级的 S3 数据湖?

此方案,未亲测。

  • 推荐文献

由 DuckDB 和 DuckLake 组成的轻量级数据湖方案,旨在解决传统数据湖(如Hadoop+Hive)元数据管理复杂、查询性能低及厂商锁定等问题。
该方案为中小规模数据湖场景提供了简单、高性能且无厂商锁定的替代选择。

什么是 DuckLake 和 DuckDB?

  • 在现代数据架构中,数据湖(Data Lake) 和 湖仓一体(Lakehouse) 已成为存储和管理大规模结构化与非结构化数据的核心方案。然而,传统的数据湖(如 Hadoop + Hive)往往存在元数据管理复杂、查询性能低、依赖特定厂商等问题。

  • DuckDB 是一个高性能的嵌入式分析数据库,支持 SQL 查询和向量化执行,特别适合本地和云环境下的数据分析。而 DuckLake 是一个基于 DuckDB 的轻量级表格式,它将元数据存储在 SQL 数据库(如 DuckDB)中,而实际数据则存储在开放格式(如 Parquet)的云存储(如 S3、GCS、Azure Blob Storage)上。

  • DuckLake 的核心优势:

  • ✅ ​​简单易用​​:所有元数据管理通过 SQL 完成,无需复杂配置。
  • ✅ ​​高性能​​:元数据操作极快,查询性能优异。
  • ✅ ​​开放标准​​:数据存储在 Parquet 格式,元数据可移植。
  • ✅ ​​ACID 事务支持​​:支持 schema 演进、时间旅行(Time Travel)等高级功能。

环境准备:安装 DuckDB 并加载扩展

  • 确保已安装 DuckDB(官方下载地址)。然后,在 DuckDB 中加载必要的扩展以支持云存储和 DuckLake:
-- 安装并加载 AWS S3 支持
INSTALL aws;
LOAD aws;

-- 安装 HTTP 文件系统支持(可选,用于远程数据访问)
INSTALL httpfs;
LOAD httpfs;

-- 安装 Parquet 支持(用于读取/写入 Parquet 文件)
INSTALL parquet;
LOAD parquet;

-- 安装 DuckLake 扩展
INSTALL ducklake;
LOAD ducklake;
  • 配置 AWS 凭证

DuckDB 支持从环境变量或直接加载 AWS 凭证。推荐使用环境变量方式(更安全):

# 在终端设置 AWS 凭证(Linux/macOS)
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_REGION="us-east-1"  # 替换为你的 S3 区域

或者在 DuckDB 中直接加载凭证:

-- 直接加载 AWS 凭证(不推荐生产环境使用)
CALL load_aws_credentials();

创建 DuckLake 目录并连接 S3

  • DuckLake 使用 目录(Catalog) 管理表元数据。

我们可以在 S3 上创建一个 DuckLake 目录:

-- 在 S3 上创建 DuckLake 目录
ATTACH 'ducklake:metadata.ducklake' (
  DATA_PATH 's3://your-bucket/your-prefix/'  -- 替换为你的 S3 路径
);
  • metadata.ducklake 是元数据文件名(DuckDB 会自动管理)。
  • DATA_PATH 指定 S3 存储路径,所有 Parquet 数据将存储在此目录下。

创建表、插入数据、更新和删除

(1) 创建表

-- 在 DuckLake 目录中创建表
CREATE TABLE IF NOT EXISTS metadata.customers (
    customer_id INTEGER,
    first_name STRING,
    last_name STRING,
    email STRING,
    city STRING,
    created_at TIMESTAMP
);

(2) 插入数据

-- 插入示例数据
INSERT INTO metadata.customers VALUES
  (1, 'Alice', 'Smith', 'alice@example.com', 'New York', CURRENT_TIMESTAMP),
  (2, 'Bob', 'Johnson', 'bob@example.com', 'San Francisco', CURRENT_TIMESTAMP);

(3) 更新数据

-- 更新 Bob 的城市
UPDATE metadata.customers
SET city = 'Los Angeles'
WHERE customer_id = 2;

(4) 删除数据

-- 删除 Alice 的记录
DELETE FROM metadata.customers WHERE customer_id = 1;

(5) 查询数据

-- 查询所有客户
SELECT * FROM metadata.customers;

高级功能:ACID 事务 & 时间旅行

  • DuckLake 支持 ACID 事务,确保数据一致性。例如:
-- 开启事务
BEGIN TRANSACTION;

-- 插入新数据
INSERT INTO metadata.customers VALUES
  (3, 'Charlie', 'Brown', 'charlie@example.com', 'Chicago', CURRENT_TIMESTAMP);

-- 更新数据
UPDATE metadata.customers
SET city = 'Seattle'
WHERE customer_id = 2;

-- 提交事务
COMMIT;
  • 时间旅行(Time Travel) 允许查询历史数据版本:
-- 查询 1 小时前的数据(假设 DuckLake 支持时间旅行)
SELECT * FROM metadata.customers AT TIMESTAMP '2025-05-28 12:00:00';

注意:时间旅行功能可能需要额外配置,具体取决于 DuckLake 版本。

小结:为什么选择 DuckLake + DuckDB?

特性 DuckLake + DuckDB 传统数据湖 (Hive/Hadoop)
元数据管理 SQL 管理,简单高效 依赖 Hive Metastore, 复杂
查询性能 向量执行,极快 依赖 MapReduce/Spark, 较慢
数据格式 Parquet(开放标准) Parquet/ORC(但依赖特定工具)
ACID 支持 完整支持 部分支持(如 Delta Lake)
厂商锁定 无锁定,纯开源 可能依赖 Hadoop/Spark 生态
  • DuckLake + DuckDB 提供了一种 轻量级、高性能、开源 的数据湖解决方案,特别适合:
  • 本地开发(嵌入式 DuckDB)
  • 云原生分析(S3/GCS 存储)
  • 需要 ACID 事务的场景

Y 推荐文献

  • DuckDB
  • Apache Parquet

CASE : DuckDB 数据库 On Parquet
CASE : 二维数组保存为 parquet

  • Apache Doris
  • 其他文献

注:这是一次思想实验,是与 DuckLake 数据仓库相反的创新路径

X 参考文献

posted @ 2026-01-03 23:24  千千寰宇  阅读(46)  评论(0)    收藏  举报