mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MWL#90: Subqueries: Inside-out execution for non-semijoin materialized subqueries that are AND-parts of the WHERE
- Address feedback - Code cleanup (not finished)
This commit is contained in:
@@ -5733,26 +5733,10 @@ Item_field* Item_equal::get_first(Item_field *field)
|
||||
It's a field from an materialized semi-join. We can substitute it only
|
||||
for a field from the same semi-join.
|
||||
*/
|
||||
#if 0
|
||||
psergey3:remove:
|
||||
JOIN_TAB *first;
|
||||
JOIN *join= field_tab->join;
|
||||
int tab_idx= field_tab - field_tab->join->join_tab;
|
||||
|
||||
/* Find the first table of this semi-join nest */
|
||||
for (int i= tab_idx; i >= (int)join->const_tables; i--)
|
||||
{
|
||||
if (join->join_tab[i].table->map & emb_nest->sj_inner_tables)
|
||||
first= join->join_tab + i;
|
||||
else
|
||||
// Found first tab that doesn't belong to current SJ.
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Find an item to substitute for. */
|
||||
while ((item= it++))
|
||||
{
|
||||
//if (item->field->table->reginfo.join_tab >= first)
|
||||
if (item->field->table->pos_in_table_list->embedding == emb_nest)
|
||||
{
|
||||
/*
|
||||
|
@@ -45,8 +45,8 @@
|
||||
exception that we don't care how many matches a row from outer_tbl has in
|
||||
inner_tbl.
|
||||
|
||||
In SQL, that translates into following: a semi-join subquery is an IN
|
||||
subquery that is an AND-part of the WHERE/ON clause.
|
||||
In SQL terms: a semi-join subquery is an IN subquery that is an AND-part of
|
||||
the WHERE/ON clause.
|
||||
|
||||
2. General idea about semi-join execution
|
||||
-----------------------------------------
|
||||
@@ -3957,8 +3957,8 @@ static void remove_subq_pushed_predicates(JOIN *join, Item **where)
|
||||
|
||||
bool join_tab_execution_startup(JOIN_TAB *tab)
|
||||
{
|
||||
DBUG_ENTER("join_tab_execution_startup");
|
||||
Item_in_subselect *in_subs;
|
||||
DBUG_ENTER("join_tab_execution_startup");
|
||||
if (tab->table->pos_in_table_list &&
|
||||
(in_subs= tab->table->pos_in_table_list->jtbm_subselect))
|
||||
{
|
||||
@@ -3995,13 +3995,9 @@ bool join_tab_execution_startup(JOIN_TAB *tab)
|
||||
if ((rc= sub_select(join, join_tab, FALSE/* no EOF */)) < 0 ||
|
||||
(rc= sub_select(join, join_tab, TRUE/* now EOF */)) < 0)
|
||||
{
|
||||
//psergey3-todo: set sjm->materialized=TRUE here, too??
|
||||
join->return_tab= save_return_tab;
|
||||
DBUG_RETURN(rc); /* it's NESTED_LOOP_(ERROR|KILLED)*/
|
||||
}
|
||||
/*
|
||||
Ok, materialization finished. Initialize the access to the temptable
|
||||
*/
|
||||
join->return_tab= save_return_tab;
|
||||
sjm->materialized= TRUE;
|
||||
}
|
||||
|
@@ -158,42 +158,6 @@ JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, bool include_bush_roots);
|
||||
|
||||
void JOIN_CACHE::calc_record_fields()
|
||||
{
|
||||
//psergey4-todo: prev_cache, or
|
||||
// - first non-const table if on top level
|
||||
// - first table inside SJM nest if within sjm nest
|
||||
// this->join_tab is 'our' join_tab
|
||||
|
||||
// No. the right idea: start from ... and walk to the current join_tab
|
||||
/// with an iterator, skipping
|
||||
// join nests (can do so for now)
|
||||
|
||||
/*
|
||||
The above sucks, too.
|
||||
The right idea:
|
||||
- for SJM-inner tables, walk only within the nest
|
||||
- for SJM-outer tables, use all preceding tables, including inner ones.
|
||||
eof
|
||||
*/
|
||||
|
||||
/* JOIN_TAB *tab = prev_cache ? prev_cache->join_tab :
|
||||
join->join_tab+join->const_tables;
|
||||
*/
|
||||
|
||||
/* JOIN_TAB *tab;
|
||||
if (prev_cache)
|
||||
tab= prev_cache->join_tab;
|
||||
else
|
||||
{
|
||||
if (tab->bush_root_tab)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
/ * top-level * /
|
||||
tab= join->join_tab+join->const_tables;
|
||||
}
|
||||
}*/
|
||||
JOIN_TAB *tab;
|
||||
if (prev_cache)
|
||||
tab= prev_cache->join_tab;
|
||||
@@ -201,12 +165,18 @@ void JOIN_CACHE::calc_record_fields()
|
||||
{
|
||||
if (join_tab->bush_root_tab)
|
||||
{
|
||||
// inside SJM-Mat nest: pick first one
|
||||
/*
|
||||
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
|
||||
{
|
||||
// outside SJM-Mat nest: start from first non-const table
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -1011,10 +1011,10 @@ JOIN::optimize()
|
||||
{
|
||||
List_iterator<JOIN_TAB_RANGE> it(join_tab_ranges);
|
||||
JOIN_TAB_RANGE *jt_range;
|
||||
bool first= TRUE;
|
||||
uint first_tab_offs= const_tables;
|
||||
while ((jt_range= it++))
|
||||
{
|
||||
for (JOIN_TAB *tab= jt_range->start + (first ? const_tables : 0);
|
||||
for (JOIN_TAB *tab= jt_range->start + first_tab_offs;
|
||||
tab < jt_range->end; tab++)
|
||||
{
|
||||
if (*tab->on_expr_ref)
|
||||
@@ -1025,7 +1025,7 @@ JOIN::optimize()
|
||||
(*tab->on_expr_ref)->update_used_tables();
|
||||
}
|
||||
}
|
||||
first= FALSE;
|
||||
first_tab_offs= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1298,9 +1298,11 @@ JOIN::optimize()
|
||||
*/
|
||||
if (need_tmp || select_distinct || group_list || order)
|
||||
{
|
||||
for (uint i = const_tables; i < tables; i++)
|
||||
for (uint i= 0; i < tables; i++)
|
||||
{
|
||||
if (!(table[i]->map & const_table_map))
|
||||
table[i]->prepare_for_position();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_EXECUTE("info",TEST_join(this););
|
||||
@@ -5871,7 +5873,6 @@ JOIN_TAB *first_linear_tab(JOIN *join, bool after_const_tables)
|
||||
first+= join->const_tables;
|
||||
if (first < join->join_tab + join->top_jtrange_tables)
|
||||
return first;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5888,24 +5889,24 @@ JOIN_TAB *first_linear_tab(JOIN *join, bool after_const_tables)
|
||||
to.)
|
||||
*/
|
||||
|
||||
JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, bool include_bush_roots) //psergey2: added
|
||||
JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, bool include_bush_roots)
|
||||
{
|
||||
if (include_bush_roots && tab->bush_children)
|
||||
return tab->bush_children->start;
|
||||
|
||||
DBUG_ASSERT(!tab->last_leaf_in_bush || tab->bush_root_tab);
|
||||
if (tab->last_leaf_in_bush)
|
||||
tab= tab->bush_root_tab;
|
||||
|
||||
if (tab->bush_root_tab)
|
||||
return ++tab;
|
||||
|
||||
if (++tab == join->join_tab + join->top_jtrange_tables /*join->join_tab_ranges.head()->end*/)
|
||||
if (++tab == join->join_tab + join->top_jtrange_tables)
|
||||
return NULL;
|
||||
|
||||
if (!include_bush_roots && tab->bush_children)
|
||||
{
|
||||
tab= tab->bush_children->start;
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
@@ -5929,12 +5930,12 @@ JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, bool include_bush_roots) //
|
||||
|
||||
*/
|
||||
|
||||
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab) //psergey2: added
|
||||
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab)
|
||||
{
|
||||
bool start= FALSE;
|
||||
if (tab == NULL)
|
||||
{
|
||||
/* This means we're starting. */
|
||||
/* This means we're starting the enumeration */
|
||||
if (join->const_tables == join->top_jtrange_tables)
|
||||
return NULL;
|
||||
|
||||
@@ -5945,7 +5946,11 @@ JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab) //psergey2: added
|
||||
if (tab->last_leaf_in_bush)
|
||||
return tab->bush_root_tab;
|
||||
|
||||
if ((start? tab: ++tab) == join->join_tab_ranges.head()->end)
|
||||
/* Move to next tab in the array we're traversing*/
|
||||
if (!start)
|
||||
tab++;
|
||||
|
||||
if (tab == join->join_tab_ranges.head()->end)
|
||||
return NULL; /* End */
|
||||
|
||||
if (tab->bush_children)
|
||||
@@ -5955,7 +5960,7 @@ JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab) //psergey2: added
|
||||
}
|
||||
|
||||
|
||||
static Item *null_ptr= NULL;
|
||||
static Item * const null_ptr= NULL;
|
||||
|
||||
/*
|
||||
Set up join struct according to the picked join order in
|
||||
@@ -6004,10 +6009,6 @@ get_best_combination(JOIN *join)
|
||||
|
||||
fix_semijoin_strategies_for_picked_join_order(join);
|
||||
|
||||
/*
|
||||
psergey2-todo: Here: switch to nested structure when copying.
|
||||
*/
|
||||
|
||||
JOIN_TAB_RANGE *root_range= new JOIN_TAB_RANGE;
|
||||
root_range->start= join->join_tab;
|
||||
/* root_range->end will be set later */
|
||||
@@ -6041,7 +6042,7 @@ get_best_combination(JOIN *join)
|
||||
j->ref.key_parts=0;
|
||||
j->loosescan_match_tab= NULL; //non-nulls will be set later
|
||||
j->use_join_cache= FALSE;
|
||||
j->on_expr_ref= &null_ptr;
|
||||
j->on_expr_ref= (Item**) &null_ptr;
|
||||
j->cache= NULL;
|
||||
|
||||
/*
|
||||
@@ -6363,9 +6364,6 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table)
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
|
||||
join_tab= parent->join_tab_reexec;
|
||||
//psergey2: hopefully this is ok:
|
||||
// join_tab_ranges.head()->start= join_tab;
|
||||
// join_tab_ranges.head()->end= join_tab + 1;
|
||||
top_jtrange_tables= 1;
|
||||
|
||||
table= &parent->table_reexec[0]; parent->table_reexec[0]= tmp_table;
|
||||
@@ -7701,21 +7699,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
|
||||
tab->sorted= sorted;
|
||||
sorted= 0; // only first must be sorted
|
||||
|
||||
|
||||
//if (sj_is_materialize_strategy(join->best_positions[i].sj_strategy))
|
||||
if (tab->bush_children) // SJM
|
||||
if (tab->bush_children)
|
||||
{
|
||||
/* This is a start of semi-join nest */
|
||||
//first_sjm_table= i;
|
||||
//last_sjm_table= i + join->best_positions[i].n_sj_tables;
|
||||
/*
|
||||
psergey2: dont:
|
||||
if (i == join->const_tables)
|
||||
join->first_select= sub_select_sjm;
|
||||
else
|
||||
tab[-1].next_select= sub_select_sjm;
|
||||
*/
|
||||
|
||||
if (setup_sj_materialization(tab))
|
||||
return TRUE;
|
||||
table= tab->table;
|
||||
@@ -12717,9 +12702,9 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(join->tables);
|
||||
error= join->first_select(join,join_tab,0);
|
||||
error= sub_select(join,join_tab,0);
|
||||
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
|
||||
error= join->first_select(join,join_tab,1);
|
||||
error= sub_select(join,join_tab,1);
|
||||
if (error == NESTED_LOOP_QUERY_LIMIT)
|
||||
error= NESTED_LOOP_OK; /* select_limit used */
|
||||
}
|
||||
|
@@ -190,8 +190,15 @@ typedef struct st_join_table {
|
||||
psergey2: for join tabs that are inside a bush: root of this bush.
|
||||
*/
|
||||
st_join_table *bush_root_tab;
|
||||
|
||||
/* TRUE <=> This join_tab is inside a join bush and is the last leaf tab here */
|
||||
bool last_leaf_in_bush;
|
||||
|
||||
/*
|
||||
ptr - this is a bush, and ptr points to description of child join_tab
|
||||
range
|
||||
NULL - this join tab has no bush children
|
||||
*/
|
||||
JOIN_TAB_RANGE *bush_children;
|
||||
|
||||
/* Special content for EXPLAIN 'Extra' column or NULL if none */
|
||||
@@ -500,13 +507,13 @@ protected:
|
||||
context can be accessed.
|
||||
*/
|
||||
JOIN *join;
|
||||
#if 0
|
||||
/*
|
||||
Cardinality of the range of join tables whose fields can be put into the
|
||||
cache. (A table from the range not necessarily contributes to the cache.)
|
||||
JOIN_TAB of the first table that can have it's fields in the join cache.
|
||||
That is, tables in the [start_tab, tab) range can have their fields in the
|
||||
join cache.
|
||||
If a join tab in the range represents an SJM-nest, then all tables from the
|
||||
nest can have their fields in the join cache, too.
|
||||
*/
|
||||
uint tables;
|
||||
#endif
|
||||
JOIN_TAB *start_tab;
|
||||
|
||||
/*
|
||||
@@ -1505,7 +1512,6 @@ public:
|
||||
|
||||
/* We also maintain a stack of join optimization states in * join->positions[] */
|
||||
/******* Join optimization state members end *******/
|
||||
Next_select_func first_select;
|
||||
/*
|
||||
The cost of best complete join plan found so far during optimization,
|
||||
after optimization phase - cost of picked join order (not taking into
|
||||
@@ -1691,7 +1697,6 @@ public:
|
||||
rollup.state= ROLLUP::STATE_NONE;
|
||||
|
||||
no_const_tables= FALSE;
|
||||
first_select= sub_select;
|
||||
}
|
||||
|
||||
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
|
||||
|
Reference in New Issue
Block a user