对内存DataFrame调用row_number() over (),行号是否按出现顺序生成?
问题:DuckDB处理pandas/Polars DataFrame时,无排序的row_number()是否会保留原行顺序?
核心结论
不要依赖row_number() over ()这种无排序规则的窗口函数来保证原DataFrame的行顺序。尽管你给出的测试案例结果符合预期,但这属于DuckDB的实现细节,而非官方承诺的稳定语义,未来版本或不同场景下可能发生变化。
测试场景验证
你提供的测试代码确实显示行号与原DataFrame的行顺序完全匹配:
In [11]: df = pl.DataFrame({'a': range(1, 1_280_000)}); duckdb.sql('select *, row_number() over () as index from df qualify a != index').pl() Out[11]: shape: (0, 2) ┌─────┬───────┐ │ a ┆ index │ │ --- ┆ --- │ │ i64 ┆ i64 │ ╞═════╪═══════╡ └─────┴───────┘
该结果仅说明在当前测试场景下,row_number()的生成顺序与原DataFrame行序一致,但不具备普遍可靠性。
为什么不能依赖这种行为?
- 从SQL标准来看,未指定ORDER BY的窗口函数不保证行的处理顺序。
row_number() over ()既没有分区规则也没有排序规则,数据库可根据执行计划(如并行读取、缓存策略等)自由调整行的处理顺序。 - DuckDB对外部DataFrame的读取逻辑可能随版本迭代优化,比如引入更高效的并行处理机制,这可能打破当前的行序匹配情况。
可靠的替代方案
如果需要严格保留原DataFrame的行顺序并生成行号,推荐以下两种方式:
- 在原DataFrame中预先添加显式的索引列,再传入DuckDB:
# Polars示例 df = pl.DataFrame({'a': range(1, 1_280_000)}).with_row_index('original_order') result = duckdb.sql('select *, row_number() over (order by original_order) as index from df') - 在DuckDB的窗口函数中显式指定能确定原行序的排序键(前提是原DataFrame存在唯一标识行序的列):
# 利用原DataFrame的自增列a确定顺序 result = duckdb.sql('select *, row_number() over (order by a) as index from df')
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

