Skip to content
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

feat(hashjoin): Add fast row size estimation for hash probe #11558

Closed

Conversation

tanjialiang
Copy link
Contributor

@tanjialiang tanjialiang commented Nov 16, 2024

  • Add column stats for row container to collect aggregated column stats. The aggregated column stats will be used in hash probe to decide if row size estimation is applicable. If it is applicable, column stats will be used to compose a fast row size estimation to avoid memory exploding when probing and listing results. This added feature makes hash join more performant, and in some extreme skew cases that we've seen in Meta internal queries, it helped to decrease the query latency by >20x.
  • The work of this feature also helped to discovered a bug in HashTable when using simd for fast path result listing -> when max number of rows is smaller than kWidth, the unsigned integer overflow bug will make the max number of rows be ignored. Fixed the bug and the new test covers that case.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 16, 2024
Copy link

netlify bot commented Nov 16, 2024

Deploy Preview for meta-velox canceled.

Name Link
🔨 Latest commit 07ede69
🔍 Latest deploy log https://app.netlify.com/sites/meta-velox/deploys/6740f6ecd8c3000008da482b

@tanjialiang tanjialiang force-pushed the rc_column_stats branch 2 times, most recently from 852cbe2 to 9ed88ab Compare November 17, 2024 01:10
@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@tanjialiang tanjialiang force-pushed the rc_column_stats branch 2 times, most recently from a9dc3bc to b4758b6 Compare November 18, 2024 04:47
@tanjialiang tanjialiang changed the title [WIP] feature(hashjoin): Add fast path to list join result feature(hashjoin): Add fast row size estimation for hash probe Nov 18, 2024
@tanjialiang tanjialiang marked this pull request as ready for review November 18, 2024 04:55
@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

Copy link
Contributor

@xiaoxmeng xiaoxmeng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tanjialiang thanks for the improvement % minors.

velox/exec/RowContainer.h Outdated Show resolved Hide resolved
velox/exec/RowContainer.h Outdated Show resolved Hide resolved

private:
// Aggregated stats for non-null rows of the column.
int32_t minBytes_{0};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use uint32_t? Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int32_t is widely used as cell size in row container. I'm trying to make it compatible so that no cast is needed when performing ::max ::min. If we want we can have another PR for refactoring the types in general.

velox/exec/RowContainer.cpp Outdated Show resolved Hide resolved
velox/exec/RowContainer.h Outdated Show resolved Hide resolved
if (columnStatsValid) {
for (uint32_t columnIndex = 0; columnIndex < rowColumnsStats_.size();
columnIndex++) {
if (types_[columnIndex]->isFixedWidth()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep this simple by having column stats for fixed width as well like null count sth.

velox/exec/RowContainer.cpp Outdated Show resolved Hide resolved
velox/exec/HashProbe.h Outdated Show resolved Hide resolved
velox/exec/HashProbe.h Outdated Show resolved Hide resolved
velox/exec/HashProbe.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@xiaoxmeng xiaoxmeng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tanjialiang LGTM % minors. Thanks!

velox/exec/RowContainer.h Outdated Show resolved Hide resolved
velox/exec/RowContainer.h Outdated Show resolved Hide resolved
velox/exec/RowContainer.h Outdated Show resolved Hide resolved
velox/exec/RowContainer.cpp Outdated Show resolved Hide resolved
velox/exec/RowContainer.cpp Outdated Show resolved Hide resolved
velox/exec/HashProbe.h Outdated Show resolved Hide resolved
velox/exec/HashProbe.cpp Show resolved Hide resolved
velox/exec/HashProbe.cpp Outdated Show resolved Hide resolved
if (totalMaxBytes == 0) {
return 0;
}
return std::nullopt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why return null here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After offline discussion, I re-thought about it. The reason we want to return nullopt is as follows:
Imagine we have a case where 99999999 rows are of size 0, and 1 row is of size 1MB. And all left side join with this row. This will explode the memory.

velox/exec/HashProbe.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@xiaoxmeng xiaoxmeng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tanjialiang thanks!

totalAvgBytes += stats.avgBytes();
totalMaxBytes += stats.maxBytes();
}
if (totalAvgBytes == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (totalAvgBytes == 0) {
  return 0;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After offline discussion, I re-thought about it. The reason we want to return nullopt is as follows:
Imagine we have a case where 99999999 rows are of size 0, and 1 row is of size 1MB. And all left side join with this row. This will explode the memory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it explodes? So most of rows are zero size so it is ok to execute fast path? There is number of output row limit.

@tanjialiang tanjialiang force-pushed the rc_column_stats branch 2 times, most recently from b69ee43 to 9a3270b Compare November 20, 2024 01:56
@tanjialiang tanjialiang changed the title feature(hashjoin): Add fast row size estimation for hash probe feat(hashjoin): Add fast row size estimation for hash probe Nov 20, 2024
@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@tanjialiang tanjialiang force-pushed the rc_column_stats branch 3 times, most recently from 03bbefd to 613aebe Compare November 20, 2024 09:16
@tanjialiang tanjialiang force-pushed the rc_column_stats branch 6 times, most recently from c041da5 to 5ab4a6e Compare November 20, 2024 19:53
@tanjialiang tanjialiang force-pushed the rc_column_stats branch 3 times, most recently from f99c1be to ccfd4e7 Compare November 20, 2024 23:55
@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

Copy link
Contributor

@xiaoxmeng xiaoxmeng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tanjialiang can you add to track the row column size for non-join case as well. The prefix sort might require that as well @zhli1142015 . Thanks!

@@ -27,7 +27,7 @@ namespace facebook::velox::functions::prestosql {
namespace {

class SimpleComparisonMatcherTest : public testing::Test,
public test::VectorTestBase {
public velox::test::VectorTestBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need these namespace changes?

@@ -26,6 +26,7 @@
#include "velox/parse/TypeResolver.h"
#include "velox/vector/tests/utils/VectorTestBase.h"

using namespace facebook;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need additional facebook namespace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For making complier not confused with the newly added test namespace in exec.

@zhli1142015
Copy link
Contributor

zhli1142015 commented Nov 21, 2024

Yes, we should also need max length for string columns for prefix sort.
#11527 (comment)
#11272

@tanjialiang
Copy link
Contributor Author

ot successful

I'll do a followup PR for that, to make sure there's no regression if enabled by default.

@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@tanjialiang tanjialiang force-pushed the rc_column_stats branch 5 times, most recently from 1f56443 to 397baeb Compare November 22, 2024 01:14
@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@tanjialiang has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

…incubator#11558)

Summary:
* Add column stats for row container to collect aggregated column stats. The aggregated column stats will be used in hash probe to decide if row size estimation is applicable. If it is applicable, column stats will be used to compose a fast row size estimation to avoid memory exploding when probing and listing results. This added feature makes hash join more performant, and in some extreme skew cases that we've seen in Meta internal queries, it helped to decrease the query latency by >20x.
* The work of this feature also helped to discovered a bug in HashTable when using simd for fast path result listing -> when max number of rows is smaller than kWidth, the unsigned integer overflow bug will make the max number of rows be ignored. Fixed the bug and the new test covers that case.

Pull Request resolved: facebookincubator#11558

Reviewed By: xiaoxmeng

Differential Revision: D66064300

Pulled By: tanjialiang
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D66064300

@facebook-github-bot
Copy link
Contributor

@tanjialiang merged this pull request in 059337f.

Copy link

Conbench analyzed the 1 benchmark run on commit 059337fc.

There were no benchmark performance regressions. 🎉

The full Conbench report has more details.

@FelixYBW
Copy link

FelixYBW commented Dec 4, 2024

Thank you for the fix. @zhouyuan @zhztheplayer Is our Gluten Jenkins verified?

athmaja-n pushed a commit to athmaja-n/velox that referenced this pull request Jan 10, 2025
…incubator#11558)

Summary:
* Add column stats for row container to collect aggregated column stats. The aggregated column stats will be used in hash probe to decide if row size estimation is applicable. If it is applicable, column stats will be used to compose a fast row size estimation to avoid memory exploding when probing and listing results. This added feature makes hash join more performant, and in some extreme skew cases that we've seen in Meta internal queries, it helped to decrease the query latency by >20x.
* The work of this feature also helped to discovered a bug in HashTable when using simd for fast path result listing -> when max number of rows is smaller than kWidth, the unsigned integer overflow bug will make the max number of rows be ignored. Fixed the bug and the new test covers that case.

Pull Request resolved: facebookincubator#11558

Reviewed By: xiaoxmeng

Differential Revision: D66064300

Pulled By: tanjialiang

fbshipit-source-id: 886cd943036350b1c1bf0b6741ebe7165883a30f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants