duckdb
duckdb 的限制
- 可以多线程并发读, 但不能多线程并发写数据库.
duckdb 的作用
- 数据交换格式, 尤其适合于用于较大的数据传输, 比csv格式更好, 有主外键约束, 有非空约束, 每列都有强数据类型, 避免出现脏数据, 列式数据库文件压缩效果好
- 数据处理引擎, 可以读写csv/json/parquet文件, 甚至支持RDBMS读写, 然后利用duckdb强大的SQL特性, 进行数据分析和处理.
- 数据探索工具, 可以非常容易集成到Jupyter Notebook中, 可以从Python DataFrame对象读取, 然后利用强大的SQL特性, 进行数据分析. 也可以将sql的结果回写到 DataFrame, 可以同时获得SQL和DataFrame的数据探索的优势.
dataframe to SQL
Narwhals 开源库, 可以将data frame 转成sql https://narwhals-dev.github.io/narwhals/generating_sql/
将data frame转成sql仅仅是 Narwhals 的一个功能, 它最重要的功能是: Python 世界有很多个 data frame的实现(pandas/polars/cuDF/Modin), 它们虽然功能类似, 但具备不同的 API, 我们可以使用 Narwhals 统一的接口对接不同的data frame实现.
# ==================================
# Pandas 写法
# ==================================
def process_pandas(df):
return df[df["age"] > 21].assign(is_adult=True)
# ==================================
# Polars 写法
# ==================================
import polars as pl
def process_polars(df):
return df.filter(pl.col("age") > 21).with_columns(is_adult=pl.lit(True))
# ==================================
# 使用 Narwhals 的写法
# ==================================
import narwhals as nw
# 使用装饰器自动转换和还原数据类型
@nw.narwhalify
def process_data(df):
# 此时 df 自动变成了 Narwhals 的通用 DataFrame 对象
return df.filter(nw.col("age") > 21).with_columns(is_adult=True)
# 使用 Narwhals 的写法可以同时对接 pandas和polars dataframe
import pandas as pd
import polars as pl
# 测试数据
df_pd = pd.DataFrame({"age": [18, 25, 30]})
df_pl = pl.DataFrame({"age": [18, 25, 30]})
# 同样的函数,直接处理不同的输入
result_pd = process_data(df_pd) # 返回标准 pandas DataFrame
result_pl = process_data(df_pl) # 返回标准 Polars DataFrame
print(type(result_pd)) # <class 'pandas.core.frame.DataFrame'>
print(type(result_pl)) # <class 'polars.dataframe.frame.DataFrame'>
duckdb 读取 DataFrame 的示例
import duckdb
import pandas as pd
# Create a DataFrame, in this case using Pandas
my_df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
# Query it directly with SQL - no explicit conversion needed
result = duckdb.sql("SELECT * FROM my_df WHERE a > 1")
duckdb 读写 pandas 示例
import pandas as pd
import duckdb
mydf = pd.DataFrame({'a' : [1, 2, 3]})
print(duckdb.query("SELECT sum(a) FROM mydf").to_df())
将 duckdb 转成 DataFrame 并可视化
import duckdb
import polars as pl
import plotly.express as px
# Use SQL to load data and apply a complex aggregation
regional_summary = duckdb.query("""
SELECT
region,
SUM(sales) as total_sales,
COUNT(DISTINCT customer_id) as customer_count,
SUM(sales) / COUNT(DISTINCT customer_id) as sales_per_customer
FROM read_csv('sales_data*.csv')
WHERE sale_date >= '2024-01-01'
GROUP BY region
ORDER BY total_sales DESC
""").pl()
# Use summarised data in Polars for visualization
fig = px.bar(
regional_summary,
x="region",
y="sales_per_customer",
)
fig.show()
参考
https://endjin.com/blog/2025/04/duckdb-in-depth-how-it-works-what-makes-it-fast
https://endjin.com/blog/2025/04/duckdb-in-practice-enterprise-integration-architectural-patterns
https://www.timestored.com/data/duckdb/
https://github.com/davidgasquez/awesome-duckdb
建构数仓项目完整架构体系
https://dlthub.com/blog/dlt-motherduck-demo
https://datawise.dev/a-portable-data-stack-with-dagster-docker-duckdb-dbt-and-superset
参考博文1中给出了一个基于 dlt 和 dbt 和 duckdb 的数仓架构:



浙公网安备 33010602011771号