-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-24985][SQL][WIP] Fix OOM in Full Outer Join in case of data skew #22168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
c5e83ab
0b150f8
a0d807d
d575a45
d4420b4
57aff93
13c5c1f
949d712
d7dd59a
3628242
b8b5acd
1d20d13
3286bff
1bc6723
d04a737
ffb362a
b517636
69dd44a
6c4552c
5c50f68
b56e433
1d95dea
f7bd1ab
938d954
0e44a51
04e53d2
568db94
5678e68
a840b99
23bde44
982c4c8
39f75b4
979bb90
4a5768b
6450c59
53e31e2
017919b
18b36ee
02e9f93
215609d
33f3c48
52838e7
0024173
d50603a
dfa2328
051336d
f16dfb9
3e4cfe9
601fac2
5ff39cd
3db117e
63e4bf4
f62f44f
05f6b87
08858f6
58674d5
2e90574
85e5d4f
5ea4dee
1470f23
ab8710b
181d190
0745333
4177292
d33ae2e
239082d
43da473
4ec7f63
5d8aee5
94adffa
bbbe54a
4eb694c
0407070
9ed60c2
0881f64
38fc8e2
67bd124
4704af4
eea3f55
0bb716b
27d625d
3ab96d7
d35e81f
c58a4fe
a4cf1a4
f9837d3
8718367
257d01a
88d9de2
a8f20c9
7c4a643
b404e02
26ed65f
1bb0c8e
61feb16
54b0d1e
e6618de
e1c90d6
f93460d
50bdc9b
7d44ba0
9c238b8
9c41bfd
3748b38
e1ece6a
8f82237
163a6e2
31488e1
16bbe0f
777b450
d61b3bc
4cb1cd6
ad60c6d
9793d9e
8a8643c
009059e
d4a16f4
777b797
d36cce1
79d3bc0
5172190
3240e52
43a73e3
55f26d8
93a264d
d9b2ce0
7cc15af
ecfdffc
00f2f31
810be5d
5bf5d9d
596a5ff
a30983d
cd4a284
b7f9830
b1c6b60
f82ed5e
8b86326
d5dbf05
d2656aa
2234667
85fd552
fe99305
7b367bf
6328be7
90085a1
bde30bc
447d018
d8db7db
20a3ef7
05b85eb
07d07fe
5a62295
76785cd
fbc7942
8a17d26
a6716d3
fb6b19a
75b40a5
618d6bf
7432e7d
25ee047
a35043c
6eca435
8375103
9623420
fcc42d4
3670826
2da406c
b73744a
253a879
df8aa7b
7a8cc8e
3ecafb0
f950e53
875e7e1
375cfa3
3859ca3
5c47924
9a419c3
6c2d351
51de86b
4241a72
c66ec43
5182aa2
d9bcacf
6001d47
4b725e5
6ef4530
eec1a3c
d5308cd
d124ce9
8ef4da7
614a5cc
2f55809
5e79ae3
303ee3f
83f628b
8329e7d
3ea44e5
e63fbfc
bae5baa
09422f5
57450ed
78a403f
0969d7a
b5ffec1
9b3211a
fbb56f2
cfe236f
78748b5
80de449
3442fca
c71f217
fa5dc0a
bcd3b61
dbb8143
9ff77b1
5a8aad0
be6d39c
2bc42ad
126310c
d169b0a
f3ddd6f
8b0bdaa
66f5a42
db2e3c4
695dbe2
a10608c
fee695d
2da5b21
7dd2dd5
fd9acf2
bfb3ffe
d14e2d7
efa3035
0bba5cf
02c3369
3e30a98
c6a45e6
6a317c8
fc5bd6d
9e0d8c6
e39e97b
141a3bf
9bca99b
e354042
824d357
d47e788
b435303
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -248,7 +248,9 @@ case class SortMergeJoinExec( | |||||||||||||||||||||||||||||||||||||||||||||||
| rightIter = RowIterator.fromScala(rightIter), | ||||||||||||||||||||||||||||||||||||||||||||||||
| boundCondition, | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftNullRow, | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightNullRow) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightNullRow, | ||||||||||||||||||||||||||||||||||||||||||||||||
| inMemoryThreshold, | ||||||||||||||||||||||||||||||||||||||||||||||||
| spillThreshold) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| new FullOuterIterator( | ||||||||||||||||||||||||||||||||||||||||||||||||
| smjScanner, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -966,7 +968,9 @@ private class SortMergeFullOuterJoinScanner( | |||||||||||||||||||||||||||||||||||||||||||||||
| rightIter: RowIterator, | ||||||||||||||||||||||||||||||||||||||||||||||||
| boundCondition: InternalRow => Boolean, | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftNullRow: InternalRow, | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightNullRow: InternalRow) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightNullRow: InternalRow, | ||||||||||||||||||||||||||||||||||||||||||||||||
| inMemoryThreshold: Int, | ||||||||||||||||||||||||||||||||||||||||||||||||
| spillThreshold: Int) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] val joinedRow: JoinedRow = new JoinedRow() | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var leftRow: InternalRow = _ | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var leftRowKey: InternalRow = _ | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -975,8 +979,10 @@ private class SortMergeFullOuterJoinScanner( | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var leftIndex: Int = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var rightIndex: Int = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] val leftMatches: ArrayBuffer[InternalRow] = new ArrayBuffer[InternalRow] | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] val rightMatches: ArrayBuffer[InternalRow] = new ArrayBuffer[InternalRow] | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] val leftMatches: ExternalAppendOnlyUnsafeRowArray = | ||||||||||||||||||||||||||||||||||||||||||||||||
| new ExternalAppendOnlyUnsafeRowArray(inMemoryThreshold, spillThreshold) | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] val rightMatches: ExternalAppendOnlyUnsafeRowArray = | ||||||||||||||||||||||||||||||||||||||||||||||||
| new ExternalAppendOnlyUnsafeRowArray(inMemoryThreshold, spillThreshold) | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var leftMatched: BitSet = new BitSet(1) | ||||||||||||||||||||||||||||||||||||||||||||||||
| private[this] var rightMatched: BitSet = new BitSet(1) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1028,23 +1034,23 @@ private class SortMergeFullOuterJoinScanner( | |||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| while (leftRowKey != null && keyOrdering.compare(leftRowKey, matchingKey) == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatches += leftRow.copy() | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatches.add(leftRow.copy().asInstanceOf[UnsafeRow]) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
sujithjay marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||
| advancedLeft() | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| while (rightRowKey != null && keyOrdering.compare(rightRowKey, matchingKey) == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatches += rightRow.copy() | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatches.add(rightRow.copy().asInstanceOf[UnsafeRow]) | ||||||||||||||||||||||||||||||||||||||||||||||||
| advancedRight() | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (leftMatches.size <= leftMatched.capacity) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched.clearUntil(leftMatches.size) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (leftMatches.length <= leftMatched.capacity) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched.clearUntil(leftMatches.length) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched = new BitSet(leftMatches.size) | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched = new BitSet(leftMatches.length) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (rightMatches.size <= rightMatched.capacity) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched.clearUntil(rightMatches.size) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (rightMatches.length <= rightMatched.capacity) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched.clearUntil(rightMatches.length) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched = new BitSet(rightMatches.size) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched = new BitSet(rightMatches.length) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1058,31 +1064,37 @@ private class SortMergeFullOuterJoinScanner( | |||||||||||||||||||||||||||||||||||||||||||||||
| * @return true if a valid match is found, false otherwise. | ||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||
| private def scanNextInBuffered(): Boolean = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| while (leftIndex < leftMatches.size) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| while (rightIndex < rightMatches.size) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftMatches(leftIndex), rightMatches(rightIndex)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (boundCondition(joinedRow)) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched.set(leftIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched.set(rightIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
| val leftMatchesIterator = leftMatches.generateIterator(leftIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| while (leftMatchesIterator.hasNext) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| val leftCurRow = leftMatchesIterator.next() | ||||||||||||||||||||||||||||||||||||||||||||||||
| val rightMatchesIterator = rightMatches.generateIterator(rightIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we keep the scanning left and right iterators? Because if they are spilled, obtaining the iterator from spilled data needs to loop over spill writers and create readers. We may avoid calling
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @viirya, I agree the code will be a bit complicated if we had to keep scanning the iterators. In this particular case, I was following a pattern observed throughout the rest of the class. spark/sql/core/src/main/scala/org/apache/spark/sql/execution/joins/SortMergeJoinExec.scala Lines 307 to 329 in 35f7f5c
Having said that, I do feel the penalty for following a similar approach in case of full outer joins could be higher. I will try & see what I can do.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @viirya , |
||||||||||||||||||||||||||||||||||||||||||||||||
| while (rightMatchesIterator.hasNext) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftCurRow, rightMatchesIterator.next()) | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (boundCondition(joinedRow)) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftMatched.set(leftIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightMatched.set(rightIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!leftMatched.get(leftIndex)) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // the left row has never matched any right row, join it with null row | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftMatches(leftIndex), rightNullRow) | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftCurRow, rightNullRow) | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| leftIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| while (rightIndex < rightMatches.size) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| val rightMatchesIterator = rightMatches.generateIterator(rightIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||
| while (rightMatchesIterator.hasNext) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| val rightCurRow = rightMatchesIterator.next() | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!rightMatched.get(rightIndex)) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // the right row has never matched any left row, join it with null row | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftNullRow, rightMatches(rightIndex)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| joinedRow(leftNullRow, rightCurRow) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rightIndex += 1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1099,7 +1111,7 @@ private class SortMergeFullOuterJoinScanner( | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| def advanceNext(): Boolean = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // If we already buffered some matching rows, use them directly | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (leftIndex <= leftMatches.size || rightIndex <= rightMatches.size) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (leftIndex <= leftMatches.length || rightIndex <= rightMatches.length) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
sujithjay marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (scanNextInBuffered()) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.