Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
The results for a UNION ALL that specifies an ORDER BY is sometimes sorted incorrectly.
Note
To Reproduce
Using datafusion-cli (version 22.0) execute;
WITH
m0(time, tag0, f64) AS (VALUES (1667181600000000000, 'val00', 10.1), (1667181610000000000, 'val00', 21.2), (1667181620000000000, 'val00', 11.2), (1667181630000000000, 'val00', 19.2), (1667181600000000000, 'val01', 11.3), (1667181600000000000, 'val02', 10.4), (1667181610000000000, 'val00', 18.9)),
m1(time, tag0, f64) AS (VALUES (1667181600000000000, 'val00', 100.5), (1667181610000000000, 'val00', 200.6), (1667181600000000000, 'val01', 101.7)),
t AS (
SELECT 'm0' as "iox::measurement", tag0, 0::timestamp as time, COUNT(f64), SUM(f64), stddev(f64) FROM m0 GROUP BY 1, 2, 3),
u AS (
SELECT 'm1' as "iox::measurement", tag0, 0::timestamp as time, COUNT(f64), SUM(f64), stddev(f64) FROM m1 GROUP BY 1, 2, 3)
SELECT * FROM t
UNION ALL
SELECT * FROM u
ORDER BY 1, 2, 3;Expected behavior
Output should be sorted on the first 3 columns:
+------------------+-------+---------------------+------------+----------+-------------------+
| iox::measurement | tag0 | time | COUNT(f64) | SUM(f64) | STDDEV(f64) |
+------------------+-------+---------------------+------------+----------+-------------------+
| m0 | val00 | 1970-01-01T00:00:00 | 5 | 80.6 | 5.085961069453836 |
| m0 | val01 | 1970-01-01T00:00:00 | 1 | 11.3 | |
| m0 | val02 | 1970-01-01T00:00:00 | 1 | 10.4 | |
| m1 | val00 | 1970-01-01T00:00:00 | 2 | 301.1 | 70.7813887967734 |
| m1 | val01 | 1970-01-01T00:00:00 | 1 | 101.7 | |
+------------------+-------+---------------------+------------+----------+-------------------+
Actual behavior
Output is sometimes inconsistent, noting that the sort order is incorrect:
+------------------+-------+---------------------+------------+----------+-------------------+
| iox::measurement | tag0 | time | COUNT(f64) | SUM(f64) | STDDEV(f64) |
+------------------+-------+---------------------+------------+----------+-------------------+
| m0 | val00 | 1970-01-01T00:00:00 | 5 | 80.6 | 5.085961069453836 |
| m0 | val01 | 1970-01-01T00:00:00 | 1 | 11.3 | |
| m1 | val00 | 1970-01-01T00:00:00 | 2 | 301.1 | 70.7813887967734 |
| m0 | val02 | 1970-01-01T00:00:00 | 1 | 10.4 | |
| m1 | val01 | 1970-01-01T00:00:00 | 1 | 101.7 | |
+------------------+-------+---------------------+------------+----------+-------------------+
Additional context
DataFusion versions 18, 19, 20 and 21 work consistently after numerous executions of the same query
The following also works on 22
WITH
m0(time, tag0, f64) AS (VALUES (1667181600000000000, 'val00', 10.1), (1667181610000000000, 'val00', 21.2), (1667181620000000000, 'val00', 11.2), (1667181630000000000, 'val00', 19.2), (1667181600000000000, 'val01', 11.3), (1667181600000000000, 'val02', 10.4), (1667181610000000000, 'val00', 18.9)),
m1(time, tag0, f64) AS (VALUES (1667181600000000000, 'val00', 100.5), (1667181610000000000, 'val00', 200.6), (1667181600000000000, 'val01', 101.7)),
t AS (SELECT 'm0' as "iox::measurement", tag0, 0::timestamp as time, COUNT(f64), SUM(f64), stddev(f64) FROM m0 GROUP BY 1, 2, 3),
u AS (SELECT 'm1' as "iox::measurement", tag0, 0::timestamp as time, COUNT(f64), SUM(f64), stddev(f64) FROM m1 GROUP BY 1, 2, 3),
-- add another CTE
v AS (
SELECT * FROM t
UNION ALL
SELECT * FROM u)
SELECT * FROM v
ORDER BY 1, 2, 3;Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
crepererum commentedon Apr 13, 2023
I'm working on this.
crepererum commentedon Apr 13, 2023
I couldn't get the datafusion-cli to reproduce, but I think it largely depends on the plan and the target partitions / CPU count. So here's a code test that reproduces the issue on my system as well. I took the liberty to minimize the SQL query a bit. We apparently only require a very simple group-by and no string columns. Also the time column is irrelevant.
results in:
To me, the phys. plan looks fine. I guess either
SortExecorSortPreservingMergeExecare buggy. The issue was bisected to #5661 which makes use ofSortPreservingMergeExecso my current hypothesis is that this is the buggy one.crepererum commentedon Apr 13, 2023
So the plan is seemingly right but actual wrong:
The two
SortExecs in the above plan have two partitions each (= 4 in total). They are hash-partitioned because this is what you get from the group-by operation.The
UnionExecthinks it is "partition aware" (whatever that means):https://github.com/apache/arrow-datafusion/blob/fcd8b899e2a62f798413c536f47078289ece9d05/datafusion/core/src/physical_plan/union.rs#L157-L168
As a consequence, it only emits 2 output partitions (instead of 4) and concats the input data:
https://github.com/apache/arrow-datafusion/blob/fcd8b899e2a62f798413c536f47078289ece9d05/datafusion/core/src/physical_plan/union.rs#L276-L292
Hence, it no longer preserve sorting. However the
EnforceSortingoptimizer pass thinks it can pushSortExecsafely throughUnionExec:Now we could either blame
EnforceSortingfor performing the wrong optimization orUnionExecfor having some life on its own while seemingly being a really simple node (who would have expected that it concats input batches from different input partitions?!). I would argue thatUnionExecshould NEVER modify its inputs but just be a plain, simple node that forwards its inputs w/o messing up sorting (or any other property).CC @mustafasrepo who authored #5661 (= making
EnforceSortingsmarter) and @mingmwang who taughtUnionExecto be "partition aware" in #4043.alamb commentedon Apr 13, 2023
I agree with this sentiment -- we already have
RepartitionExecthat concatenates batches from different streamsstuartcarnie commentedon Apr 13, 2023
Does it mean that the
UnionExecwill return the inputs sequentially (i.e. concatenated) or will it potentially interleave the inputs, whilst maintaining the ordering?crepererum commentedon Apr 14, 2023
So what it SHOULD do (IMHO) and what it also does in the majority of the cases (i.e. when the
partition_aware = false):However what it actually does with
partition_aware = true:The exact logical of
CombinedRecordBatchStreamcan be found here:https://github.com/apache/arrow-datafusion/blob/fcd8b899e2a62f798413c536f47078289ece9d05/datafusion/core/src/physical_plan/union.rs#L364-L408
This shuffling obviously confuses the
SortPreservingMergeExeclogic because it assumes that the inputs are sorted.fix: remove partition aware union logic
mingmwang commentedon Apr 14, 2023
My suggestion is making the partition-aware optimization a configure option, but do not remove the code.
By default, we turn it off. So that the UnionExec just like a plain Union and do not keep the partition info.
crepererum commentedon Apr 14, 2023
But that also means that if a user turns it on, DataFusion may produce incorrect results. I'm not sure this is a desired feature then.
Edit: discussion mostly moved to #6009.
fix: split "union" and "interleave"
fix: split "union" and "interleave"
fix: split "union" and "interleave" (#6045)