diff options
-rw-r--r-- | mysql-test/disabled.def | 2 | ||||
-rw-r--r-- | mysql-test/r/view.result | 2 | ||||
-rw-r--r-- | sql/sql_delete.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 182 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 652 | ||||
-rw-r--r-- | sql/sql_union.cc | 6 |
7 files changed, 123 insertions, 727 deletions
diff --git a/mysql-test/disabled.def b/mysql-test/disabled.def index 4133eb2a12c..d9f8f15cfff 100644 --- a/mysql-test/disabled.def +++ b/mysql-test/disabled.def @@ -16,4 +16,4 @@ read_many_rows_innodb : Bug#11748886 2010-11-15 mattiasj report already exist archive-big : Bug#11817185 2011-03-10 Anitha Disabled since this leads to timeout on Solaris Sparc log_tables-big : Bug#11756699 2010-11-15 mattiasj report already exists mysql_embedded : Bug#12561297 2011-05-14 Anitha Dependent on PB2 changes - eventum#41836 -show_explain : Psergey: random timeout in range-checked-for-each record query. +#show_explain : Psergey: random timeout in range-checked-for-each record query. diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 7fc2fa72805..bc286c36655 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3584,7 +3584,7 @@ View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` FORCE INDEX (PRIMARY) FORCE INDEX (`b`) order by `t1`.`a` latin1 latin1_swedish_ci EXPLAIN SELECT * FROM v1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 15 +1 SIMPLE t1 ALL NULL NULL NULL NULL 15 CREATE VIEW v2 AS SELECT * FROM t1 USE KEY () ORDER BY a; SHOW CREATE VIEW v2; View Create View character_set_client collation_connection diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 30ae60ddc43..50401e2af46 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -159,7 +159,9 @@ void Update_plan::save_query_plan_footprint_intern(QPF_query *query, QPF_update qpf->add_child(unit->first_select()->select_number); //TODO: temporary?: - unit->save_qpf(query); + // A: yes. optimizing children subqueries has caused them to save QPFs, + // automatically. + //unit->save_qpf(query); } } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df38d9fcdb0..c453a599dce 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4172,29 +4172,32 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) return all_merged; } +/* + This is used by SHOW EXPLAIN. It assuses query plan has been already + collected into QPF structures and we only need to print it out. +*/ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, - bool *printed_anything) + bool *printed_anything) //TODO: remove printed_anything { - /* if (upd_del_plan) + int res; + if (query_plan_footprint) { - upd_del_plan->print_explain(output, explain_flags, printed_anything); - return 0; - }*/ - //int res= unit.print_explain(output, explain_flags, printed_anything); - - //psergey-todo: here, we should make Query Plan Footprint, and then produce - // an EXPLAIN output from it. - /* - The new, QueryPlanFootprint way: - */ - QPF_query qpf; - unit.save_qpf(&qpf); - //return res; - return 0; + res= query_plan_footprint->print_explain(output, explain_flags); + *printed_anything= true; + } + else + { + res= 0; + *printed_anything= false; + } + return res; } +/* + +*/ void st_select_lex::save_qpf(QPF_query *output) { int res; @@ -4261,92 +4264,12 @@ err: return ;//res; } -#if 0 -int st_select_lex::print_explain(select_result_sink *output, - uint8 explain_flags, - bool *printed_anything) -{ - int res; - if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) - { - /* - There is a number of reasons join can be marked as degenerate, so all - three conditions below can happen simultaneously, or individually: - */ - *printed_anything= TRUE; - if (!join->table_count || !join->tables_list || join->zero_result_cause) - { - /* It's a degenerate join */ - const char *cause= join->zero_result_cause ? join-> zero_result_cause : - "No tables used"; - res= join->print_explain(output, explain_flags, TRUE, FALSE, FALSE, - FALSE, cause); - } - else - { - res= join->print_explain(output, explain_flags, TRUE, - join->need_tmp, // need_tmp_table - !join->skip_sort_order && !join->no_order && - (join->order || join->group_list), // bool need_order - join->select_distinct, // bool distinct - NULL); //const char *message - } - if (res) - goto err; - - for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); - unit; - unit= unit->next_unit()) - { - /* - Display subqueries only if they are not parts of eliminated WHERE/ON - clauses. - */ - if (!(unit->item && unit->item->eliminated)) - { - if ((res= unit->print_explain(output, explain_flags, printed_anything))) - goto err; - } - } - } - else - { - const char *msg; - if (!join) - DBUG_ASSERT(0); /* Seems not to be possible */ - - /* Not printing anything useful, don't touch *printed_anything here */ - if (join->have_query_plan == JOIN::QEP_NOT_PRESENT_YET) - msg= "Not yet optimized"; - else - { - DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); - msg= "Query plan already deleted"; - } - set_explain_type(TRUE/* on_the_fly */); - res= print_explain_message_line(output, 0/*options*/, select_number, type, - msg); - } -err: - return res; -} -#endif - -int st_select_lex_unit::save_qpf(QPF_query *output) +int st_select_lex_unit::save_union_qpf(QPF_query *output) { - //int res= 0; SELECT_LEX *first= first_select(); - - if (!first->next_select()) - { - /* This is a 1-way UNION, i.e. not really a UNION */ - if (!output->get_select(first->select_number)) - first->save_qpf(output); - return 0; - } - QPF_union *qpfu= new (output->mem_root) QPF_union; + /* TODO: The following code should be eliminated. If we have a capability to save Query Plan Footprints, we should just save them, and never need to @@ -4380,53 +4303,48 @@ int st_select_lex_unit::save_qpf(QPF_query *output) // Save the UNION node output->add_node(qpfu); -#if 0 - /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ + qpfu->fake_select_type= "UNION RESULT"; + qpfu->using_filesort= test(global_parameters->order_list.first); + return 0; +} + + +int st_select_lex_unit::save_union_qpf_part2(QPF_query *output) +{ + QPF_union *qpfu= output->get_union(first_select()->select_number); if (fake_select_lex) { - res= print_fake_select_lex_join(output, TRUE /* on the fly */, - fake_select_lex, explain_flags); + for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit(); + unit; unit= unit->next_unit()) + { + if (!(unit->item && unit->item->eliminated)) + { + qpfu->add_child(unit->first_select()->select_number); + } + } } - return res; -#endif return 0; } -#if 0 -int st_select_lex_unit::print_explain(select_result_sink *output, - uint8 explain_flags, bool *printed_anything) + +int st_select_lex_unit::save_qpf(QPF_query *output) { - int res= 0; + //int res= 0; SELECT_LEX *first= first_select(); - - if (first && !first->next_select() && !first->join) - { - /* - If there is only one child, 'first', and it has join==NULL, emit "not in - EXPLAIN state" error. - */ - const char *msg="Query plan already deleted"; - first->set_explain_type(TRUE/* on_the_fly */); - res= print_explain_message_line(output, 0/*options*/, first->select_number, - first->type, msg); - return res; - } - for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) + if (!first->next_select()) { - if ((res= sl->print_explain(output, explain_flags, printed_anything))) - break; + /* This is a 1-way UNION, i.e. not really a UNION */ + if (!output->get_select(first->select_number)) + first->save_qpf(output); + return 0; } - /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ - if (fake_select_lex) - { - res= print_fake_select_lex_join(output, TRUE /* on the fly */, - fake_select_lex, explain_flags); - } - return res; + save_union_qpf(output); + + return 0; } -#endif + /** A routine used by the parser to decide whether we are specifying a full diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7e76c09a4f5..77abc46d30b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -733,6 +733,8 @@ public: List<Item> *get_unit_column_types(); int save_qpf(QPF_query *output); + int save_union_qpf(QPF_query *output); + int save_union_qpf_part2(QPF_query *output); }; typedef class st_select_lex_unit SELECT_LEX_UNIT; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1b98d0b12ee..5e20d2faf24 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1002,6 +1002,7 @@ err: DBUG_RETURN(res); /* purecov: inspected */ } +void join_save_qpf(JOIN *join); int JOIN::optimize() { @@ -1020,7 +1021,10 @@ int JOIN::optimize() return 0, even though we never had a query plan. */ if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED) + { have_query_plan= QEP_AVAILABLE; + join_save_qpf(this); + } return res; } @@ -1611,8 +1615,10 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S JOIN_TAB *tab= &join_tab[const_tables]; bool all_order_fields_used; if (order) + { skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1, &tab->table->keys_in_use_for_order_by); + } if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, order, fields_list, all_fields, &all_order_fields_used))) @@ -2289,11 +2295,48 @@ JOIN::save_join_tab() } +void join_save_qpf(JOIN *join) +{ + THD *thd= join->thd; +//TODO: why not call st_select_lex::save_qpf here? + + if (join->select_lex->select_number != UINT_MAX && + join->select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && + join->have_query_plan != JOIN::QEP_NOT_PRESENT_YET && + join->have_query_plan != JOIN::QEP_DELETED && // this happens when there was no QEP ever, but then + //cleanup() is called multiple times + + thd->lex->query_plan_footprint && // for "SET" command in SPs. + !thd->lex->query_plan_footprint->get_select(join->select_lex->select_number)) + { + const char *message= NULL; + + if (!join->table_count || !join->tables_list || join->zero_result_cause) + { + /* It's a degenerate join */ + message= join->zero_result_cause ? join->zero_result_cause : "No tables used"; + } + + join->save_qpf(thd->lex->query_plan_footprint, + join->need_tmp, // need_tmp_table + !join->skip_sort_order && !join->no_order && + (join->order || join->group_list), // bool need_order + join->select_distinct, // bool distinct + message); // message + } +} + + void JOIN::exec() { /* Enable SHOW EXPLAIN only if we're in the top-level query. */ + + /* + psergey: we can produce SHOW explain at this point. This means, we're ready + to save the query plan. + */ thd->apc_target.enable(); DBUG_EXECUTE_IF("show_explain_probe_join_exec_start", if (dbug_user_var_equals_int(thd, @@ -11109,6 +11152,7 @@ void JOIN::cleanup(bool full) if (full) { // +#if 0 if (select_lex->select_number != UINT_MAX && select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && have_query_plan != QEP_NOT_PRESENT_YET && @@ -11133,7 +11177,7 @@ void JOIN::cleanup(bool full) select_distinct, // bool distinct message); // message } - +#endif // have_query_plan= QEP_DELETED; //psergey: this is a problem! @@ -22352,589 +22396,6 @@ void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res) } -/** - EXPLAIN handling. - - Produce lines explaining execution of *this* select (not including children - selects) - @param on_the_fly TRUE <=> we're being executed on-the-fly, so don't make - modifications to any select's data structures - - psergey-todo: should this produce a data structure with a query plan? Or, the - data structure with the query plan should be produced in any way? -*/ -#if 0 -int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, - bool on_the_fly, - bool need_tmp_table, bool need_order, - bool distinct, const char *message) -{ - List<Item> field_list; - List<Item> item_list; - JOIN *join= this; /* Legacy: this code used to be a non-member function */ - THD *thd=join->thd; - Item *item_null= new Item_null(); - CHARSET_INFO *cs= system_charset_info; - int quick_type; - int error= 0; - DBUG_ENTER("JOIN::print_explain"); - DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", - (ulong)join->select_lex, join->select_lex->type, - message ? message : "NULL")); - DBUG_ASSERT(on_the_fly? have_query_plan == QEP_AVAILABLE: TRUE); - /* Don't log this into the slow query log */ - - if (!on_the_fly) - { - thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); - join->unit->offset_limit_cnt= 0; - } - - /* - NOTE: the number/types of items pushed into item_list must be in sync with - EXPLAIN column types as they're "defined" in THD::send_explain_fields() - */ - if (message) - { - if (on_the_fly) - join->select_lex->set_explain_type(on_the_fly); - - if (print_explain_message_line(result, explain_flags, - join->select_lex->select_number, - join->select_lex->type, message)) - error= 1; - - } - else if (join->select_lex == join->unit->fake_select_lex) - { - if (print_fake_select_lex_join(result, on_the_fly, - join->select_lex, - explain_flags)) - error= 1; - } - else if (!join->select_lex->master_unit()->derived || - join->select_lex->master_unit()->derived->is_materialized_derived()) - { - table_map used_tables=0; - - if (on_the_fly) - join->select_lex->set_explain_type(on_the_fly); - - bool printing_materialize_nest= FALSE; - uint select_id= join->select_lex->select_number; - - JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); - - for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab; - tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab)) - { - if (tab->bush_root_tab) - { - JOIN_TAB *first_sibling= tab->bush_root_tab->bush_children->start; - select_id= first_sibling->emb_sj_nest->sj_subq_pred->get_identifier(); - printing_materialize_nest= TRUE; - } - - TABLE *table=tab->table; - TABLE_LIST *table_list= tab->table->pos_in_table_list; - char buff[512]; - char buff1[512], buff2[512], buff3[512], buff4[512]; - char keylen_str_buf[64]; - my_bool key_read; - String extra(buff, sizeof(buff),cs); - char table_name_buffer[SAFE_NAME_LEN]; - String tmp1(buff1,sizeof(buff1),cs); - String tmp2(buff2,sizeof(buff2),cs); - String tmp3(buff3,sizeof(buff3),cs); - String tmp4(buff4,sizeof(buff4),cs); - char hash_key_prefix[]= "#hash#"; - KEY *key_info= 0; - uint key_len= 0; - bool is_hj= tab->type == JT_HASH || tab->type ==JT_HASH_NEXT; - - extra.length(0); - tmp1.length(0); - tmp2.length(0); - tmp3.length(0); - tmp4.length(0); - quick_type= -1; - QUICK_SELECT_I *quick= NULL; - JOIN_TAB *saved_join_tab= NULL; - - /* Don't show eliminated tables */ - if (table->map & join->eliminated_tables) - { - used_tables|=table->map; - continue; - } - - if (join->table_access_tabs == join->join_tab && - tab == (first_top_tab + join->const_tables) && pre_sort_join_tab) - { - saved_join_tab= tab; - tab= pre_sort_join_tab; - } - - item_list.empty(); - /* id */ - item_list.push_back(new Item_uint((uint32)select_id)); - /* select_type */ - const char* stype= printing_materialize_nest? "MATERIALIZED" : - join->select_lex->type; - item_list.push_back(new Item_string(stype, strlen(stype), cs)); - - enum join_type tab_type= tab->type; - if ((tab->type == JT_ALL || tab->type == JT_HASH) && - tab->select && tab->select->quick && tab->use_quick != 2) - { - quick= tab->select->quick; - quick_type= tab->select->quick->get_type(); - if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) || - (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) || - (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) || - (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION)) - tab_type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE; - else - tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE; - } - - /* table */ - if (table->derived_select_number) - { - /* Derived table name generation */ - int len= my_snprintf(table_name_buffer, sizeof(table_name_buffer)-1, - "<derived%u>", - table->derived_select_number); - item_list.push_back(new Item_string(table_name_buffer, len, cs)); - } - else if (tab->bush_children) - { - JOIN_TAB *ctab= tab->bush_children->start; - /* table */ - int len= my_snprintf(table_name_buffer, - sizeof(table_name_buffer)-1, - "<subquery%d>", - ctab->emb_sj_nest->sj_subq_pred->get_identifier()); - item_list.push_back(new Item_string(table_name_buffer, len, cs)); - } - 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)); - } - /* "partitions" column */ - if (explain_flags & DESCRIBE_PARTITIONS) - { -#ifdef WITH_PARTITION_STORAGE_ENGINE - partition_info *part_info; - if (!table->derived_select_number && - (part_info= table->part_info)) - { - Item_string *item_str= new Item_string(cs); - make_used_partitions_str(part_info, &item_str->str_value); - item_list.push_back(item_str); - } - else - item_list.push_back(item_null); -#else - /* just produce empty column if partitioning is not compiled in */ - item_list.push_back(item_null); -#endif - } - /* "type" column */ - item_list.push_back(new Item_string(join_type_str[tab_type], - strlen(join_type_str[tab_type]), - cs)); - /* Build "possible_keys" value and add it to item_list */ - if (!tab->keys.is_clear_all()) - { - uint j; - for (j=0 ; j < table->s->keys ; j++) - { - if (tab->keys.is_set(j)) - { - if (tmp1.length()) - tmp1.append(','); - tmp1.append(table->key_info[j].name, - strlen(table->key_info[j].name), - system_charset_info); - } - } - } - if (tmp1.length()) - item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs)); - else - item_list.push_back(item_null); - - /* Build "key", "key_len", and "ref" values and add them to item_list */ - if (tab_type == JT_NEXT) - { - key_info= table->key_info+tab->index; - key_len= key_info->key_length; - } - else if (tab->ref.key_parts) - { - key_info= tab->get_keyinfo_by_key_no(tab->ref.key); - key_len= tab->ref.key_length; - } - if (key_info) - { - register uint length; - if (is_hj) - tmp2.append(hash_key_prefix, strlen(hash_key_prefix), cs); - tmp2.append(key_info->name, strlen(key_info->name), cs); - length= (longlong10_to_str(key_len, keylen_str_buf, 10) - - keylen_str_buf); - tmp3.append(keylen_str_buf, length, cs); - if (tab->ref.key_parts && tab_type != JT_FT) - { - store_key **ref=tab->ref.key_copy; - for (uint kp= 0; kp < tab->ref.key_parts; kp++) - { - if (tmp4.length()) - tmp4.append(','); - - if ((key_part_map(1) << kp) & tab->ref.const_ref_part_map) - tmp4.append("const"); - else - { - tmp4.append((*ref)->name(), strlen((*ref)->name()), cs); - ref++; - } - } - } - } - if (is_hj && tab_type != JT_HASH) - { - tmp2.append(':'); - tmp3.append(':'); - } - if (tab_type == JT_HASH_NEXT) - { - register uint length; - key_info= table->key_info+tab->index; - key_len= key_info->key_length; - tmp2.append(key_info->name, strlen(key_info->name), cs); - length= (longlong10_to_str(key_len, keylen_str_buf, 10) - - keylen_str_buf); - tmp3.append(keylen_str_buf, length, cs); - } - if (tab->type != JT_CONST && tab->select && quick) - tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3); - if (key_info || (tab->select && quick)) - { - if (tmp2.length()) - item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs)); - else - item_list.push_back(item_null); - if (tmp3.length()) - item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs)); - else - item_list.push_back(item_null); - if (key_info && tab_type != JT_NEXT) - item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs)); - else - item_list.push_back(item_null); - } - else - { - if (table_list && /* SJM bushes don't have table_list */ - table_list->schema_table && - table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE) - { - const char *tmp_buff; - int f_idx; - if (table_list->has_db_lookup_value) - { - f_idx= table_list->schema_table->idx_field1; - tmp_buff= table_list->schema_table->fields_info[f_idx].field_name; - tmp2.append(tmp_buff, strlen(tmp_buff), cs); - } - if (table_list->has_table_lookup_value) - { - if (table_list->has_db_lookup_value) - tmp2.append(','); - f_idx= table_list->schema_table->idx_field2; - tmp_buff= table_list->schema_table->fields_info[f_idx].field_name; - tmp2.append(tmp_buff, strlen(tmp_buff), cs); - } - if (tmp2.length()) - item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs)); - else - item_list.push_back(item_null); - } - else - item_list.push_back(item_null); - item_list.push_back(item_null); - item_list.push_back(item_null); - } - - /* Add "rows" field to item_list. */ - if (table_list /* SJM bushes don't have table_list */ && - table_list->schema_table) - { - /* in_rows */ - if (explain_flags & DESCRIBE_EXTENDED) - item_list.push_back(item_null); - /* rows */ - item_list.push_back(item_null); - } - else - { - ha_rows examined_rows= tab->get_examined_rows(); - - item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows, - MY_INT64_NUM_DECIMAL_DIGITS)); - - /* Add "filtered" field to item_list. */ - if (explain_flags & DESCRIBE_EXTENDED) - { - float f= 0.0; - if (examined_rows) - { - double pushdown_cond_selectivity= tab->cond_selectivity; - if (pushdown_cond_selectivity == 1.0) - f= (float) (100.0 * tab->records_read / examined_rows); - else - f= (float) (100.0 * pushdown_cond_selectivity); - } - set_if_smaller(f, 100.0); - item_list.push_back(new Item_float(f, 2)); - } - } - - /* Build "Extra" field and add it to item_list. */ - key_read=table->key_read; - if ((tab_type == JT_NEXT || tab_type == JT_CONST) && - table->covering_keys.is_set(tab->index)) - key_read=1; - if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT && - !((QUICK_ROR_INTERSECT_SELECT*)quick)->need_to_fetch_row) - key_read=1; - - if (tab->info) - { - const char *reason; - switch (tab->info) { - case ET_CONST_ROW_NOT_FOUND: - reason= "const row not found"; - break; - case ET_UNIQUE_ROW_NOT_FOUND: - reason= "unique row not found"; - break; - case ET_IMPOSSIBLE_ON_CONDITION: - reason= "Impossible ON condition"; - break; - default: - DBUG_ASSERT(0); - } - item_list.push_back(new Item_string(reason,strlen(reason),cs)); - } - else if (tab->packed_info & TAB_INFO_HAVE_VALUE) - { - if (tab->packed_info & TAB_INFO_USING_INDEX) - extra.append(STRING_WITH_LEN("; Using index")); - if (tab->packed_info & TAB_INFO_USING_WHERE) - extra.append(STRING_WITH_LEN("; Using where")); - if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL) - extra.append(STRING_WITH_LEN("; Full scan on NULL key")); - /* Skip initial "; "*/ - const char *str= extra.ptr(); - uint32 len= extra.length(); - if (len) - { - str += 2; - len -= 2; - } - item_list.push_back(new Item_string(str, len, cs)); - } - else - { - uint keyno= MAX_KEY; - if (tab->ref.key_parts) - keyno= tab->ref.key; - else if (tab->select && quick) - keyno = quick->index; - - if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno && - table->file->pushed_idx_cond) - extra.append(STRING_WITH_LEN("; Using index condition")); - else if (tab->cache_idx_cond) - extra.append(STRING_WITH_LEN("; Using index condition(BKA)")); - - if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || - quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || - quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT || - quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) - { - extra.append(STRING_WITH_LEN("; Using ")); - tab->select->quick->add_info_string(&extra); - } - if (tab->select) - { - if (tab->use_quick == 2) - { - /* 4 bits per 1 hex digit + terminating '\0' */ - char buf[MAX_KEY / 4 + 1]; - extra.append(STRING_WITH_LEN("; Range checked for each " - "record (index map: 0x")); - extra.append(tab->keys.print(buf)); - extra.append(')'); - } - else if (tab->select->cond) - { - const COND *pushed_cond= tab->table->file->pushed_cond; - - if (((thd->variables.optimizer_switch & - OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN) || - (tab->table->file->ha_table_flags() & - HA_MUST_USE_TABLE_CONDITION_PUSHDOWN)) && - pushed_cond) - { - extra.append(STRING_WITH_LEN("; Using where with pushed " - "condition")); - if (explain_flags & DESCRIBE_EXTENDED) - { - extra.append(STRING_WITH_LEN(": ")); - ((COND *)pushed_cond)->print(&extra, QT_ORDINARY); - } - } - else - extra.append(STRING_WITH_LEN("; Using where")); - } - } - if (table_list /* SJM bushes don't have table_list */ && - table_list->schema_table && - table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE) - { - if (!table_list->table_open_method) - extra.append(STRING_WITH_LEN("; Skip_open_table")); - else if (table_list->table_open_method == OPEN_FRM_ONLY) - extra.append(STRING_WITH_LEN("; Open_frm_only")); - else - extra.append(STRING_WITH_LEN("; Open_full_table")); - if (table_list->has_db_lookup_value && - table_list->has_table_lookup_value) - extra.append(STRING_WITH_LEN("; Scanned 0 databases")); - else if (table_list->has_db_lookup_value || - table_list->has_table_lookup_value) - extra.append(STRING_WITH_LEN("; Scanned 1 database")); - else - extra.append(STRING_WITH_LEN("; Scanned all databases")); - } - if (key_read) - { - if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) - { - QUICK_GROUP_MIN_MAX_SELECT *qgs= - (QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick; - extra.append(STRING_WITH_LEN("; Using index for group-by")); - qgs->append_loose_scan_type(&extra); - } - else - extra.append(STRING_WITH_LEN("; Using index")); - } - if (table->reginfo.not_exists_optimize) - extra.append(STRING_WITH_LEN("; Not exists")); - - /* - if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE && - !(((QUICK_RANGE_SELECT*)(tab->select->quick))->mrr_flags & - HA_MRR_USE_DEFAULT_IMPL)) - { - extra.append(STRING_WITH_LEN("; Using MRR")); - } - */ - if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE) - { - explain_append_mrr_info((QUICK_RANGE_SELECT*)(tab->select->quick), - &extra); - } - - if (need_tmp_table) - { - need_tmp_table=0; - extra.append(STRING_WITH_LEN("; Using temporary")); - } - if (need_order) - { - need_order=0; - extra.append(STRING_WITH_LEN("; Using filesort")); - } - if (distinct & test_all_bits(used_tables, - join->select_list_used_tables)) - extra.append(STRING_WITH_LEN("; Distinct")); - if (tab->loosescan_match_tab) - { - extra.append(STRING_WITH_LEN("; LooseScan")); - } - - if (tab->first_weedout_table) - extra.append(STRING_WITH_LEN("; Start temporary")); - if (tab->check_weed_out_table) - extra.append(STRING_WITH_LEN("; End temporary")); - else if (tab->do_firstmatch) - { - if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1) - extra.append(STRING_WITH_LEN("; FirstMatch")); - else - { - extra.append(STRING_WITH_LEN("; FirstMatch(")); - TABLE *prev_table=tab->do_firstmatch->table; - if (prev_table->derived_select_number) - { - char namebuf[NAME_LEN]; - /* Derived table name generation */ - int len= my_snprintf(namebuf, sizeof(namebuf)-1, - "<derived%u>", - prev_table->derived_select_number); - extra.append(namebuf, len); - } - else - extra.append(prev_table->pos_in_table_list->alias); - extra.append(STRING_WITH_LEN(")")); - } - } - - for (uint part= 0; part < tab->ref.key_parts; part++) - { - if (tab->ref.cond_guards[part]) - { - extra.append(STRING_WITH_LEN("; Full scan on NULL key")); - break; - } - } - - if (tab->cache) - { - extra.append(STRING_WITH_LEN("; Using join buffer")); - tab->cache->print_explain_comment(&extra); - } - - /* Skip initial "; "*/ - const char *str= extra.ptr(); - uint32 len= extra.length(); - if (len) - { - str += 2; - len -= 2; - } - item_list.push_back(new Item_string(str, len, cs)); - } - - if (saved_join_tab) - tab= saved_join_tab; - - // For next iteration - used_tables|=table->map; - if (result->send_data(item_list)) - error= 1; - } - } - DBUG_RETURN(error); -} -#endif ///////////////////////////////////////////////////////////////////////////////////////////////// void QPF_table_access::push_extra(enum Extra_tag extra_tag) { @@ -23001,6 +22462,7 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, } else if (join->select_lex == join->unit->fake_select_lex) { +#if 0 select_lex->set_explain_type(on_the_fly); QPF_union *qp_union= new (output->mem_root) QPF_union; qp_node= qp_union; @@ -23017,6 +22479,7 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, test(select_lex->master_unit()->global_parameters->order_list.first); output->add_node(qp_union); +#endif } else if (!join->select_lex->master_unit()->derived || join->select_lex->master_unit()->derived->is_materialized_derived()) @@ -23555,16 +23018,21 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, THD *thd=join->thd; select_result *result=join->result; DBUG_ENTER("select_describe"); -#if 0 - join->error= join->print_explain(result, thd->lex->describe, - FALSE, /* Not on-the-fly */ - need_tmp_table, need_order, distinct, - message); -#endif - //psergey-todo: save QPF here, too. + + // Update the QPF: + QPF_select *qp; + if ((qp= thd->lex->query_plan_footprint->get_select(join->select_lex->select_number))) + { + qp->using_temporary= need_tmp_table; + qp->using_filesort= need_order; + } + +/* + WE DONT NEED THIS here anymore: + join->save_qpf(thd->lex->query_plan_footprint, need_tmp_table, need_order, distinct, message); - +*/ for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); unit; unit= unit->next_unit()) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index eb4454ecab3..b77b0669b50 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -626,6 +626,9 @@ bool st_select_lex_unit::exec() saved_error= optimize(); + + save_union_qpf(thd->lex->query_plan_footprint); + if (uncacheable || !item || !item->assigned() || describe) { for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) @@ -772,6 +775,9 @@ bool st_select_lex_unit::exec() */ if (!fake_select_lex->ref_pointer_array) fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; + + + save_union_qpf_part2(thd->lex->query_plan_footprint); saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, &result_table_list, |