0 序
- DuckDB 是近期非常火的一款 AP 数据库,其独特的定位很有趣。甚至有数据库产品考虑将其纳入进来,作为分析能力的扩展。
考虑到项目中一个数据处理场景,就此调研一二。
- DuckDB 的爆火,也给所有盲目追逐“大数据”的技术人敲响了警钟:
- DuckDB 是一场复古的叛逆,也是一场属于单机的复仇。它告诉我们:在算力爆炸的今天,小,即是快;简,即是强。
- 我们被云厂商和大数据鼓吹者洗脑太久了,总觉得不搞个集群、不弄个微服务,架构就不够“高大上”。但技术的本质是解决问题,而不是制造复杂度。
- DuckDB := 数据分析领域的 SQLLite (列式存储)
适合分析 / 列压缩 / 每一列在磁盘和内存中以分块数组的形式存储
内存局部性优化 / 读取查询速度更快
物联网/移动端/个人PC端/中小企业(TB级以下数据场景,尤其是数百GB级以下)
1 概述:DuckDB
DuckDB 介绍
产品定位与产生背景
- DuckDB 是一个诞生于2018年,开源免费的、面向嵌入式场景的、列式存储的、In-Process 的 OLAP 数据库。
- 产生背景:2019 年, SIGMOD 有一篇 Demo 论文介绍 DuckDB:an embedded analytical database。随着单机内存的变大,大部分 OLTP 数据库都能在内存中放得下,而很多 OLAP 也有在单机就能搞定的趋势。单台服务器的内存很容易达到 TB,加上 SSD,搞个几十甚至上百 TB 很容易。DuckDB 就是为了填补这个空白而生的。
- 定位:一款单机版/嵌入式分析型数据库 (数据分析领域的 SQLLite,但其底层是列式存储)
- Slogan : DuckDB 是一个分析式的 SQL 数据库管理系统
- https://github.com/duckdb/duckdb
- csv / excel / json / parquet 等本地文件格式
- http(s) / s3 等远程文件格式
开源情况
- DuckDB 采用 较为宽松的 MIT 协议开源。
其作为荷兰 CWI 数据库组的一个项目,学术气息比较浓厚,项目的组织很有教科书的感觉,架构很清晰,所以非常适合阅读学习。
从 OSS Insight 拉个一个 Star 数对比,可以看到 DuckDB 发展非常迅速。
https://ossinsight.io/analyze/duckdb/duckdb#overview
DuckDB 主要特点
- DuckDB是一个免费的、开源的、面向单机的(嵌入式/非分布式的)数据库管理系统,专为【数据分析】和【在线分析处理】而设计。
这意味着以下几点:
- 它是免费的开源软件,因此任何人都可以使用和修改代码。
- 它是面向单机的/嵌入式的。
这意味着DBMS(数据库管理系统)与使用它的应用程序在同一进程中运行。这使得它快速且易于使用。
- 它针对【数据分析】和【OLAP】(在线分析处理)进行了优化,而不仅仅是像典型数据库那样只针对事务数据。
这意味着数据【按列】而不是【按行】组织以优化聚合和分析。
- 它支持【标准SQL】,因此可以在数据上运行查询、聚合、连接和其他SQL函数。
- 它在【进程中运行】,即在应用程序本身内运行,而不是作为单独的进程运行。这消除了进程间通信的开销。
与SQLite一样,它是一个简单的、基于文件的数据库。因此,不需要单独安装服务器。只需将库包含在应用程序中即可。
主要优点
- 易于安装、部署和使用。没有需要配置的服务器,可在应用程序内部嵌入运行,这使得它易于集成到不同编程语言环境中。
- 尽管它很简单,但DuckDB具有丰富的功能集。它支持完整的SQL标准、事务、二级索引,并且与流行的数据分析编程语言如 Python 和 R 集成良好。
- 免费的,任何人都可以使用和修改它,这降低了开发人员和数据分析师采用它的门槛。
- 兼容性很好,几乎无依赖性,甚至可在浏览器中运行。
- 具有灵活的扩展机制,这对于直接从 CSV、JSON、Parquet、MySQL 或直接从 S3 读取数据特别重要,能够大大提高开发人员的体验。
- 可提供数据超出内存限制但小于磁盘容量规模下的工作负载,这样分析工作可通过 "便宜"的硬件来完成。
2 安装部署篇
- DuckDB 安装部署过程相当简单,且支持多种部署模式:
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 查询。
- 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>
复制代码- 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
- duckdb_cli-windows-amd64.zip
- duckdb_cli-windows-arm64.zip
D:\Program\DuckDB-CLI\duckdb.exe
3 工作原理与架构篇
数据库架构
- 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 专章
- 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']);
复制代码 WildcardDescription*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']);
复制代码文件路径 / 列名 / 列序 / 列类型 / 压缩算法(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 |
复制代码- -- 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 |
复制代码- -- 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);
复制代码- -- 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 命令:
加载扩展后,设置凭证和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|
- **/
复制代码
参数管理
- 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 SELECT current_setting('threads') AS threads;
- +---------+
- | threads |
- +---------+
- | 10 |
- +---------+
复制代码 Pragma 扩展
- PRAGMA 语句是DuckDB从SQLite中采用的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 │
- └───────────────────────────┘
复制代码 密钥管理
密钥类型服务 / 协议扩展azureAzure Blob 存储azureducklakeDuckLakeducklakegcsGoogle Cloud StoragehttpfshttpHTTP 和 HTTPShttpfshuggingfaceHugging FacehttpfsmysqlMySQLmysqlpostgresPostgreSQLpostgresr2Cloudflare R2httpfss3AWS S3httpfs插件管理
别名:扩展管理
查看插件
- 获取扩展列表,请使用 duckdb_extensions 函数
- SELECT
- extension_name, installed, description
- FROM duckdb_extensions();
复制代码 扩展名称已安装描述arrow否Apache Arrow 和 DuckDB 之间的零拷贝数据集成autocomplete否在 Shell 中添加自动补全支持………此列表将显示哪些扩展可用、哪些扩展已安装、版本以及安装位置等信息。
此列表包含大多数(但并非所有)可用的核心扩展。有关完整列表,请参阅我们维护的核心扩展列表。
内置扩展
- DuckDB 的二进制分发版标准包含一些内置扩展。它们静态链接到二进制文件中,可以直接使用。
例如,要使用内置的 json 扩展来读取 JSON 文件
- SELECT * FROM 'test.json';
复制代码
- 为了使 DuckDB 分发包轻量化,只有少数必需的扩展是内置的,具体取决于不同的分发版本。
哪个扩展在哪个平台上是内置的,已在核心扩展列表中说明。
安装更多扩展
- 可以通过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 行为的方式,更倾向于用户在使用前显式选择加入该扩展。
要查看哪些扩展可以自动加载,请查看核心扩展列表。
社区扩展
- 例如,您可以通过以下方式安装 avro 社区扩展:
- INSTALL avro FROM community;
复制代码
- 社区扩展由社区成员贡献,但它们在集中式存储库中构建、签名和分发。
更新扩展
- 内置扩展由于其内置于 DuckDB 二进制文件的性质而与 DuckDB 版本绑定,而可安装的扩展可以且确实会接收更新。为确保所有当前安装的扩展都处于最新版本,请调用
- 有关扩展版本的更多详细信息,请参阅扩展版本控制页面。
开发扩展
- 核心扩展使用的相同 API 也可用于开发扩展。这允许用户扩展 DuckDB 的功能,使其最适合其领域。用于创建扩展的模板可在 extension-template 存储库中找到。此模板还包含有关如何开始构建自己的扩展的一些文档。
使用扩展
Z FAQ for DuckDB
Q: DBeaver 连接 DuckDB
- 数据库 - 新建数据库连接 - DuckDB - 下一步
- 路径(输入: :memory
- 下一步
当然,也可输入持久化的duckdb数据库文件路径。
即安装完成:
- select version();
- -- v1.4.3
- select * from read_csv("D:\Program-Data\DuckDB\datasources\tb_student.csv")
复制代码
tb_student.csv
- id,name,birthdate,comment
- 1,jack,2005-07-01,""
- 2,jane,2004-09-28,""
复制代码 Q: 使用 DuckLake 和 DuckDB 构建轻量级的 S3 数据湖?
此方案,未亲测。
- 使用 DuckLake 和 DuckDB 构建 S3 数据湖实战指南 - CSDN
由 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;
复制代码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 推荐文献
- 安装包 https://duckdb.org/install/
- Guide https://duckdb.org/docs/stable/guides/overview
- SQL 介绍 https://duckdb.org/docs/stable/sql/introduction
- Github https://github.com/duckdb/duckdb
- [文件格式/数据存储] Apache Parquet:开源、高效的列式存储文件格式协议 - 博客园/千千寰宇
CASE : DuckDB 数据库 On Parquet
CASE : 二维数组保存为 parquet
- 别再被“大数据”忽悠了:DuckDB,一场属于单机的复仇 - Weixin 2025.12
- 数据Infra:基于 DuckDB 设计的分布式数据平台 - Weixin/DuckNest
注:这是一次思想实验,是与 DuckLake 数据仓库相反的创新路径
- 【R数据库】duckdb/duckplyr包:整洁操作数据库 - Weixin
X 参考文献
- 1 分钟安装 DuckDB - 腾讯云 2024.11.21
- 嵌入式分析型数据库DuckDB - Zhihu 2025.1.27
- DuckDB 读写远程s3, oss, http Parquet 文件 - modb.pro 2024.1.25
本文作者: 千千寰宇
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |