mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge 5.5-main -> 5.5-show-explain
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates.
|
||||
2009-2011 Monty Program Ab
|
||||
/* Copyright (c) 2000, 2012 Oracle and/or its affiliates.
|
||||
Copyright (c) 2009, 2012, Monty Program Ab
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -271,6 +271,8 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
|
||||
bool *inherited_fl);
|
||||
JOIN_TAB *first_depth_first_tab(JOIN* join);
|
||||
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
|
||||
JOIN_TAB *first_breadth_first_tab(JOIN *join);
|
||||
JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
|
||||
@ -1045,7 +1047,10 @@ JOIN::optimize_inner()
|
||||
}
|
||||
|
||||
eval_select_list_used_tables();
|
||||
|
||||
|
||||
if (optimize_constant_subqueries())
|
||||
DBUG_RETURN(1);
|
||||
|
||||
table_count= select_lex->leaf_tables.elements;
|
||||
|
||||
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
|
||||
@ -1332,6 +1337,12 @@ JOIN::optimize_inner()
|
||||
{
|
||||
conds= substitute_for_best_equal_field(NO_PARTICULAR_TAB, conds,
|
||||
cond_equal, map2table);
|
||||
if (thd->is_error())
|
||||
{
|
||||
error= 1;
|
||||
DBUG_PRINT("error",("Error from substitute_for_best_equal"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
conds->update_used_tables();
|
||||
DBUG_EXECUTE("where",
|
||||
print_where(conds,
|
||||
@ -1352,6 +1363,12 @@ JOIN::optimize_inner()
|
||||
*tab->on_expr_ref,
|
||||
tab->cond_equal,
|
||||
map2table);
|
||||
if (thd->is_error())
|
||||
{
|
||||
error= 1;
|
||||
DBUG_PRINT("error",("Error from substitute_for_best_equal"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
(*tab->on_expr_ref)->update_used_tables();
|
||||
}
|
||||
}
|
||||
@ -6702,6 +6719,32 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Estimate the number of rows that query execution will read.
|
||||
|
||||
@todo This is a very pessimistic upper bound. Use join selectivity
|
||||
when available to produce a more realistic number.
|
||||
*/
|
||||
|
||||
double JOIN::get_examined_rows()
|
||||
{
|
||||
ha_rows examined_rows;
|
||||
double prev_fanout= 1;
|
||||
JOIN_TAB *tab= first_breadth_first_tab(this);
|
||||
JOIN_TAB *prev_tab= tab;
|
||||
|
||||
examined_rows= tab->get_examined_rows();
|
||||
|
||||
while ((tab= next_breadth_first_tab(this, tab)))
|
||||
{
|
||||
prev_fanout *= prev_tab->records_read;
|
||||
examined_rows+= tab->get_examined_rows() * prev_fanout;
|
||||
prev_tab= tab;
|
||||
}
|
||||
return examined_rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Find a good, possibly optimal, query execution plan (QEP) by a possibly
|
||||
exhaustive search.
|
||||
@ -8174,36 +8217,15 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
|
||||
row_limit= unit->select_limit_cnt;
|
||||
do_send_rows= row_limit ? 1 : 0;
|
||||
|
||||
join_tab->use_join_cache= FALSE;
|
||||
join_tab->cache=0; /* No caching */
|
||||
bzero(join_tab, sizeof(JOIN_TAB));
|
||||
join_tab->table=temp_table;
|
||||
join_tab->cache_select= 0;
|
||||
join_tab->select=0;
|
||||
join_tab->select_cond= 0; // Avoid valgrind warning
|
||||
join_tab->set_select_cond(NULL, __LINE__);
|
||||
join_tab->quick=0;
|
||||
join_tab->type= JT_ALL; /* Map through all records */
|
||||
join_tab->keys.init();
|
||||
join_tab->keys.set_all(); /* test everything in quick */
|
||||
join_tab->info=0;
|
||||
join_tab->on_expr_ref=0;
|
||||
join_tab->last_inner= 0;
|
||||
join_tab->first_unmatched= 0;
|
||||
join_tab->ref.key = -1;
|
||||
join_tab->not_used_in_distinct=0;
|
||||
join_tab->read_first_record= join_init_read_record;
|
||||
join_tab->preread_init_done= FALSE;
|
||||
join_tab->join= this;
|
||||
join_tab->ref.key_parts= 0;
|
||||
join_tab->keep_current_rowid= FALSE;
|
||||
join_tab->flush_weedout_table= join_tab->check_weed_out_table= NULL;
|
||||
join_tab->do_firstmatch= NULL;
|
||||
join_tab->loosescan_match_tab= NULL;
|
||||
join_tab->emb_sj_nest= NULL;
|
||||
join_tab->pre_idx_push_select_cond= NULL;
|
||||
join_tab->bush_root_tab= NULL;
|
||||
join_tab->bush_children= NULL;
|
||||
join_tab->last_leaf_in_bush= FALSE;
|
||||
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
|
||||
temp_table->status=0;
|
||||
temp_table->null_row=0;
|
||||
@ -10401,6 +10423,51 @@ double JOIN_TAB::scan_time()
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Estimate the number of rows that a an access method will read from a table.
|
||||
|
||||
@todo: why not use JOIN_TAB::found_records
|
||||
*/
|
||||
|
||||
ha_rows JOIN_TAB::get_examined_rows()
|
||||
{
|
||||
ha_rows examined_rows;
|
||||
|
||||
if (select && select->quick)
|
||||
examined_rows= select->quick->records;
|
||||
else if (type == JT_NEXT || type == JT_ALL ||
|
||||
type == JT_HASH || type ==JT_HASH_NEXT)
|
||||
{
|
||||
if (limit)
|
||||
{
|
||||
/*
|
||||
@todo This estimate is wrong, a LIMIT query may examine much more rows
|
||||
than the LIMIT itself.
|
||||
*/
|
||||
examined_rows= limit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (table->is_filled_at_execution())
|
||||
examined_rows= records;
|
||||
else
|
||||
{
|
||||
/*
|
||||
handler->info(HA_STATUS_VARIABLE) has been called in
|
||||
make_join_statistics()
|
||||
*/
|
||||
examined_rows= table->file->stats.records;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
examined_rows= (ha_rows) records_read;
|
||||
|
||||
return examined_rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the join_tab before reading.
|
||||
Currently only derived table/view materialization is done here.
|
||||
@ -10718,6 +10785,22 @@ void JOIN::cleanup(bool full)
|
||||
tmp_join->tmp_table_param.save_copy_field= 0;
|
||||
}
|
||||
tmp_table_param.cleanup();
|
||||
|
||||
if (!join_tab)
|
||||
{
|
||||
List_iterator<TABLE_LIST> li(*join_list);
|
||||
TABLE_LIST *table_ref;
|
||||
while ((table_ref= li++))
|
||||
{
|
||||
if (table_ref->table &&
|
||||
table_ref->jtbm_subselect &&
|
||||
table_ref->jtbm_subselect->is_jtbm_const_tab)
|
||||
{
|
||||
free_tmp_table(thd, table_ref->table);
|
||||
table_ref->table= NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -11394,9 +11477,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
|
||||
if (!item)
|
||||
{
|
||||
Item_func_eq *eq_item;
|
||||
if ((eq_item= new Item_func_eq(orig_left_item, orig_right_item)))
|
||||
if (!(eq_item= new Item_func_eq(orig_left_item, orig_right_item)) ||
|
||||
eq_item->set_cmp_func())
|
||||
return FALSE;
|
||||
eq_item->set_cmp_func();
|
||||
eq_item->quick_fix_field();
|
||||
item= eq_item;
|
||||
}
|
||||
@ -11489,9 +11572,9 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
|
||||
if (!is_converted)
|
||||
{
|
||||
Item_func_eq *eq_item;
|
||||
if (!(eq_item= new Item_func_eq(left_item, right_item)))
|
||||
if (!(eq_item= new Item_func_eq(left_item, right_item)) ||
|
||||
eq_item->set_cmp_func())
|
||||
return FALSE;
|
||||
eq_item->set_cmp_func();
|
||||
eq_item->quick_fix_field();
|
||||
eq_list->push_back(eq_item);
|
||||
}
|
||||
@ -12177,9 +12260,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
|
||||
|
||||
eq_item= new Item_func_eq(field_item->real_item(), head_item);
|
||||
|
||||
if (!eq_item)
|
||||
if (!eq_item || eq_item->set_cmp_func())
|
||||
return 0;
|
||||
eq_item->set_cmp_func();
|
||||
eq_item->quick_fix_field();
|
||||
}
|
||||
current_sjm= field_sjm;
|
||||
@ -12266,7 +12348,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
|
||||
Item_equal::get_first() for details.
|
||||
|
||||
@return
|
||||
The transformed condition
|
||||
The transformed condition, or NULL in case of error
|
||||
*/
|
||||
|
||||
static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab,
|
||||
@ -18737,8 +18819,6 @@ check_reverse_order:
|
||||
join_read_first:join_read_last;
|
||||
tab->type=JT_NEXT; // Read with index_first(), index_next()
|
||||
|
||||
if (table->covering_keys.is_set(best_key) && ! table->key_read)
|
||||
table->enable_keyread();
|
||||
if (tab->pre_idx_push_select_cond)
|
||||
{
|
||||
tab->set_cond(tab->pre_idx_push_select_cond);
|
||||
@ -18749,6 +18829,7 @@ check_reverse_order:
|
||||
orig_cond= 0;
|
||||
orig_cond_saved= false;
|
||||
}
|
||||
|
||||
table->file->ha_index_or_rnd_end();
|
||||
if (tab->join->select_options & SELECT_DESCRIBE)
|
||||
{
|
||||
@ -18756,6 +18837,7 @@ check_reverse_order:
|
||||
tab->ref.key_parts= 0;
|
||||
if (select_limit < table->file->stats.records)
|
||||
tab->limit= select_limit;
|
||||
table->disable_keyread();
|
||||
}
|
||||
}
|
||||
else if (tab->type != JT_ALL)
|
||||
@ -20469,6 +20551,8 @@ copy_fields(TMP_TABLE_PARAM *param)
|
||||
Copy_field *ptr=param->copy_field;
|
||||
Copy_field *end=param->copy_field_end;
|
||||
|
||||
DBUG_ASSERT((ptr != NULL && end >= ptr) || (ptr == NULL && end == NULL));
|
||||
|
||||
for (; ptr != end; ptr++)
|
||||
(*ptr->do_copy)(ptr);
|
||||
|
||||
@ -21676,10 +21760,17 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
|
||||
}
|
||||
else
|
||||
{
|
||||
TABLE_LIST *real_table= table->pos_in_table_list;
|
||||
item_list.push_back(new Item_string(real_table->alias,
|
||||
strlen(real_table->alias),
|
||||
cs));
|
||||
TABLE_LIST *real_table= table->pos_in_table_list;
|
||||
/*
|
||||
Internal temporary tables have no corresponding table reference
|
||||
object. Such a table may appear in EXPLAIN when a subquery that needs
|
||||
a temporary table has been executed, and JOIN::exec replaced the
|
||||
original JOIN with a plan to access the data in the temp table
|
||||
(made by JOIN::make_simple_join).
|
||||
*/
|
||||
const char *tab_name= real_table ? real_table->alias :
|
||||
"internal_tmp_table";
|
||||
item_list.push_back(new Item_string(tab_name, strlen(tab_name), cs));
|
||||
}
|
||||
/* "partitions" column */
|
||||
if (explain_flags & DESCRIBE_PARTITIONS)
|
||||
@ -21844,32 +21935,8 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
|
||||
}
|
||||
else
|
||||
{
|
||||
ha_rows examined_rows;
|
||||
if (tab->select && quick)
|
||||
examined_rows= quick->records;
|
||||
else if (tab_type == JT_NEXT || tab_type == JT_ALL || is_hj)
|
||||
{
|
||||
if (tab->limit)
|
||||
examined_rows= tab->limit;
|
||||
else
|
||||
{
|
||||
if (tab->table->is_filled_at_execution())
|
||||
{
|
||||
examined_rows= tab->records;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
handler->info(HA_STATUS_VARIABLE) has been called in
|
||||
make_join_statistics()
|
||||
*/
|
||||
examined_rows= tab->table->file->stats.records;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
examined_rows=(ha_rows)tab->records_read;
|
||||
|
||||
ha_rows examined_rows= tab->get_examined_rows();
|
||||
|
||||
item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS));
|
||||
|
||||
|
Reference in New Issue
Block a user