跳转至

DuckDB 嵌入式分析数据库

一句话概述:DuckDB 是嵌入式分析型数据库,像SQLite一样零配置开箱即用,但专门为分析查询优化,能直接查询CSV/Parquet/JSON文件。

核心知识点表

概念白话解释
嵌入式不需要安装服务器,直接在你的Python/R程序里运行
列式存储数据按列存储,分析查询(SUM/AVG/COUNT)极快
向量化执行一次处理一批数据而不是一条,像批量发快递而不是一件件寄
OLAP联机分析处理,适合"统计分析"而不是"增删改查"
DuckLakeDuckDB的湖仓格式,元数据存数据库,数据存文件
Extension扩展系统,通过插件添加新功能(空间查询、HTTP读取等)

版本信息(2026年5月)

  • 最新版本:DuckDB 1.5.1
  • LTS版本:1.4.4(长期支持,每隔一个版本一个LTS)
  • 亮点:AES-256加密、Iceberg写入、DuckLake 1.0

安装配置

# Python安装(最常用)
pip install duckdb  # 就这一行,不需要装服务器

# CLI安装(命令行交互)
# macOS
brew install duckdb
# Ubuntu
wget https://github.com/duckdb/duckdb/releases/latest/download/duckdb_cli-linux-amd64.zip
unzip duckdb_cli-linux-amd64.zip
sudo mv duckdb /usr/local/bin/

# 验证
python -c "import duckdb; print(duckdb.__version__)"
duckdb --version  # CLI版本

基本使用

Python API

import duckdb  # 导入DuckDB

# 创建内存数据库(最简单)
con = duckdb.connect()  # 内存模式,关闭即丢失

# 创建持久化数据库
con = duckdb.connect("my_analysis.db")  # 数据保存到文件

# 直接运行SQL
result = con.sql("SELECT 42 AS answer")  # 执行SQL
print(result)  # 显示结果

# 关闭连接
con.close()

直接查询文件(最强特性)

import duckdb

# 直接查询CSV文件,不需要先导入!
result = duckdb.sql("""
    SELECT
        city,
        COUNT(*) AS user_count,
        AVG(age) AS avg_age
    FROM 'users.csv'          -- 直接写文件路径当表名
    GROUP BY city
    ORDER BY user_count DESC
""")
print(result)

# 查询Parquet文件
duckdb.sql("SELECT * FROM 'data/*.parquet'")  # 支持通配符,读取所有parquet文件

# 查询JSON文件
duckdb.sql("SELECT * FROM read_json_auto('events.json')")

# 查询Excel文件
duckdb.sql("""
    INSTALL spatial;  -- 安装扩展
    LOAD spatial;
    SELECT * FROM st_read('data.xlsx')
""")

# 查询远程文件(HTTP/S3)
duckdb.sql("""
    SELECT * FROM 'https://example.com/data.csv'
    LIMIT 10
""")

# 查询S3上的Parquet
duckdb.sql("""
    SELECT * FROM read_parquet('s3://bucket/path/data.parquet')
""")

与pandas/Polars互操作

import duckdb
import pandas as pd
import polars as pl

# pandas DataFrame直接当SQL表用
pandas_df = pd.DataFrame({
    "name": ["Alice", "Bob", "Charlie"],
    "score": [95, 87, 92],
})

# 直接在SQL中引用pandas变量名!
result = duckdb.sql("""
    SELECT name, score
    FROM pandas_df              -- 直接用Python变量名
    WHERE score > 90
    ORDER BY score DESC
""")

# 结果转pandas
pandas_result = result.df()  # 转pandas DataFrame

# 结果转Polars
polars_result = result.pl()  # 转Polars DataFrame

# Polars DataFrame也能直接查询
polars_df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
duckdb.sql("SELECT * FROM polars_df WHERE x > 1")

创建表和导入数据

import duckdb

con = duckdb.connect("warehouse.db")

# 从CSV创建表
con.sql("""
    CREATE TABLE users AS
    SELECT * FROM read_csv_auto('users.csv')  -- 自动推断类型
""")

# 从Parquet创建表
con.sql("""
    CREATE TABLE events AS
    SELECT * FROM 'events.parquet'
""")

# 手动建表
con.sql("""
    CREATE TABLE products (
        id INTEGER PRIMARY KEY,   -- 主键
        name VARCHAR NOT NULL,    -- 产品名
        price DECIMAL(10, 2),     -- 价格,10位数字2位小数
        category VARCHAR,         -- 分类
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP  -- 创建时间
    )
""")

# 插入数据
con.sql("""
    INSERT INTO products VALUES
    (1, 'Python入门', 59.90, '图书', CURRENT_TIMESTAMP),
    (2, '机械键盘', 299.00, '外设', CURRENT_TIMESTAMP)
""")

高级用法

窗口函数

duckdb.sql("""
    SELECT
        name,
        department,
        salary,
        -- 部门内薪资排名
        RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
        -- 部门平均薪资
        AVG(salary) OVER (PARTITION BY department) AS dept_avg,
        -- 与上一个人的薪资差
        salary - LAG(salary) OVER (ORDER BY salary) AS salary_diff
    FROM 'employees.csv'
""")

PIVOT/UNPIVOT(行列转换)

# 行转列
duckdb.sql("""
    PIVOT (SELECT city, quarter, sales FROM sales_data)
    ON quarter
    USING SUM(sales)  -- 每个季度的销售额变成单独的列
""")

# 列转行
duckdb.sql("""
    UNPIVOT sales_wide
    ON q1, q2, q3, q4   -- 这些列转成行
    INTO NAME quarter VALUE sales  -- 新列名
""")

导出数据

# 导出为Parquet
duckdb.sql("""
    COPY (SELECT * FROM users WHERE active = true)
    TO 'active_users.parquet' (FORMAT PARQUET)
""")

# 导出为CSV
duckdb.sql("""
    COPY users TO 'users_export.csv' (HEADER, DELIMITER ',')
""")

# 分区导出
duckdb.sql("""
    COPY orders TO 'output' (FORMAT PARQUET, PARTITION_BY (year, month))
""")

扩展系统

# 安装并使用扩展
duckdb.sql("INSTALL httpfs;")   # HTTP/S3文件系统
duckdb.sql("LOAD httpfs;")

duckdb.sql("INSTALL json;")     # JSON处理
duckdb.sql("INSTALL spatial;")  # 空间数据
duckdb.sql("INSTALL iceberg;")  # Apache Iceberg
duckdb.sql("INSTALL fts;")      # 全文搜索

# 使用全文搜索
duckdb.sql("""
    INSTALL fts; LOAD fts;
    -- 创建全文索引
    PRAGMA create_fts_index('docs', 'id', 'content');
    -- 全文搜索
    SELECT * FROM fts_main_docs.search_and_rank('机器学习');
""")

CLI交互模式

# 启动CLI
duckdb my_data.db  # 打开/创建数据库

# 常用命令
.tables              # 列出所有表
.schema users        # 查看表结构
.mode markdown       # 输出格式改为Markdown表格
.timer on            # 显示查询耗时
.maxrows 20          # 最多显示20行
.import data.csv tbl # 导入CSV到表
.quit                # 退出

常见报错与解决

报错信息原因解决方案
IOException: file not found文件路径错误检查路径,用绝对路径
Catalog Error: Table not found表名写错或没创建.tables查看已有表
Conversion Error数据类型转换失败TRY_CAST()代替CAST()
Out of Memory数据太大SET memory_limit='4GB'增大内存
Permission denied数据库文件被锁确保没有其他进程在用同一个db文件
Extension not found扩展没安装INSTALL extension_name; LOAD extension_name;

速查表

-- ===== 文件查询 =====
SELECT * FROM 'file.csv';                    -- 查CSV
SELECT * FROM 'file.parquet';                -- 查Parquet
SELECT * FROM read_json_auto('file.json');   -- 查JSON
SELECT * FROM 'dir/*.parquet';               -- 通配符查多文件

-- ===== 常用函数 =====
-- 聚合:COUNT, SUM, AVG, MIN, MAX, MEDIAN, MODE
-- 字符串:LOWER, UPPER, TRIM, CONCAT, LENGTH, REGEXP_MATCHES
-- 日期:CURRENT_DATE, DATE_PART, DATE_TRUNC, AGE
-- 条件:CASE WHEN, COALESCE, NULLIF, IIF
-- 列表:LIST, UNNEST, LIST_AGGREGATE

-- ===== 导出 =====
COPY tbl TO 'out.parquet' (FORMAT PARQUET);
COPY tbl TO 'out.csv' (HEADER, DELIMITER ',');

-- ===== 配置 =====
SET threads = 4;           -- 线程数
SET memory_limit = '4GB';  -- 内存限制

-- ===== Python速查 =====
-- duckdb.sql("SQL")         执行SQL
-- result.df()               转pandas
-- result.pl()               转Polars
-- result.fetchall()         获取所有行
-- result.show()             打印结果

同类工具对比

特性DuckDBSQLitePolarsClickHouse
类型OLAP(分析)OLTP(事务)DataFrame库OLAP服务器
安装零配置零配置pip install需要服务器
查询语言SQLSQLPython APISQL
直接查文件支持不支持支持有限支持
并发写入单写多读单写单读N/A多写多读
适合场景本地分析、ETL应用内嵌数据库高性能数据处理大规模实时分析

面试建议:DuckDB是"分析领域的SQLite",零配置就能查询各种文件格式。重点记住:1)列式存储 vs 行式存储的区别;2)OLAP vs OLTP的区别;3)DuckDB能直接查CSV/Parquet不需要导入是最大卖点。