diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 224 |
1 files changed, 178 insertions, 46 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36582223703..02d2187970a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -798,13 +798,46 @@ err: } +/* + Create a dummy temporary table, useful only for the sake of having a + TABLE* object with map,tablenr and maybe_null properties. + + This is used by non-mergeable semi-join materilization code to handle + degenerate cases where materialized subquery produced "Impossible WHERE" + and thus wasn't materialized. +*/ + +TABLE *create_dummy_tmp_table(THD *thd) +{ + DBUG_ENTER("create_dummy_tmp_table"); + TABLE *table; + TMP_TABLE_PARAM sjm_table_param; + sjm_table_param.init(); + sjm_table_param.field_count= 1; + List<Item> sjm_table_cols; + Item *column_item= new Item_int(1); + sjm_table_cols.push_back(column_item); + if (!(table= create_tmp_table(thd, &sjm_table_param, + sjm_table_cols, (ORDER*) 0, + TRUE /* distinct */, + 1, /*save_sum_fields*/ + thd->options | TMP_TABLE_ALL_COLUMNS, + HA_POS_ERROR /*rows_limit */, + (char*)"dummy", TRUE /* Do not open */))) + { + DBUG_RETURN(NULL); + } + DBUG_RETURN(table); +} + + void -inject_jtbm_conds(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where) +setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where) { TABLE_LIST *table; NESTED_JOIN *nested_join; List_iterator<TABLE_LIST> li(*join_list); - DBUG_ENTER("inject_jtbm_conds"); + DBUG_ENTER("setup_jtbm_semi_joins"); while ((table= li++)) @@ -817,34 +850,60 @@ inject_jtbm_conds(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where) double rows; double read_time; - //DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); subq_pred->optimize(&rows, &read_time); - subq_pred->jtbm_read_time= read_time; subq_pred->jtbm_record_count=rows; subq_pred->is_jtbm_merged= TRUE; + JOIN *subq_join= subq_pred->unit->first_select()->join; + if (!subq_join->tables_list || !subq_join->table_count) + { + /* + This is an empty and constant table. - subselect_hash_sj_engine *hash_sj_engine= - ((subselect_hash_sj_engine*)item->engine); - - - //repeat of convert_subq_to_jtbm: - table->table= hash_sj_engine->tmp_table; - table->table->pos_in_table_list= table; + TODO: what if this is not empty but still constant? + + We'll need to check the equality but there's no materializatnion + table? + + A: create an IN-equality from + - left_expr + - right_expr. Q: how can right-expr exist in the context of + parent select? We don't have refs from outside to inside! + A: create/check in the context of the child select? + + for injection, check how in->exists is performed. + */ + subq_pred->is_jtbm_const_tab= TRUE; - setup_table_map(table->table, table, table->jtbm_table_no); + TABLE *dummy_table= create_dummy_tmp_table(join->thd); + table->table= dummy_table; + table->table->pos_in_table_list= table; - Item *sj_conds= hash_sj_engine->semi_join_conds; + setup_table_map(table->table, table, table->jtbm_table_no); + } + else + { + DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION)); + subq_pred->is_jtbm_const_tab= FALSE; + subselect_hash_sj_engine *hash_sj_engine= + ((subselect_hash_sj_engine*)item->engine); + + table->table= hash_sj_engine->tmp_table; + table->table->pos_in_table_list= table; - (*join_where)= and_items(*join_where, sj_conds); - if (!(*join_where)->fixed) - (*join_where)->fix_fields(join->thd, join_where); - //parent_join->select_lex->where= parent_join->conds; + setup_table_map(table->table, table, table->jtbm_table_no); + + Item *sj_conds= hash_sj_engine->semi_join_conds; + + (*join_where)= and_items(*join_where, sj_conds); + if (!(*join_where)->fixed) + (*join_where)->fix_fields(join->thd, join_where); + } } if ((nested_join= table->nested_join)) { - inject_jtbm_conds(join, &nested_join->join_list, join_where); + setup_jtbm_semi_joins(join, &nested_join->join_list, join_where); } } DBUG_VOID_RETURN; @@ -971,7 +1030,7 @@ JOIN::optimize() thd->restore_active_arena(arena, &backup); } - inject_jtbm_conds(this, join_list, &conds); + setup_jtbm_semi_joins(this, join_list, &conds); conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal); @@ -1449,7 +1508,7 @@ JOIN::optimize() order=0; // Can't use sort on head table if using join buffering - if (full_join) + if (full_join || hash_join) { TABLE *stable= (sort_by_table == (TABLE *) 1 ? join_tab[const_tables].table : sort_by_table); @@ -3130,6 +3189,14 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, set_position(join,const_count++,s,(KEYUSE*) 0); no_rows_const_tables |= table->map; } + + /* SJ-Materialization handling: */ + if (table->pos_in_table_list->jtbm_subselect && + table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + set_position(join,const_count++,s,(KEYUSE*) 0); + no_rows_const_tables |= table->map; + } } stat_vector[i]=0; @@ -5391,7 +5458,9 @@ best_access_path(JOIN *join, (1) s is inner table of semi-join -> join cache is allowed for semijoins (2) s is inner table of outer join -> join cache is allowed for outer joins */ - if (idx > join->const_tables && best_key == 0 && + if (idx > join->const_tables && best_key == 0 && + (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && + join->max_allowed_join_cache_level > 2 && !bitmap_is_clear_all(eq_join_set) && !disable_jbuf && (!s->emb_sj_nest || join->allowed_semijoin_with_cache) && // (1) @@ -7044,6 +7113,7 @@ get_best_combination(JOIN *join) DBUG_RETURN(TRUE); join->full_join=0; + join->hash_join= FALSE; used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read @@ -7133,6 +7203,11 @@ get_best_combination(JOIN *join) } else if (create_ref_for_key(join, j, keyuse, used_tables)) DBUG_RETURN(TRUE); // Something went wrong + + if ((j->type == JT_REF || j->type == JT_EQ_REF) && + is_hash_join_key_no(j->ref.key)) + join->hash_join= TRUE; + loop_end: /* Save records_read in JOIN_TAB so that select_describe()/etc don't have @@ -7193,10 +7268,26 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, do { - if (!(~used_tables & keyuse->used_tables) && - (first_keyuse || keyuse->keypart != (keyuse-1)->keypart)) - key_parts++; - first_keyuse= FALSE; + if (!(~used_tables & keyuse->used_tables)) + { + if (first_keyuse) + { + key_parts++; + first_keyuse= FALSE; + } + else + { + KEYUSE *curr= org_keyuse; + for( ; curr < keyuse; curr++) + { + if (curr->keypart == keyuse->keypart && + !(~used_tables & curr->used_tables)) + break; + } + if (curr == keyuse) + key_parts++; + } + } keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); if (!key_parts) @@ -7221,15 +7312,31 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, keyuse= org_keyuse; do { - if (!(~used_tables & keyuse->used_tables) && - (first_keyuse || keyuse->keypart != (keyuse-1)->keypart)) - { - Field *field= table->field[keyuse->keypart]; - uint fieldnr= keyuse->keypart+1; - table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr); - first_keyuse= FALSE; - key_part_info++; + if (!(~used_tables & keyuse->used_tables)) + { + bool add_key_part= TRUE; + if (!first_keyuse) + { + for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++) + { + if (curr->keypart == keyuse->keypart && + !(~used_tables & curr->used_tables)) + { + keyuse->keypart= NO_KEYPART; + add_key_part= FALSE; + break; + } + } + } + if (add_key_part) + { + Field *field= table->field[keyuse->keypart]; + uint fieldnr= keyuse->keypart+1; + table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr); + key_part_info++; + } } + first_keyuse= FALSE; keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); @@ -7312,8 +7419,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, { if (are_tables_local(j, keyuse->val->used_tables())) { - if ((is_hash_join_key_no(key) && - (keyparts == 0 || keyuse->keypart != (keyuse-1)->keypart)) || + if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) || (!is_hash_join_key_no(key) && keyparts == keyuse->keypart && !(found_part_ref_or_null & keyuse->optimize))) { @@ -7367,6 +7473,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, for (i=0 ; i < keyparts ; keyuse++,i++) { while (((~used_tables) & keyuse->used_tables) || + keyuse->keypart == NO_KEYPART || (keyuse->keypart != (is_hash_join_key_no(key) ? keyinfo->key_part[i].field->field_index : i)) || @@ -8777,8 +8884,7 @@ void revise_cache_usage(JOIN_TAB *join_tab) first_inner= join_tab->first_sj_inner_tab; for (tab= join_tab-1; tab >= first_inner; tab--) { - if (tab->first_sj_inner_tab == first_inner) - set_join_cache_denial(tab); + set_join_cache_denial(tab); } } else set_join_cache_denial(join_tab); @@ -9638,8 +9744,16 @@ void JOIN_TAB::cleanup() if (table->pos_in_table_list && table->pos_in_table_list->jtbm_subselect) { - end_read_record(&read_record); - table->pos_in_table_list->jtbm_subselect->cleanup(); + if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + free_tmp_table(join->thd, table); + table= NULL; + } + else + { + end_read_record(&read_record); + table->pos_in_table_list->jtbm_subselect->cleanup(); + } DBUG_VOID_RETURN; } /* @@ -11913,7 +12027,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, { if (!table->prep_on_expr) table->prep_on_expr= table->on_expr; - used_tables= table->table->map; + used_tables= table->get_map(); if (conds) not_null_tables= conds->not_null_tables(); } @@ -11970,7 +12084,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, table->embedding->on_expr_dep_tables|= table->on_expr->used_tables(); } else - table->dep_tables&= ~table->table->map; + table->dep_tables&= ~table->get_map(); } if (prev_table) @@ -11983,7 +12097,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, prev_table->dep_tables|= table->on_expr_dep_tables; table_map prev_used_tables= prev_table->nested_join ? prev_table->nested_join->used_tables : - prev_table->table->map; + prev_table->get_map(); /* If on expression contains only references to inner tables we still make the inner tables dependent on the outer tables. @@ -13946,10 +14060,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, key_part_info->store_length= key_part_info->length; if ((*reg_field)->real_maybe_null()) + { key_part_info->store_length+= HA_KEY_NULL_LENGTH; - if ((*reg_field)->type() == MYSQL_TYPE_BLOB || - (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR) - key_part_info->store_length+= HA_KEY_BLOB_LENGTH; + key_part_info->key_part_flag |= HA_NULL_PART; + } + if ((*reg_field)->type() == MYSQL_TYPE_BLOB || + (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || + (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) + { + if ((*reg_field)->type() == MYSQL_TYPE_BLOB || + (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) + key_part_info->key_part_flag|= HA_BLOB_PART; + else + key_part_info->key_part_flag|= HA_VAR_LENGTH_PART; + + key_part_info->store_length+=HA_KEY_BLOB_LENGTH; + } keyinfo->key_length+= key_part_info->store_length; @@ -15537,6 +15663,12 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) /* Skip materialized derived tables/views. */ DBUG_RETURN(0); } + else if (tab->table->pos_in_table_list->jtbm_subselect && + tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab) + { + /* Row will not be found */ + DBUG_RETURN(-1); + } else if (tab->type == JT_SYSTEM) { if ((error=join_read_system(tab))) @@ -20654,7 +20786,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* id */ item_list.push_back(new Item_uint((uint32)select_id)); /* select_type */ - const char* stype= printing_materialize_nest? "SUBQUERY" : + const char* stype= printing_materialize_nest? "MATERIALIZED" : join->select_lex->type; item_list.push_back(new Item_string(stype, strlen(stype), cs)); |