Polars 在条件连接 + group_by/agg 上下文中比 DuckDB 慢很多

问题描述 投票:0回答:2

对于以下示例,它涉及自条件连接和后续的 groupby/aggregate 操作。事实证明,在这种情况下,

DuckDB
的性能比
Polars
好得多(在 32 核机器上约为 10 倍)。

我的问题是:

  1. 导致
    DuckDB
    缓慢(相对于
    Polars
    )的潜在原因可能是什么?
  2. 我是否错过了在
    Polars
    中做同样事情的其他更快的方法?
import time

import duckdb
import numpy as np
import polars as pl

## example dataframe
rng = np.random.default_rng(1)

nrows = 5_000_000
df = pl.DataFrame(
    dict(
        id=rng.integers(1, 1_000, nrows),
        id2=rng.integers(1, 10, nrows),
        id3=rng.integers(1, 500, nrows),
        value=rng.normal(0, 1, nrows),
    )
)

## polars
start = time.perf_counter()
res = (
    df.lazy()
    .join(df.lazy(), on=["id", "id2"], how="left")
    .filter(
        (pl.col("id3") > pl.col("id3_right"))
        & (pl.col("id3") - pl.col("id3_right") < 30)
    )
    .group_by(["id2", "id3", "id3_right"])
    .agg(pl.corr("value", "value_right"))
    .collect(streaming=True)
)
time.perf_counter() - start
# 120.93155245436355

## duckdb
start = time.perf_counter()
res2 = (
    duckdb.sql(
        """
        SELECT df.*, df2.id3 as id3_right, df2.value as value_right
        FROM df JOIN df as df2
        ON (df.id = df2.id
        AND df.id2 = df2.id2
        AND df.id3 > df2.id3
        AND df.id3 - df2.id3 < 30)
        """
    )
    .aggregate(
        "id2, id3, id3_right, corr(value, value_right) as value",
        "id2, id3, id3_right",
    )
    .pl()
)
time.perf_counter() - start
# 18.472263277042657
python python-polars duckdb
2个回答
4
投票

编辑:2023-7-18

最新发布的 Polars 已将差异从 15 倍缩小到 2 倍。

polars v0.18.2  1125
polars v0.18.3  140
duckdb 0.8.2-dev1   75

原答案

流媒体引擎

流媒体 API 尚未优化。 Polars 是一个比 DuckDB 更年轻的项目,我们没有那么多付费开发人员参与该项目。

所以请给我们时间。下一个版本

0.18.3
将发布 PR,可以使流媒体 groupby 速度提高 3.5 倍以上 https://github.com/pola-rs/polars/pull/9346.

这只是表明我们在流媒体引擎上还有多少空间。我们仍然需要对流连接进行同样的优化。

简而言之。我们的流媒体引擎正处于 alpha 阶段。该工作正在进行中。

算法不同

另外,duckdb 查询也可能在底层使用非等值连接,而我们在 Polar 中还没有,所以这个查询对于 Polar 来说可能不是最佳的。


3
投票

虽然 DuckDB 确实有几个非等值连接,但规划器当前假设所有等式谓词比不等式更具选择性,并且仅在此处生成哈希连接:

D EXPLAIN SELECT id2, id3, id3_right, corr(value, value_right) as value
> FROM (
>     SELECT df.*, df2.id3 as id3_right, df2.value as value_right
>     FROM df JOIN df as df2
>         ON (df.id = df2.id
>         AND df.id2 = df2.id2
>         AND df.id3 > df2.id3
>         AND df.id3 - df2.id3 < 30)
>     ) tbl
> GROUP BY ALL
> ;

┌─────────────────────────────┐
│┌───────────────────────────┐│
││       Physical Plan       ││
│└───────────────────────────┘│
└─────────────────────────────┘
┌───────────────────────────┐                             
│       HASH_GROUP_BY       │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│             #0            │                             
│             #1            │                             
│             #2            │                             
│        corr(#3, #4)       │                             
└─────────────┬─────────────┘                                                          
┌─────────────┴─────────────┐                             
│         PROJECTION        │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│            id2            │                             
│            id3            │                             
│         id3_right         │                             
│           value           │                             
│        value_right        │                             
└─────────────┬─────────────┘                                                          
┌─────────────┴─────────────┐                             
│         PROJECTION        │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│             #1            │                             
│             #2            │                             
│             #3            │                             
│             #4            │                             
│             #5            │                             
└─────────────┬─────────────┘                                                          
┌─────────────┴─────────────┐                             
│           FILTER          │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│     ((id3 - id3) < 30)    │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│      EC: 24727992087      │                             
└─────────────┬─────────────┘                                                          
┌─────────────┴─────────────┐                             
│         HASH_JOIN         │                             
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │                             
│           INNER           │                             
│          id = id          │                             
│         id2 = id2         ├──────────────┐              
│         id3 > id3         │              │              
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │              │              
│      EC: 24727992087      │              │              
│     Cost: 24727992087     │              │              
└─────────────┬─────────────┘              │                                           
┌─────────────┴─────────────┐┌─────────────┴─────────────┐
│         SEQ_SCAN          ││         SEQ_SCAN          │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│             df            ││             df            │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│             id            ││             id            │
│            id2            ││            id2            │
│            id3            ││            id3            │
│           value           ││           value           │
│   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   ││   ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─   │
│        EC: 5000000        ││        EC: 5000000        │
└───────────────────────────┘└───────────────────────────┘    

我们计划在未来的版本中解决这个问题。

另请注意,IEJoin 算法需要两个不等式,而查询只有一个。单个不等式可以由 PieceWiseMergeJoin 运算符处理,但 PWMJ 目前不处理简单的等式(只需扩展逻辑即可正确处理

NULL
)。

© www.soinside.com 2019 - 2024. All rights reserved.