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

CARTESIAN (left outer) (anti) semi join may cause OOM even if right table is not very large #6730

Closed
gengliqi opened this issue Feb 3, 2023 · 1 comment · Fixed by #6746

Comments

@gengliqi
Copy link
Contributor

gengliqi commented Feb 3, 2023

Bug Report

For CARTESIAN (left outer) (anti) semi join, each row in the left table's block must be combined with all of the rows in the right table's block in order to execute other_conditions expression or/and other_eq_conditions_from_in expression.

After that, according to the result of expressions, each row in the left table's block will only produce one or zero number of rows to the result block through filter function as below.

block.getByPosition(i).column = block.getByPosition(i).column->filter(row_filter, -1);

block.getByPosition(i).column = block.getByPosition(i).column->filter(row_filter, -1);

 
Then the issue comes. The allocated memory size of these columns may be much greater than the used memory size of them because filter will use the size of source column to reserve.
/** Removes elements that don't match the filter.
* Is used in WHERE and HAVING operations.
* If result_size_hint > 0, then makes advance reserve(result_size_hint) for the result column;
* if 0, then don't makes reserve(),
* otherwise (i.e. < 0), makes reserve() using size of source column.
*/
using Filter = PaddedPODArray<UInt8>;
virtual Ptr filter(const Filter & filt, ssize_t result_size_hint) const = 0;

 
For example, suppose the number of rows in the right table is 50k, left_rows_per_iter will be only 1 when max_block_size_for_cross_join is 64k.

size_t left_rows_per_iter = std::max(rows_left, 1);
if (max_block_size_for_cross_join > 0 && right_table_rows > 0 && other_condition_ptr != nullptr
&& CrossJoinAdder<KIND, STRICTNESS>::allRightRowsMaybeAdded())
{
/// if other_condition is not null, and all right columns maybe added during join, try to use multiple iter
/// to make memory usage under control, for anti semi cross join that is converted by not in subquery,
/// it is likely that other condition may filter out most of the rows
left_rows_per_iter = std::max(max_block_size_for_cross_join / right_table_rows, 1);
}

So in each iteration, there should be only one or zero number of rows in the result block while the allocated memory size is approximately equal to the memory of 50k rows.

If there are 64k rows in this block of the left table, there are 64k result blocks and the allocated memory size is approximately equal to the memory of 50k * 64k = 3276800k rows, which is likely to make TiFlash OOM.

@gengliqi gengliqi added the type/bug The issue is confirmed as a bug. label Feb 3, 2023
@gengliqi gengliqi changed the title CARTESIAN (left outer) (anti) semi join may cause OOM easily even if right table is not very large CARTESIAN (left outer) (anti) semi join may cause OOM even if right table is not very large Feb 3, 2023
@gengliqi gengliqi self-assigned this Feb 3, 2023
@LittleFall
Copy link
Contributor

Please remove the may-affect-** tag as needed or convert it to a definitive affect-** tag to make pr pass the ci check

ywqzzy pushed a commit to ywqzzy/tiflash_1 that referenced this issue Feb 13, 2023
…size_hint < 0 (pingcap#6746)

close pingcap#6730

Signed-off-by: ywqzzy <592838129@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment