diff options
Diffstat (limited to 'sql/sql_join_cache.cc')
-rw-r--r-- | sql/sql_join_cache.cc | 228 |
1 files changed, 128 insertions, 100 deletions
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index beca5fc782a..7d61ce31cca 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -634,7 +634,7 @@ void JOIN_CACHE::create_remaining_fields() /* - Calculate and set all cache constants + Calculate and set all cache constants SYNOPSIS set_constants() @@ -694,16 +694,22 @@ void JOIN_CACHE::set_constants() (prev_cache ? prev_cache->get_size_of_rec_offset() : 0) + length + fields*sizeof(uint); pack_length_with_blob_ptrs= pack_length + blobs*sizeof(uchar *); - min_buff_size= 0; min_records= 1; + min_buff_size= get_min_join_buffer_size(); buff_size= (size_t)MY_MAX(join->thd->variables.join_buff_size, - get_min_join_buffer_size()); + min_buff_size); size_of_rec_ofs= offset_size(buff_size); size_of_rec_len= blobs ? size_of_rec_ofs : offset_size(len); size_of_fld_ofs= size_of_rec_len; base_prefix_length= (with_length ? size_of_rec_len : 0) + (prev_cache ? prev_cache->get_size_of_rec_offset() : 0); - /* + /* + Call ge_min_join_buffer_size() again as the size may have got smaller + if size_of_rec_ofs or some other variable changed since last call. + */ + min_buff_size= 0; + min_buff_size= get_min_join_buffer_size(); + /* The size of the offsets for referenced fields will be added later. The values of 'pack_length' and 'pack_length_with_blob_ptrs' are adjusted every time when the first reference to the referenced field is registered. @@ -767,30 +773,29 @@ uint JOIN_CACHE::get_record_max_affix_length() size_t JOIN_CACHE::get_min_join_buffer_size() { - if (!min_buff_size) + if (min_buff_size) + return min_buff_size; // use cached value + + size_t len= 0, len_last= 0, len_addon, min_sz, add_sz= 0; + + for (JOIN_TAB *tab= start_tab; tab != join_tab; + tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) { - size_t len= 0; - size_t len_last= 0; - for (JOIN_TAB *tab= start_tab; tab != join_tab; - tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) - { - len+= tab->get_max_used_fieldlength(); - len_last+= tab->get_used_fieldlength(); - } - size_t len_addon= get_record_max_affix_length() + - get_max_key_addon_space_per_record(); - len+= len_addon; - len_last+= len_addon; - size_t min_sz= len*(min_records-1) + len_last; - min_sz+= pack_length_with_blob_ptrs; - size_t add_sz= 0; - for (uint i=0; i < min_records; i++) - add_sz+= join_tab_scan->aux_buffer_incr(i+1); - avg_aux_buffer_incr= add_sz/min_records; - min_sz+= add_sz; - set_if_bigger(min_sz, 1); - min_buff_size= min_sz; + len+= tab->get_max_used_fieldlength(); + len_last+= tab->get_used_fieldlength(); } + len_addon= (get_record_max_affix_length() + + get_max_key_addon_space_per_record()); + len+= len_addon; + len_last+= len_addon; + min_sz= len*(min_records-1) + len_last; + min_sz+= pack_length_with_blob_ptrs; + for (uint i=0; i < min_records; i++) + add_sz+= join_tab_scan->aux_buffer_incr(i+1); + avg_aux_buffer_incr= add_sz/min_records; + min_sz+= add_sz; + set_if_bigger(min_sz, 1); + min_buff_size= min_sz; return min_buff_size; } @@ -805,61 +810,67 @@ 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 */ -size_t JOIN_CACHE::get_max_join_buffer_size(bool optimize_buff_size) +size_t JOIN_CACHE::get_max_join_buffer_size(bool optimize_buff_size, + size_t min_sz) { - if (!max_buff_size) + if (max_buff_size) + return max_buff_size; // use cached value + + size_t limit_sz= (size_t) join->thd->variables.join_buff_size; + + if (!optimize_buff_size) + return max_buff_size= limit_sz; + + size_t max_sz; + size_t len= 0; + double max_records, partial_join_cardinality= + (join_tab-1)->get_partial_join_cardinality(); + /* Expected join buffer space used for one record */ + size_t space_per_record; + + for (JOIN_TAB *tab= start_tab; tab != join_tab; + tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) { - size_t max_sz; - size_t min_sz= get_min_join_buffer_size(); - size_t len= 0; - for (JOIN_TAB *tab= start_tab; tab != join_tab; - tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) - { - len+= tab->get_used_fieldlength(); - } - len+= get_record_max_affix_length(); - avg_record_length= len; - len+= get_max_key_addon_space_per_record() + avg_aux_buffer_incr; - 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 - { - if (limit_sz / max_records > space_per_record) - max_sz= space_per_record * max_records; - else - max_sz= limit_sz; - max_sz+= pack_length_with_blob_ptrs; - set_if_smaller(max_sz, limit_sz); - } - set_if_bigger(max_sz, min_sz); - max_buff_size= max_sz; + len+= tab->get_used_fieldlength(); } + len+= get_record_max_affix_length(); + avg_record_length= len; + len+= get_max_key_addon_space_per_record() + avg_aux_buffer_incr; + space_per_record= len; + + /* Note that space_per_record can be 0 if no table fields where used */ + max_records= (double) (limit_sz / MY_MAX(space_per_record, 1)); + set_if_smaller(max_records, partial_join_cardinality); + set_if_bigger(max_records, 10.0); + + if ((size_t) (limit_sz / max_records) > space_per_record) + max_sz= space_per_record * (size_t) max_records; + else + max_sz= limit_sz; + max_sz+= pack_length_with_blob_ptrs; + set_if_smaller(max_sz, limit_sz); + + set_if_bigger(max_sz, min_sz); + max_buff_size= max_sz; return max_buff_size; -} +} /* @@ -899,16 +910,8 @@ int JOIN_CACHE::alloc_buffer() join->thd->variables.join_buff_space_limit; bool optimize_buff_size= optimizer_flag(join->thd, OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE); - double partial_join_cardinality= (join_tab-1)->get_partial_join_cardinality(); buff= NULL; - min_buff_size= 0; - max_buff_size= 0; - min_records= 1; - max_records= (size_t) (partial_join_cardinality <= join_buff_space_limit ? - (ulonglong) partial_join_cardinality : join_buff_space_limit); - set_if_bigger(max_records, 10); - min_buff_size= get_min_join_buffer_size(); - buff_size= get_max_join_buffer_size(optimize_buff_size); + buff_size= get_max_join_buffer_size(optimize_buff_size, min_buff_size); for (tab= start_tab; tab!= join_tab; tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) @@ -923,13 +926,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; @@ -1079,18 +1094,19 @@ int JOIN_CACHE::init(bool for_explain) /* - Check the possibility to read the access keys directly from the join buffer + Check the possibility to read the access keys directly from the join buffer SYNOPSIS check_emb_key_usage() DESCRIPTION - The function checks some conditions at which the key values can be read - directly from the join buffer. This is possible when the key values can be - composed by concatenation of the record fields stored in the join buffer. - Sometimes when the access key is multi-component the function has to re-order - the fields written into the join buffer to make keys embedded. If key - values for the key access are detected as embedded then 'use_emb_key' - is set to TRUE. + The function checks some conditions at which the key values can be + read directly from the join buffer. This is possible when the key + values can be composed by concatenation of the record fields + stored in the join buffer. Sometimes when the access key is + multi-component the function has to re-order the fields written + into the join buffer to make keys embedded. If key values for the + key access are detected as embedded then 'use_emb_key' is set to + TRUE. EXAMPLE Let table t2 has an index defined on the columns a,b . Let's assume also @@ -1243,7 +1259,7 @@ bool JOIN_CACHE::check_emb_key_usage() trailing spaces - significant part of fixed length fields that can have trailing spaces with the prepanded length - - data of non-blob variable length fields with the prepanded data length + - data of non-blob variable length fields with the prepanded data length - blob data from blob fields with the prepanded data length (5) record offset values for the data fields that are referred to from other caches @@ -1314,7 +1330,7 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) Check whether we won't be able to add any new record into the cache after this one because the cache will be full. Set last_record to TRUE if it's so. The assume that the cache will be full after the record has been written - into it if either the remaining space of the cache is not big enough for the + into it if either the remaining space of the cache is not big enough for the record's blob values or if there is a chance that not all non-blob fields of the next record can be placed there. This function is called only in the case when there is enough space left in @@ -1336,7 +1352,7 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) /* Put a reference to the fields of the record that are stored in the previous - cache if there is any. This reference is passed by the 'link' parameter. + cache if there is any. This reference is passed by the 'link' parameter. */ if (prev_cache) { @@ -2766,7 +2782,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 +2791,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); |