duckdb

duckdb 的限制

  1. 可以多线程并发读, 但不能多线程并发写数据库.

duckdb 的作用

  1. 数据交换格式, 尤其适合于用于较大的数据传输, 比csv格式更好, 有主外键约束, 有非空约束, 每列都有强数据类型, 避免出现脏数据, 列式数据库文件压缩效果好
  2. 数据处理引擎, 可以读写csv/json/parquet文件, 甚至支持RDBMS读写, 然后利用duckdb强大的SQL特性, 进行数据分析和处理.
  3. 数据探索工具, 可以非常容易集成到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 的数仓架构:
图片

图片

posted @ 2025-05-31 10:34  harrychinese  阅读(363)  评论(0)    收藏  举报