sql: add hash join algorithm for USING/NATURAL predicates#10618
sql: add hash join algorithm for USING/NATURAL predicates#10618irfansharif merged 7 commits intocockroachdb:masterfrom
Conversation
ebf90a6 to
93c05c5
Compare
|
Seeing how the join tests needed to be changed to use ORDER BY made me smile; it's exactly what SQL is supposed to be!
Reviewed 3 of 4 files at r1, 2 of 3 files at r2, 11 of 11 files at r3. pkg/sql/join.go, line 43 at r2 (raw file):
Just curious, why did you pull this method (commonColumns) up so far from the constructor that uses it? Oh then, I see in the next commit it disappears from here again. pkg/sql/join.go, line 34 at r3 (raw file):
If you think it is important to rename these constants, please split in a different commit. Right now it obscures the diff. pkg/sql/join.go, line 47 at r3 (raw file):
Use a single RowContainer for the entire joinNode, then take slices of its row array in each bucket. Separating RowContainers is only meaningful if they would have (say) different lists of columns. pkg/sql/join.go, line 116 at r3 (raw file):
Don't move this function away from where it was originally defined in the same commit where you modify it. Right now in the diff I see a diff for the entire function (move), and the particular changes you've made are obscured by this. This makes it very hard to review. pkg/sql/join.go, line 313 at r3 (raw file):
Split the code for the different loops in different functions; also use switch not if else. pkg/sql/join.go, line 390 at r3 (raw file):
switch pkg/sql/join.go, line 397 at r3 (raw file):
extract the error into a global err variable. pkg/sql/join.go, line 543 at r3 (raw file):
Extend this explanatory comment to highlight what happens when joining on 2 or more columns, and only one of them contains NULL. pkg/sql/join.go, line 576 at r3 (raw file):
Add a comment here "// Failed to match -- no matching row, nothing to do." pkg/sql/join.go, line 579 at r3 (raw file):
Insert a comment line above here "// Outer join: unmatched rows are padded with NULLs." pkg/sql/join.go, line 641 at r3 (raw file):
switch pkg/sql/join.go, line 663 at r3 (raw file):
switch pkg/sql/join.go, line 673 at r3 (raw file):
See my comment above; this is insane. As a general rule of thumb, the complexity of Close() for an entire logical plan should be linear in the number of nodes of the logical plan, and fully independent of the data in the database. That's the entire design contract of the monitor/account machinery. If we didn't want that, we may as well skip MemoryAccount entirely and use a loop in RowContainer to substract consumed memory row by row. pkg/sql/join_predicate.go, line 37 at r3 (raw file):
pkg/sql/join_predicate.go, line 206 at r3 (raw file):
Use int for "side"; also use switch not if here. pkg/sql/join_predicate.go, line 285 at r3 (raw file):
Woah good catch, but not the right fix. There should be a check here before the assignment to pkg/sql/row_buffer.go, line 33 at r3 (raw file):
I'd run PopFirst() at the beginning of Next() and avoid pkg/sql/distsql/hashjoiner.go, line 147 at r3 (raw file):
This seems unrelated. Please extract in a separate commit (and probably PR). Comments from Reviewable |
|
Review status: all files reviewed at latest revision, 19 unresolved discussions, all commit checks successful. pkg/sql/join.go, line 97 at r3 (raw file):
Don't use BoundAccount here; use WrappableMemoryAccount. See Comments from Reviewable |
93c05c5 to
d2da2bf
Compare
Done.
that's a good tip, thank you! restructured and moved commits around to reflect this now. Review status: 1 of 9 files reviewed at latest revision, 19 unresolved discussions. pkg/sql/join.go, line 43 at r2 (raw file):
|
d2da2bf to
be1b3d6
Compare
|
Review status: 1 of 9 files reviewed at latest revision, 19 unresolved discussions, some commit checks failed. pkg/sql/join.go, line 313 at r3 (raw file):
|
|
Thanks for addressing most of the concerns. The topic of the row containers is still open though. Reviewed 2 of 11 files at r3, 2 of 9 files at r4, 2 of 2 files at r5, 3 of 4 files at r7, 3 of 3 files at r8. pkg/sql/row_buffer.go, line 33 at r3 (raw file):
|
|
For the first commit, did you use Review status: all files reviewed at latest revision, 4 unresolved discussions, some commit checks failed. pkg/sql/index_join.go, line 241 at r5 (raw file):
This refactoring is not correct; the loop is needed - what if there are no rows produced from this batch? ( Comments from Reviewable |
|
Review status: all files reviewed at latest revision, 4 unresolved discussions, some commit checks failed. pkg/sql/index_join.go, line 241 at r5 (raw file):
|
be1b3d6 to
1f7c542
Compare
|
@RaduBerinde: I did use Review status: 0 of 12 files reviewed at latest revision, 5 unresolved discussions, some commit checks failed. pkg/sql/index_join.go, line 241 at r5 (raw file):
|
renamed file to match the rest of the package layout.
renamed file to match the rest of the package layout.
refactor out join predicate definitions, implementations into separate file.
1f7c542 to
aa97922
Compare
|
@knz: PTAL, latest revision demonstrates my ideas about the use of a shared Review status: 0 of 19 files reviewed at latest revision, 4 unresolved discussions, some commit checks pending. pkg/sql/join.go, line 47 at r3 (raw file):
Done. Comments from Reviewable |
Implementation of the hash join algorithm, limited to only NATURAL and USING predicates. ON predicates, atleast for now, fall back to the nested join implementation. There's an intermediary result buffer attached to the join node here, this cleans up the code compared to an earlier implementation with maintained state for consecutive calls to Next() and Values() and can be used similarly for other plan nodes where the computation of a batch of results is simpler to reason about with state maintenance pushed down to the buffer itself.
e404542 to
dace2b0
Compare
Done. Review status: 0 of 19 files reviewed at latest revision, 4 unresolved discussions, some commit checks pending. Comments from Reviewable |
|
I have started the review from scratch. Thanks to you splitting the changes in different commits, the experience was much more pleasant this time! The overall changes LGTM. The overall architecture of join looks fine this way. However you did something with the memory accounts which I rather strongly disagree with. A lot of the current complexity in the code was added to avoid interfaces in the monitoring API and their call overhead, and you've just introduced one. So I'd like us to look at this together and explore alternatives. If you wish I can also attempt to explore this myself and submit a PR towards your branch. Whatever you're most comfortable with. Reviewed 2 of 11 files at r3, 8 of 9 files at r9, 2 of 2 files at r10, 2 of 2 files at r11, 3 of 3 files at r12, 5 of 5 files at r13. pkg/sql/join.go, line 162 at r11 (raw file):
So why did you remove the pkg/sql/row_buffer.go, line 31 at r12 (raw file):
I think if you make RowBuffer inherit from *RowContainer you don't have to implement the two methods Close and AddRow. pkg/sql/row_container.go, line 31 at r14 (raw file):
No, please don't go there. I do not wish us to pay the price of an interface for this use case. :) Comments from Reviewable |
dace2b0 to
7312e7c
Compare
|
I investigated possible alternatives here some more, I want to bring back to question what exactly do we have to gain using a Additionally (possibly related) do you foresee the unification of the two ( Review status: 6 of 20 files reviewed at latest revision, 5 unresolved discussions. pkg/sql/join.go, line 162 at r11 (raw file):
|
|
Oh I see, cleaner transitioning between session specific and transaction specific contexts. I'm still not sure Review status: 6 of 20 files reviewed at latest revision, 5 unresolved discussions, all commit checks successful. Comments from Reviewable |
Shared RowContainer between all buckets, separate memory account used for RowBuffer structure. Additionally embedded RowContainer into RowBuffer to avoid duplicate AddRow() and Close() functionality.
7312e7c to
d74aa09
Compare
|
@knz: PTAL, reverted back to the original use of Review status: 6 of 19 files reviewed at latest revision, 5 unresolved discussions, some commit checks pending. Comments from Reviewable |
|
Reviewed 1 of 2 files at r10, 14 of 14 files at r15, 2 of 2 files at r16. pkg/sql/join.go, line 162 at r11 (raw file):
|
|
Well done, btw. I dig this PR :) 💛 Review status: all files reviewed at latest revision, 2 unresolved discussions, all commit checks successful. Comments from Reviewable |
d74aa09 to
4623eff
Compare
|
Thank you for letting me work on this, I did give you a lot to review as well so thank you for being so prompt with that! Review status: 18 of 19 files reviewed at latest revision, 2 unresolved discussions, some commit checks pending. pkg/sql/join.go, line 76 at r16 (raw file):
|
|
👍 Reviewed 1 of 2 files at r10, 1 of 1 files at r17. Comments from Reviewable |
|
Great stuff!! 👍 |
Implementation of the hash join algorithm, limited to only
NATURALandUSINGpredicates.ONpredicates with explicit equality constraints(i.e.
a.x = b.x), at least for now, fall back to the nested loop join implementation.There's an intermediary result buffer attached to the join node here,
this cleans up the code compared to an earlier implementation with
maintained state for consecutive calls to
Next()andValues()and can beused similarly for other plan nodes where the computation of a batch of
results is simpler to reason about with any 'state maintenance' pushed down to
the buffer itself.
Due to #10534 the current buffer implementation is non-functional,
extending
RowContainerto support deletes at the front now to address this.(edit: #10623, done)
Addresses #10397.
cc @RaduBerinde @knz
This change is