diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 144 |
1 files changed, 109 insertions, 35 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 167babe9658..932a8d51af3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -266,15 +266,15 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, setup_tables_done_option changed for next rexecution */ res= mysql_select(thd, &select_lex->ref_pointer_array, - (TABLE_LIST*) select_lex->table_list.first, + select_lex->table_list.first, select_lex->with_wild, select_lex->item_list, select_lex->where, select_lex->order_list.elements + select_lex->group_list.elements, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, + select_lex->order_list.first, + select_lex->group_list.first, select_lex->having, - (ORDER*) lex->proc_list.first, + lex->proc_list.first, select_lex->options | thd->options | setup_tables_done_option, result, unit, select_lex); @@ -574,13 +574,21 @@ JOIN::prepare(Item ***rref_pointer_array, { Item *item= *ord->item; /* - Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields - there. Such fields don't contain any data to sort. + Disregard sort order if there's only + zero length NOT NULL fields (e.g. {VAR}CHAR(0) NOT NULL") or + zero length NOT NULL string functions there. + Such tuples don't contain any data to sort. */ if (!real_order && - (item->type() != Item::FIELD_ITEM || - ((Item_field *) item)->field->maybe_null() || - ((Item_field *) item)->field->sort_length())) + /* Not a zero length NOT NULL field */ + ((item->type() != Item::FIELD_ITEM || + ((Item_field *) item)->field->maybe_null() || + ((Item_field *) item)->field->sort_length()) && + /* AND not a zero length NOT NULL string function. */ + (item->type() != Item::FUNC_ITEM || + item->maybe_null || + item->result_type() != STRING_RESULT || + item->max_length))) real_order= TRUE; if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) @@ -2717,15 +2725,29 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, as well as allow us to catch illegal cross references/ Warshall's algorithm is used to build the transitive closure. As we use bitmaps to represent the relation the complexity - of the algorithm is O((number of tables)^2). + of the algorithm is O((number of tables)^2). + + The classic form of the Warshall's algorithm would look like: + for (i= 0; i < table_count; i++) + { + for (j= 0; j < table_count; j++) + { + for (k= 0; k < table_count; k++) + { + if (bitmap_is_set(stat[j].dependent, i) && + bitmap_is_set(stat[i].dependent, k)) + bitmap_set_bit(stat[j].dependent, k); + } + } */ - for (i= 0, s= stat ; i < table_count ; i++, s++) + + for (s= stat ; s < stat_end ; s++) { - for (uint j= 0 ; j < table_count ; j++) + table= s->table; + for (JOIN_TAB *t= stat ; t < stat_end ; t++) { - table= stat[j].table; - if (s->dependent & table->map) - s->dependent |= table->reginfo.join_tab->dependent; + if (t->dependent & table->map) + t->dependent |= table->reginfo.join_tab->dependent; } if (outer_join & s->table->map) s->table->maybe_null= 1; @@ -7279,7 +7301,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, *simple_order=0; // Must do a temp table to sort else if (!(order_tables & not_const_tables)) { - if (order->item[0]->with_subselect) + if (order->item[0]->with_subselect && + !(join->select_lex->options & SELECT_DESCRIBE)) order->item[0]->val_str(&order->item[0]->str_value); DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; // skip const item @@ -8784,6 +8807,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) NESTED_JOIN *nested_join; TABLE_LIST *prev_table= 0; List_iterator<TABLE_LIST> li(*join_list); + bool straight_join= test(join->select_options & SELECT_STRAIGHT_JOIN); DBUG_ENTER("simplify_joins"); /* @@ -8896,7 +8920,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) if (prev_table) { /* The order of tables is reverse: prev_table follows table */ - if (prev_table->straight) + if (prev_table->straight || straight_join) prev_table->dep_tables|= used_tables; if (prev_table->on_expr) { @@ -9178,6 +9202,46 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab) /** Nested joins perspective: Remove the last table from the join order. + The algorithm is the reciprocal of check_interleaving_with_nj(), hence + parent join nest nodes are updated only when the last table in its child + node is removed. The ASCII graphic below will clarify. + + %A table nesting such as <tt> t1 x [ ( t2 x t3 ) x ( t4 x t5 ) ] </tt>is + represented by the below join nest tree. + + @verbatim + NJ1 + _/ / \ + _/ / NJ2 + _/ / / \ + / / / \ + t1 x [ (t2 x t3) x (t4 x t5) ] + @endverbatim + + At the point in time when check_interleaving_with_nj() adds the table t5 to + the query execution plan, QEP, it also directs the node named NJ2 to mark + the table as covered. NJ2 does so by incrementing its @c counter + member. Since all of NJ2's tables are now covered by the QEP, the algorithm + proceeds up the tree to NJ1, incrementing its counter as well. All join + nests are now completely covered by the QEP. + + restore_prev_nj_state() does the above in reverse. As seen above, the node + NJ1 contains the nodes t2, t3, and NJ2. Its counter being equal to 3 means + that the plan covers t2, t3, and NJ2, @e and that the sub-plan (t4 x t5) + completely covers NJ2. The removal of t5 from the partial plan will first + decrement NJ2's counter to 1. It will then detect that NJ2 went from being + completely to partially covered, and hence the algorithm must continue + upwards to NJ1 and decrement its counter to 2. %A subsequent removal of t4 + will however not influence NJ1 since it did not un-cover the last table in + NJ2. + + SYNOPSIS + restore_prev_nj_state() + last join table to remove, it is assumed to be the last in current + partial join order. + + DESCRIPTION + Remove the last table from the partial join order and update the nested joins counters and join->cur_embedding_map. It is ok to call this function for the first table in join order (for which @@ -9191,19 +9255,20 @@ static void restore_prev_nj_state(JOIN_TAB *last) { TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding; JOIN *join= last->join; - while (last_emb) + for (;last_emb != NULL; last_emb= last_emb->embedding) { - if (!(--last_emb->nested_join->counter)) - join->cur_embedding_map&= ~last_emb->nested_join->nj_map; - else if (last_emb->nested_join->n_tables-1 == - last_emb->nested_join->counter) - { - join->cur_embedding_map|= last_emb->nested_join->nj_map; - break; - } - else + NESTED_JOIN *nest= last_emb->nested_join; + DBUG_ASSERT(nest->counter > 0); + + bool was_fully_covered= nest->is_fully_covered(); + + if (--nest->counter == 0) + join->cur_embedding_map&= ~nest->nj_map; + + if (!was_fully_covered) break; - last_emb= last_emb->embedding; + + join->cur_embedding_map|= nest->nj_map; } } @@ -13615,6 +13680,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, uint nr; key_map keys; uint best_key_parts; + uint saved_best_key_parts= 0; int best_key_direction; ha_rows best_records; double read_time; @@ -13816,6 +13882,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { best_key= nr; best_key_parts= keyinfo->key_parts; + saved_best_key_parts= used_key_parts; best_records= quick_records; is_best_covering= is_covering; best_key_direction= direction; @@ -13902,8 +13969,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ } } - used_key_parts= best_key_parts; order_direction= best_key_direction; + /* + saved_best_key_parts is actual number of used keyparts found by the + test_if_order_by_key function. It could differ from keyinfo->key_parts, + thus we have to restore it in case of desc order as it affects + QUICK_SELECT_DESC behaviour. + */ + used_key_parts= (order_direction == -1) ? + saved_best_key_parts : best_key_parts; } else DBUG_RETURN(0); @@ -17052,15 +17126,15 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) thd->lex->current_select= first; unit->set_limit(unit->global_parameters); res= mysql_select(thd, &first->ref_pointer_array, - (TABLE_LIST*) first->table_list.first, + first->table_list.first, first->with_wild, first->item_list, first->where, first->order_list.elements + first->group_list.elements, - (ORDER*) first->order_list.first, - (ORDER*) first->group_list.first, + first->order_list.first, + first->group_list.first, first->having, - (ORDER*) thd->lex->proc_list.first, + thd->lex->proc_list.first, first->options | thd->options | SELECT_DESCRIBE, result, unit, first); } @@ -17370,7 +17444,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (group_list.elements) { str->append(STRING_WITH_LEN(" group by ")); - print_order(str, (ORDER *) group_list.first, query_type); + print_order(str, group_list.first, query_type); switch (olap) { case CUBE_TYPE: @@ -17401,7 +17475,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); - print_order(str, (ORDER *) order_list.first, query_type); + print_order(str, order_list.first, query_type); } // limit |