You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem or challenge?
In SortMergeJoin, it is possibly run of memory when it requires extra memory to hold polled buffer batches. We can consider adding spilling support there to make the operator resilient to the memory issue.
Describe the solution you'd like
Add spilling support in SortMergeJoin.
Describe alternatives you've considered
No response
Additional context
No response
Reacted by SteveLauC, Oleks V, Marko Milenković and Hector Veiga
After reading some code and already opened issues on the same topic, probably its possible to summarize whats needed for POC at least:
try to use external mem sorter to sort streamed and buffered batches for the sort phases
MemoryReservation is already in SMJ impl and for merge phase it uses the try_grow on buffered, so naive approach is to spill buffered and read back lesser chunks from disk, we can play with that
run test query and try to profile memory to see other places where spill can be useful
I think I managed to find the test query.
First observation is SMJ using external sorter, but the spill doesn't work, will dig into it.
Resources exhausted: Failed to allocate additional 1048576 bytes for ExternalSorterMerge[0] with 0 bytes already allocated - maximum available is 1043520
This gives me a suggestion ExternalSorter used but spill is not used
Playing with sort params I managed to make SMJ merge phase complain on mem exhaustion
./datafusion-cli/target/debug/datafusion-cli -m 1m
DataFusion CLI v37.0.0
❯ set datafusion.optimizer.prefer_hash_join = false;
0 row(s) fetched.
Elapsed 0.003 seconds.
❯ set datafusion.execution.sort_in_place_threshold_bytes = 104857;
0 row(s) fetched.
Elapsed 0.001 seconds.
❯ set datafusion.execution.sort_spill_reservation_bytes = 104857;
0 row(s) fetched.
Elapsed 0.000 seconds.
❯ select * from (select unnest(range(0, 10000)) id) t inner join (select unnest(range(0, 100000)) id) t1 on t.id = t1.id;
Resources exhausted: Failed to allocate additional 165208 bytes for SMJStream[5] with 0 bytes already allocated - maximum available is 65456
I can reproduce this pretty reliably in lance if it's any help. I run SortExec on a column of 100 million strings (each ~30 bytes long) and I have a 100MiB fair pool and it triggers in about 5 minutes. Let me know if there is anything I can do to assist you.
FWIW, I believe I was looking at this problem some time ago, if I remember correctly the issue was that one of the memory consumer, presumably ExternalSorterMerge was returning all the memory it allocated just to ask for new allocation with similar size very soon after. MemoryConsumer would return all the memory when dropped.
Thanks, I'm planning to check next week if spilling works or not for ExternalSorter used for SMJ and see how it is possible to make spilling work as well for the merge phase, the memory pool is injected and SMJ get new allocations through try_grow so lets see what we can do
Activity
Omega359 commentedon Feb 27, 2024
Possibly related: #8398, #9170, #5108, #1599
comphead commentedon Apr 2, 2024
After reading some code and already opened issues on the same topic, probably its possible to summarize whats needed for POC at least:
comphead commentedon Apr 2, 2024
I'll try to start with creating a test query that fails on mem
comphead commentedon Apr 5, 2024
Related to #9846
comphead commentedon Apr 7, 2024
I think I managed to find the test query.
First observation is SMJ using external sorter, but the spill doesn't work, will dig into it.
This gives me a suggestion ExternalSorter used but spill is not used
Playing with sort params I managed to make SMJ merge phase complain on mem exhaustion
comphead commentedon Apr 7, 2024
My next steps
ExternalSorterMergedoesn't use spillwestonpace commentedon Apr 11, 2024
I can reproduce this pretty reliably in lance if it's any help. I run SortExec on a column of 100 million strings (each ~30 bytes long) and I have a 100MiB fair pool and it triggers in about 5 minutes. Let me know if there is anything I can do to assist you.
milenkovicm commentedon Apr 12, 2024
FWIW, I believe I was looking at this problem some time ago, if I remember correctly the issue was that one of the memory consumer, presumably
ExternalSorterMergewas returning all the memory it allocated just to ask for new allocation with similar size very soon after.MemoryConsumerwould return all the memory when dropped.My suspect is:
https://github.com/apache/arrow-datafusion/blob/a5cf0b8902ae55b81ac86b875c7e94cf1bdc205d/datafusion/physical-plan/src/sorts/sort.rs#L263
or
https://github.com/apache/arrow-datafusion/blob/a5cf0b8902ae55b81ac86b875c7e94cf1bdc205d/datafusion/physical-plan/src/sorts/sort.rs#L359
or somewhere around it.
line
may back my clain
I cant find more information looks like that branch is MIA
comphead commentedon Apr 12, 2024
Thanks, I'm planning to check next week if spilling works or not for ExternalSorter used for SMJ and see how it is possible to make spilling work as well for the merge phase, the memory pool is injected and SMJ get new allocations through
try_growso lets see what we can docomphead commentedon Jun 6, 2024
Finally starting on it. The test doesn't work anymore
viirya commentedon Jun 6, 2024
Yes, I tried the above test few days ago but it doesn't work now.
comphead commentedon Jun 6, 2024
I made it work that way (notice
-m 1m)Weird the same thing as a test doesn't respect memory pool
comphead commentedon Jun 7, 2024
the first use case is to try spilling for buffered data, as the buffered data comes in full size and eats the memory.
This is proved by query below
UPD: Buffered data comes in by partitions, every partition gets processed sequentially. The flow is approx:
Looks like the spilling needed in 1 place only