1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-28217 Incorrect Join Execution When Controlling Join Buffer Size

The problem was that join_buffer_size conflicted with
join_buffer_space_limit, which caused the query to be run without join
buffer. However this caused wrong results as the optimizer assumed
that hash+join buffer would ensure that the equi-join condition
would be satisfied, and didn't check it itself.

Fixed by not using join_buffer_space_limit when
optimize_join_buffer_size=off. This matches the documentation at
https://mariadb.com/kb/en/block-based-join-algorithms

Other things:
- Removed not used variable JOIN_TAB::join_buffer_size_limit
- Give an error if we cannot allocate a join buffer. This can
  only happen if the join_buffer variables are wrongly configured or
  we are running out of memory.
  In the future, instead of returning an error, we could properly
  convert the query plan that uses BNL-H join into one that doesn't
  use join buffering:
  make sure the equi-join condition is checked where appropriate.

Reviewer: Sergei Petrunia <sergey@mariadb.com>
This commit is contained in:
Monty
2023-05-03 21:27:30 +03:00
parent 01ea779149
commit 08a4732860
5 changed files with 104 additions and 28 deletions

View File

@ -805,20 +805,18 @@ size_t JOIN_CACHE::get_min_join_buffer_size()
the estimated number of records in the partial join
DESCRIPTION
At the first its invocation for the cache the function calculates the
maximum possible size of join buffer for the cache. If the parameter
optimize_buff_size true then this value does not exceed the size of the
space needed for the estimated number of records 'max_records' in the
partial join that joins tables from the first one through join_tab. This
value is also capped off by the value of join_tab->join_buffer_size_limit,
if it has been set a to non-zero value, and by the value of the system
parameter join_buffer_size - otherwise. After the calculation of the
interesting size the function saves the value in the field 'max_buff_size'
in order to use it directly at the next invocations of the function.
NOTES
Currently the value of join_tab->join_buffer_size_limit is initialized
to 0 and is never reset.
At the first its invocation for the cache the function calculates
the maximum possible size of join buffer for the cache. If the
parameter optimize_buff_size true then this value does not exceed
the size of the space needed for the estimated number of records
'max_records' in the partial join that joins tables from the first
one through join_tab. This value is also capped off by the value
of the system parameter join_buffer_size. After the calculation of
the interesting size the function saves the value in the field
'max_buff_size' in order to use it directly at the next
invocations of the function.
RETURN VALUE
The maximum possible size of the join buffer of this cache
@ -842,8 +840,6 @@ size_t JOIN_CACHE::get_max_join_buffer_size(bool optimize_buff_size)
space_per_record= len;
size_t limit_sz= (size_t)join->thd->variables.join_buff_size;
if (join_tab->join_buffer_size_limit)
set_if_smaller(limit_sz, join_tab->join_buffer_size_limit);
if (!optimize_buff_size)
max_sz= limit_sz;
else
@ -923,13 +919,25 @@ int JOIN_CACHE::alloc_buffer()
curr_min_buff_space_sz+= min_buff_size;
curr_buff_space_sz+= buff_size;
if (curr_min_buff_space_sz > join_buff_space_limit ||
(curr_buff_space_sz > join_buff_space_limit &&
(!optimize_buff_size ||
if (optimize_buff_size)
{
/*
optimize_join_buffer_size=on used. We should limit the join
buffer space to join_buff_space_limit if possible.
*/
if (curr_min_buff_space_sz > join_buff_space_limit)
{
/*
Increase buffer size to minimum needed, to be able to use the
join buffer.
*/
join_buff_space_limit= curr_min_buff_space_sz;
}
if (curr_buff_space_sz > join_buff_space_limit &&
join->shrink_join_buffers(join_tab, curr_buff_space_sz,
join_buff_space_limit))))
goto fail;
join_buff_space_limit))
goto fail; // Fatal error
}
if (for_explain_only)
return 0;
@ -2766,7 +2774,6 @@ bool JOIN_CACHE_BKAH::save_explain_data(EXPLAIN_BKA_TYPE *explain)
int JOIN_CACHE_HASHED::init(bool for_explain)
{
int rc= 0;
TABLE_REF *ref= &join_tab->ref;
DBUG_ENTER("JOIN_CACHE_HASHED::init");
@ -2776,8 +2783,21 @@ int JOIN_CACHE_HASHED::init(bool for_explain)
key_length= ref->key_length;
if ((rc= JOIN_CACHE::init(for_explain)) || for_explain)
DBUG_RETURN (rc);
if (JOIN_CACHE::init(for_explain))
{
THD *thd= join->thd;
const char *errmsg=
"Could not create a join buffer. Please check and "
"adjust the value of the variables 'JOIN_BUFFER_SIZE (%llu)' and "
"'JOIN_BUFFER_SPACE_LIMIT (%llu)'";
my_printf_error(ER_OUTOFMEMORY, errmsg, MYF(0),
thd->variables.join_buff_size,
thd->variables.join_buff_space_limit);
DBUG_RETURN (1);
}
if (for_explain)
DBUG_RETURN(0);
if (!(key_buff= (uchar*) join->thd->alloc(key_length)))
DBUG_RETURN(1);