1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

MWL#90: Subqueries: Inside-out execution for materialized non-sj subqueries

- Merge with 5.3 (3)
This commit is contained in:
Sergey Petrunya
2011-02-15 20:29:57 +03:00
44 changed files with 4287 additions and 1810 deletions

View File

@ -33,7 +33,7 @@
#define NO_MORE_RECORDS_IN_BUFFER (uint)(-1)
void save_or_restore_used_tabs(JOIN_TAB *join_tab, bool save);
/*****************************************************************************
* Join cache module
******************************************************************************/
@ -138,50 +138,52 @@ uint add_table_data_fields_to_join_cache(JOIN_TAB *tab,
return len;
}
/*
Get the next table whose records are stored in the join buffer of this cache
JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, bool include_bush_roots);
SYNOPSIS
get_next_table()
tab the table for which the next table is to be returned
DESCRIPTION
For a given table whose records are stored in this cache the function
returns the next such table if there is any.
The function takes into account that the tables whose records are
are stored in the same cache now can interleave with tables from
materialized semijoin subqueries.
TODO
This function should be modified/simplified after the new code for
materialized semijoins is merged.
RETURN
The next join table whose records are stored in the buffer of this cache
if such table exists, 0 - otherwise
*/
JOIN_TAB *JOIN_CACHE::get_next_table(JOIN_TAB *tab)
{
if (++tab == join_tab)
return NULL;
if (join_tab->first_sjm_sibling)
return tab;
uint i= tab-join->join_tab;
/*
Temporary measure before MWL#90 refactorings are there: if 'tab' is at upper
level (i.e. it's not inside an SJM nest), still include into the join buffer
the tables from within SJM nest. We might need the subquery's select list
columns, because SJ-Materialization-Scan upacks data to those.
while (sj_is_materialize_strategy(join->best_positions[i].sj_strategy) &&
i < join->tables)
i+= join->best_positions[i].n_sj_tables;
*/
return join->join_tab+i < join_tab ? join->join_tab+i : NULL;
}
// /*
// Get the next table whose records are stored in the join buffer of this cache
//
// SYNOPSIS
// get_next_table()
// tab the table for which the next table is to be returned
//
// DESCRIPTION
// For a given table whose records are stored in this cache the function
// returns the next such table if there is any.
// The function takes into account that the tables whose records are
// are stored in the same cache now can interleave with tables from
// materialized semijoin subqueries.
//
// TODO
// This function should be modified/simplified after the new code for
// materialized semijoins is merged.
//
// RETURN
// The next join table whose records are stored in the buffer of this cache
// if such table exists, 0 - otherwise
// */
//
// JOIN_TAB *JOIN_CACHE::get_next_table(JOIN_TAB *tab)
// {
//
// if (++tab == join_tab)
// return NULL;
// if (join_tab->first_sjm_sibling)
// return tab;
// uint i= tab-join->join_tab;
// /*
// Temporary measure before MWL#90 refactorings are there: if 'tab' is at upper
// level (i.e. it's not inside an SJM nest), still include into the join buffer
// the tables from within SJM nest. We might need the subquery's select list
// columns, because SJ-Materialization-Scan upacks data to those.
//
// while (sj_is_materialize_strategy(join->best_positions[i].sj_strategy) &&
// i < join->tables)
// i+= join->best_positions[i].n_sj_tables;
//
// */
// return join->join_tab+i < join_tab ? join->join_tab+i : NULL;
// }
/*
@ -203,12 +205,38 @@ JOIN_TAB *JOIN_CACHE::get_next_table(JOIN_TAB *tab)
void JOIN_CACHE::calc_record_fields()
{
JOIN_TAB *tab;
/**
psergey-merge: was:
JOIN_TAB *tab = prev_cache ? prev_cache->join_tab :
(join_tab->first_sjm_sibling ?
join_tab->first_sjm_sibling :
join->join_tab+join->const_tables);
tables= join_tab-tab;
**/
if (prev_cache)
tab= prev_cache->join_tab;
else
{
if (join_tab->bush_root_tab)
{
/*
If the tab we're attached to is inside an SJM-nest, start from the
first tab in that SJM nest
*/
tab= join_tab->bush_root_tab->bush_children->start;
}
else
{
/*
The tab we're attached to is not inside an SJM-nest. Start from the
first non-const table.
*/
tab= join->join_tab + join->const_tables;
}
}
start_tab= tab;
//tables= join_tab-tab;
//tables= 0;
fields= 0;
blobs= 0;
flag_fields= 0;
@ -216,7 +244,12 @@ void JOIN_CACHE::calc_record_fields()
data_field_ptr_count= 0;
referenced_fields= 0;
for ( ; tab ; tab= get_next_table(tab))
//psergey-merge: for ( ; tab ; tab= get_next_table(tab))
/*
The following loop will get inside SJM nests, because data may be unpacked
to sjm-inner tables.
*/
for ( ; tab != join_tab ; tab= next_linear_tab(join, tab, TRUE))
{
tab->calc_used_field_length(FALSE);
flag_fields+= test(tab->used_null_fields || tab->used_uneven_bit_fields);
@ -225,6 +258,7 @@ void JOIN_CACHE::calc_record_fields()
blobs+= tab->used_blobs;
fields+= tab->check_rowid_field();
//tables++;
}
if ((with_match_flag= join_tab->use_match_flag()))
flag_fields++;
@ -245,7 +279,8 @@ void JOIN_CACHE::calc_record_fields()
that occur in the ref expressions and marks these fields in the bitmap
tab->table->tmp_set. The function counts the number of them stored
in this cache and the total number of them stored in the previous caches
and saves the results of the counting in 'local_key_arg_fields' and 'external_key_arg_fields' respectively.
and saves the results of the counting in 'local_key_arg_fields' and
'external_key_arg_fields' respectively.
NOTES
The function does not do anything if no key is used to join the records
@ -269,8 +304,14 @@ void JOIN_CACHE::collect_info_on_key_args()
cache= this;
do
{
for (tab= cache->join_tab-cache->tables; tab ;
tab= cache->get_next_table(tab))
/*
psergey-merge:
tab"=start_tab" is not a correct substitute for
"cache->join_tab - cache->tables".
*/
for (tab= cache->start_tab; tab != cache->join_tab; tab= next_linear_tab(join, tab, TRUE))
//for (tab= cache->join_tab-cache->tables; tab ;
// tab= cache->get_next_table(tab))
{
uint key_args;
bitmap_clear_all(&tab->table->tmp_set);
@ -386,7 +427,9 @@ void JOIN_CACHE::create_flag_fields()
&copy);
/* Create fields for all null bitmaps and null row flags that are needed */
for (tab= join_tab-tables; tab; tab= get_next_table(tab))
// // psergey-merge: for (tab= join_tab-tables; tab; tab= get_next_table(tab))
//for (tab= join_tab-tables; tab < join_tab; tab++)
for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
{
TABLE *table= tab->table;
@ -473,8 +516,11 @@ void JOIN_CACHE::create_key_arg_fields()
while (ext_key_arg_cnt)
{
cache= cache->prev_cache;
for (tab= cache->join_tab-cache->tables; tab;
tab= cache->get_next_table(tab))
//for (tab= cache->join_tab-cache->tables; tab;
// tab= cache->get_next_table(tab))
//psergey-merge: ^
for (tab= cache->start_tab; tab != cache->join_tab;
tab= next_linear_tab(join, tab, TRUE))
{
CACHE_FIELD *copy_end;
MY_BITMAP *key_read_set= &tab->table->tmp_set;
@ -524,7 +570,8 @@ void JOIN_CACHE::create_key_arg_fields()
/* Now create local fields that are used to build ref for this key access */
copy= field_descr+flag_fields;
for (tab= join_tab-tables; tab; tab= get_next_table(tab))
for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
//for (tab= join_tab-tables; tab; tab= get_next_table(tab))
{
length+= add_table_data_fields_to_join_cache(tab, &tab->table->tmp_set,
&data_field_count, &copy,
@ -573,14 +620,16 @@ void JOIN_CACHE::create_key_arg_fields()
none
*/
void JOIN_CACHE:: create_remaining_fields()
void JOIN_CACHE::create_remaining_fields()
{
JOIN_TAB *tab;
bool all_read_fields= !is_key_access();
CACHE_FIELD *copy= field_descr+flag_fields+data_field_count;
CACHE_FIELD **copy_ptr= blob_ptr+data_field_ptr_count;
for (tab= join_tab-tables; tab; tab= get_next_table(tab))
for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
//psergey-merge: for (tab= join_tab-tables; tab; tab= get_next_table(tab))
//for (tab= join_tab-tables; tab < join_tab; tab++)
{
MY_BITMAP *rem_field_set;
TABLE *table= tab->table;
@ -737,7 +786,8 @@ ulong JOIN_CACHE::get_min_join_buffer_size()
if (!min_buff_size)
{
ulong len= 0;
for (JOIN_TAB *tab= join_tab-tables; tab < join_tab; tab++)
//for (JOIN_TAB *tab= join_tab-tables; tab < join_tab; tab++)
for (JOIN_TAB *tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
len+= tab->get_max_used_fieldlength();
len+= get_record_max_affix_length() + get_max_key_addon_space_per_record();
ulong min_sz= len*min_records;
@ -785,7 +835,8 @@ ulong JOIN_CACHE::get_max_join_buffer_size()
ulong max_sz;
ulong min_sz= get_min_join_buffer_size();
ulong len= 0;
for (JOIN_TAB *tab= join_tab-tables; tab < join_tab; tab++)
//for (JOIN_TAB *tab= join_tab-tables; tab < join_tab; tab++)
for (JOIN_TAB *tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
len+= tab->get_used_fieldlength();
len+= get_record_max_affix_length();
avg_record_length= len;
@ -853,7 +904,11 @@ int JOIN_CACHE::alloc_buffer()
set_if_bigger(max_records, 10);
min_buff_size= get_min_join_buffer_size();
buff_size= get_max_join_buffer_size();
for (tab= join->join_tab+join->const_tables; tab <= join_tab; tab++)
//psergey-merge: for (tab= join->join_tab+join->const_tables; tab <= join_tab; tab++)
// for (tab= cache->join_tab-cache->tables; tab < cache->join_tab ; tab++)
// (fixed)
for (tab= join->join_tab + join->const_tables; tab!= join_tab;
tab= next_linear_tab(join, tab, TRUE))
{
cache= tab->cache;
if (cache)
@ -984,6 +1039,7 @@ int JOIN_CACHE::realloc_buffer()
*/
int JOIN_CACHE::init()
//psergey-merge:wtf is this here: for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, TRUE))
{
DBUG_ENTER("JOIN_CACHE::init");
@ -2143,8 +2199,12 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
}
/* Prepare to retrieve all records of the joined table */
if ((error= join_tab_scan->open()))
if ((error= join_tab_scan->open())) //psergey-merge: TODO: look what it does inside? status-reset should use next_linear_tab
goto finish; /* psergey-note: if this returns error, we will assert in net_send_statement() */
if ((rc= join_tab_execution_startup(join_tab)) < 0)
goto finish;
while (!(error= join_tab_scan->next()))
{
@ -3179,12 +3239,23 @@ uint JOIN_CACHE_HASHED::get_next_key(uchar ** key)
int JOIN_TAB_SCAN::open()
{
JOIN_TAB *bound= join_tab-cache->tables;
//psergey-merge: todo: check the below:
//JOIN_TAB *bound= join_tab-cache->tables;
#if 0
JOIN_TAB *bound= cache->start_tab;
// psergey-todo-merge: can we really iterate backwards?
// Q: is there really a need to iterate backwards?
for (JOIN_TAB *tab= join_tab-1; tab != bound && !tab->cache; tab--)
{
tab->status= tab->table->status;
tab->table->status= 0;
}
#endif
save_or_restore_used_tabs(join_tab, FALSE);
is_first_record= TRUE;
return join_init_read_record(join_tab);
}
@ -3239,6 +3310,40 @@ int JOIN_TAB_SCAN::next()
}
void save_or_restore_used_tabs(JOIN_TAB *join_tab, bool save)
{
JOIN_TAB *first= join_tab->bush_root_tab?
join_tab->bush_root_tab->bush_children->start :
join_tab->join->join_tab + join_tab->join->const_tables;
for (JOIN_TAB *tab= join_tab-1; tab != first && !tab->cache; tab--)
{
if (tab->bush_children)
{
for (JOIN_TAB *child= tab->bush_children->start;
child != tab->bush_children->end;
child++)
{
if (save)
child->table->status= child->status;
{
tab->status= tab->table->status;
tab->table->status= 0;
}
}
}
if (save)
tab->table->status= tab->status;
else
{
tab->status= tab->table->status;
tab->table->status= 0;
}
}
}
/*
Perform finalizing actions for a scan over the table records
@ -3255,9 +3360,12 @@ int JOIN_TAB_SCAN::next()
void JOIN_TAB_SCAN::close()
{
JOIN_TAB *bound= join_tab-cache->tables;
#if 0
JOIN_TAB *bound= join_tab - cache->tables;
for (JOIN_TAB *tab= join_tab-1; tab != bound && !tab->cache; tab--)
tab->table->status= tab->status;
#endif
save_or_restore_used_tabs(join_tab, TRUE);
}
@ -3657,12 +3765,16 @@ int JOIN_TAB_SCAN_MRR::open()
/* Dynamic range access is never used with BKA */
DBUG_ASSERT(join_tab->use_quick != 2);
JOIN_TAB *bound= join_tab-cache->tables;
/*
psergey-merge: done?
JOIN_TAB *bound= join_tab - cache->tables;
for (JOIN_TAB *tab= join_tab-1; tab != bound && !tab->cache; tab--)
{
tab->status= tab->table->status;
tab->table->status= 0;
}
*/
save_or_restore_used_tabs(join_tab, FALSE);
init_mrr_buff();