|
|
|
@ -35,14 +35,17 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
|
|
|
|
"index_merge"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct st_sargable_param;
|
|
|
|
|
|
|
|
|
|
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
|
|
|
|
static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
|
|
|
|
|
DYNAMIC_ARRAY *keyuse);
|
|
|
|
|
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
|
|
|
|
JOIN_TAB *join_tab,
|
|
|
|
|
JOIN_TAB *join_tab,
|
|
|
|
|
uint tables, COND *conds,
|
|
|
|
|
COND_EQUAL *cond_equal,
|
|
|
|
|
table_map table_map, SELECT_LEX *select_lex);
|
|
|
|
|
table_map table_map, SELECT_LEX *select_lex,
|
|
|
|
|
st_sargable_param **sargables);
|
|
|
|
|
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
|
|
|
|
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
|
|
|
|
|
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|
|
|
@ -2044,6 +2047,19 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
|
|
|
|
DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
This structure is used to collect info on potentially sargable
|
|
|
|
|
predicates in order to check whether they become sargable after
|
|
|
|
|
reading const tables.
|
|
|
|
|
We form a bitmap of indexes that can be used for sargable predicates.
|
|
|
|
|
Only such indexes are involved in range analysis.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct st_sargable_param
|
|
|
|
|
{
|
|
|
|
|
Field *field; /* field against which to check sargability */
|
|
|
|
|
Item **arg_value; /* values of potential keys for lookups */
|
|
|
|
|
uint num_values; /* number of values in the above array */
|
|
|
|
|
} SARGABLE_PARAM;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Calculate the best possible join and initialize the join structure
|
|
|
|
@ -2066,6 +2082,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|
|
|
|
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
|
|
|
|
|
KEYUSE *keyuse,*start_keyuse;
|
|
|
|
|
table_map outer_join=0;
|
|
|
|
|
SARGABLE_PARAM *sargables= 0;
|
|
|
|
|
JOIN_TAB *stat_vector[MAX_TABLES+1];
|
|
|
|
|
DBUG_ENTER("make_join_statistics");
|
|
|
|
|
|
|
|
|
@ -2187,7 +2204,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|
|
|
|
if (conds || outer_join)
|
|
|
|
|
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
|
|
|
|
conds, join->cond_equal,
|
|
|
|
|
~outer_join, join->select_lex))
|
|
|
|
|
~outer_join, join->select_lex, &sargables))
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
|
|
|
|
|
/* Read tables with 0 or 1 rows (system tables) */
|
|
|
|
@ -2337,6 +2354,26 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|
|
|
|
}
|
|
|
|
|
} while (join->const_table_map & found_ref && ref_changed);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Update info on indexes that can be used for search lookups as
|
|
|
|
|
reading const tables may has added new sargable predicates.
|
|
|
|
|
*/
|
|
|
|
|
if (const_count && sargables)
|
|
|
|
|
{
|
|
|
|
|
for( ; sargables->field ; sargables++)
|
|
|
|
|
{
|
|
|
|
|
Field *field= sargables->field;
|
|
|
|
|
JOIN_TAB *stat= field->table->reginfo.join_tab;
|
|
|
|
|
key_map possible_keys= field->key_start;
|
|
|
|
|
possible_keys.intersect(field->table->keys_in_use_for_query);
|
|
|
|
|
bool is_const= 1;
|
|
|
|
|
for (uint i=0; i< sargables->num_values; i++)
|
|
|
|
|
is_const&= sargables->arg_value[i]->const_item();
|
|
|
|
|
if (is_const)
|
|
|
|
|
stat[0].const_keys.merge(possible_keys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calc how many (possible) matched records in each table */
|
|
|
|
|
|
|
|
|
|
for (s=stat ; s < stat_end ; s++)
|
|
|
|
@ -2596,6 +2633,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|
|
|
|
eq_func True if we used =, <=> or IS NULL
|
|
|
|
|
value Value used for comparison with field
|
|
|
|
|
usable_tables Tables which can be used for key optimization
|
|
|
|
|
sargables IN/OUT Array of found sargable candidates
|
|
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
If we are doing a NOT NULL comparison on a NOT NULL field in a outer join
|
|
|
|
@ -2607,8 +2645,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|
|
|
|
Field *field, bool eq_func, Item **value, uint num_values,
|
|
|
|
|
table_map usable_tables)
|
|
|
|
|
Field *field, bool eq_func, Item **value, uint num_values,
|
|
|
|
|
table_map usable_tables, SARGABLE_PARAM **sargables)
|
|
|
|
|
{
|
|
|
|
|
uint exists_optimize= 0;
|
|
|
|
|
if (!(field->flags & PART_KEY_FLAG))
|
|
|
|
@ -2664,6 +2702,19 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|
|
|
|
is_const&= value[i]->const_item();
|
|
|
|
|
if (is_const)
|
|
|
|
|
stat[0].const_keys.merge(possible_keys);
|
|
|
|
|
else if (!eq_func)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
Save info to be able check whether this predicate can be
|
|
|
|
|
considered as sargable for range analisis after reading const tables.
|
|
|
|
|
We do not save info about equalities as update_const_equal_items
|
|
|
|
|
will take care of updating info on keys from sargable equalities.
|
|
|
|
|
*/
|
|
|
|
|
(*sargables)--;
|
|
|
|
|
(*sargables)->field= field;
|
|
|
|
|
(*sargables)->arg_value= value;
|
|
|
|
|
(*sargables)->num_values= num_values;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
We can't always use indexes when comparing a string index to a
|
|
|
|
|
number. cmp_type() is checked to allow compare of dates to numbers.
|
|
|
|
@ -2754,6 +2805,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|
|
|
|
value Value used for comparison with field
|
|
|
|
|
Is NULL for BETWEEN and IN
|
|
|
|
|
usable_tables Tables which can be used for key optimization
|
|
|
|
|
sargables IN/OUT Array of found sargable candidates
|
|
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
If field items f1 and f2 belong to the same multiple equality and
|
|
|
|
@ -2767,11 +2819,12 @@ static void
|
|
|
|
|
add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|
|
|
|
Item_func *cond, Item_field *field_item,
|
|
|
|
|
bool eq_func, Item **val,
|
|
|
|
|
uint num_values, table_map usable_tables)
|
|
|
|
|
uint num_values, table_map usable_tables,
|
|
|
|
|
SARGABLE_PARAM **sargables)
|
|
|
|
|
{
|
|
|
|
|
Field *field= field_item->field;
|
|
|
|
|
add_key_field(key_fields, and_level, cond, field,
|
|
|
|
|
eq_func, val, num_values, usable_tables);
|
|
|
|
|
eq_func, val, num_values, usable_tables, sargables);
|
|
|
|
|
Item_equal *item_equal= field_item->item_equal;
|
|
|
|
|
if (item_equal)
|
|
|
|
|
{
|
|
|
|
@ -2786,7 +2839,8 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|
|
|
|
if (!field->eq(item->field))
|
|
|
|
|
{
|
|
|
|
|
add_key_field(key_fields, and_level, cond, item->field,
|
|
|
|
|
eq_func, val, num_values, usable_tables);
|
|
|
|
|
eq_func, val, num_values, usable_tables,
|
|
|
|
|
sargables);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2794,7 +2848,8 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
COND *cond, table_map usable_tables)
|
|
|
|
|
COND *cond, table_map usable_tables,
|
|
|
|
|
SARGABLE_PARAM **sargables)
|
|
|
|
|
{
|
|
|
|
|
if (cond->type() == Item_func::COND_ITEM)
|
|
|
|
|
{
|
|
|
|
@ -2805,20 +2860,20 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
{
|
|
|
|
|
Item *item;
|
|
|
|
|
while ((item=li++))
|
|
|
|
|
add_key_fields(key_fields,and_level,item,usable_tables);
|
|
|
|
|
add_key_fields(key_fields,and_level,item,usable_tables,sargables);
|
|
|
|
|
for (; org_key_fields != *key_fields ; org_key_fields++)
|
|
|
|
|
org_key_fields->level= *and_level;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
(*and_level)++;
|
|
|
|
|
add_key_fields(key_fields,and_level,li++,usable_tables);
|
|
|
|
|
add_key_fields(key_fields,and_level,li++,usable_tables,sargables);
|
|
|
|
|
Item *item;
|
|
|
|
|
while ((item=li++))
|
|
|
|
|
{
|
|
|
|
|
KEY_FIELD *start_key_fields= *key_fields;
|
|
|
|
|
(*and_level)++;
|
|
|
|
|
add_key_fields(key_fields,and_level,item,usable_tables);
|
|
|
|
|
add_key_fields(key_fields,and_level,item,usable_tables,sargables);
|
|
|
|
|
*key_fields=merge_key_fields(org_key_fields,start_key_fields,
|
|
|
|
|
*key_fields,++(*and_level));
|
|
|
|
|
}
|
|
|
|
@ -2849,9 +2904,9 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
cond_func->argument_count() != 2);
|
|
|
|
|
add_key_equal_fields(key_fields, *and_level, cond_func,
|
|
|
|
|
(Item_field*) (cond_func->key_item()->real_item()),
|
|
|
|
|
0, values,
|
|
|
|
|
0, values,
|
|
|
|
|
cond_func->argument_count()-1,
|
|
|
|
|
usable_tables);
|
|
|
|
|
usable_tables, sargables);
|
|
|
|
|
}
|
|
|
|
|
if (cond_func->functype() == Item_func::BETWEEN)
|
|
|
|
|
{
|
|
|
|
@ -2865,7 +2920,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
{
|
|
|
|
|
field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
|
|
|
|
|
add_key_equal_fields(key_fields, *and_level, cond_func,
|
|
|
|
|
field_item, 0, values, 1, usable_tables);
|
|
|
|
|
field_item, 0, values, 1, usable_tables,
|
|
|
|
|
sargables);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2882,7 +2938,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
add_key_equal_fields(key_fields, *and_level, cond_func,
|
|
|
|
|
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
|
|
|
|
equal_func,
|
|
|
|
|
cond_func->arguments()+1, 1, usable_tables);
|
|
|
|
|
cond_func->arguments()+1, 1, usable_tables,
|
|
|
|
|
sargables);
|
|
|
|
|
}
|
|
|
|
|
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
|
|
|
|
|
cond_func->functype() != Item_func::LIKE_FUNC &&
|
|
|
|
@ -2891,7 +2948,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
add_key_equal_fields(key_fields, *and_level, cond_func,
|
|
|
|
|
(Item_field*) (cond_func->arguments()[1])->real_item(),
|
|
|
|
|
equal_func,
|
|
|
|
|
cond_func->arguments(),1,usable_tables);
|
|
|
|
|
cond_func->arguments(),1,usable_tables,
|
|
|
|
|
sargables);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -2906,7 +2964,7 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
add_key_equal_fields(key_fields, *and_level, cond_func,
|
|
|
|
|
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
|
|
|
|
cond_func->functype() == Item_func::ISNULL_FUNC,
|
|
|
|
|
&tmp, 1, usable_tables);
|
|
|
|
|
&tmp, 1, usable_tables, sargables);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Item_func::OPTIMIZE_EQUAL:
|
|
|
|
@ -2924,7 +2982,7 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
while ((item= it++))
|
|
|
|
|
{
|
|
|
|
|
add_key_field(key_fields, *and_level, cond_func, item->field,
|
|
|
|
|
TRUE, &const_item, 1, usable_tables);
|
|
|
|
|
TRUE, &const_item, 1, usable_tables, sargables);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -2944,7 +3002,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
|
|
|
|
|
if (!field->eq(item->field))
|
|
|
|
|
{
|
|
|
|
|
add_key_field(key_fields, *and_level, cond_func, field,
|
|
|
|
|
TRUE, (Item **) &item, 1, usable_tables);
|
|
|
|
|
TRUE, (Item **) &item, 1, usable_tables,
|
|
|
|
|
sargables);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
it.rewind();
|
|
|
|
@ -3095,6 +3154,7 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
|
|
|
|
|
nested_join_table IN Nested join pseudo-table to process
|
|
|
|
|
end INOUT End of the key field array
|
|
|
|
|
and_level INOUT And-level
|
|
|
|
|
sargables IN/OUT Array of found sargable candidates
|
|
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
|
This function populates KEY_FIELD array with entries generated from the
|
|
|
|
@ -3118,7 +3178,8 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|
|
|
|
KEY_FIELD **end, uint *and_level)
|
|
|
|
|
KEY_FIELD **end, uint *and_level,
|
|
|
|
|
SARGABLE_PARAM **sargables)
|
|
|
|
|
{
|
|
|
|
|
List_iterator<TABLE_LIST> li(nested_join_table->nested_join->join_list);
|
|
|
|
|
table_map tables= 0;
|
|
|
|
@ -3128,12 +3189,12 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|
|
|
|
while ((table= li++))
|
|
|
|
|
{
|
|
|
|
|
if (table->nested_join)
|
|
|
|
|
add_key_fields_for_nj(table, end, and_level);
|
|
|
|
|
add_key_fields_for_nj(table, end, and_level, sargables);
|
|
|
|
|
else
|
|
|
|
|
if (!table->on_expr)
|
|
|
|
|
tables |= table->table->map;
|
|
|
|
|
}
|
|
|
|
|
add_key_fields(end, and_level, nested_join_table->on_expr, tables);
|
|
|
|
|
add_key_fields(end, and_level, nested_join_table->on_expr, tables, sargables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -3148,9 +3209,10 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|
|
|
|
tables Number of tables in join
|
|
|
|
|
cond WHERE condition (note that the function analyzes
|
|
|
|
|
join_tab[i]->on_expr too)
|
|
|
|
|
normal_tables tables not inner w.r.t some outer join (ones for which
|
|
|
|
|
normal_tables Tables not inner w.r.t some outer join (ones for which
|
|
|
|
|
we can make ref access based the WHERE clause)
|
|
|
|
|
select_lex current SELECT
|
|
|
|
|
sargables OUT Array of found sargable candidates
|
|
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
|
0 - OK
|
|
|
|
@ -3159,27 +3221,55 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|
|
|
|
uint tables, COND *cond, COND_EQUAL *cond_equal,
|
|
|
|
|
table_map normal_tables, SELECT_LEX *select_lex)
|
|
|
|
|
uint tables, COND *cond, COND_EQUAL *cond_equal,
|
|
|
|
|
table_map normal_tables, SELECT_LEX *select_lex,
|
|
|
|
|
SARGABLE_PARAM **sargables)
|
|
|
|
|
{
|
|
|
|
|
uint and_level,i,found_eq_constant;
|
|
|
|
|
KEY_FIELD *key_fields, *end, *field;
|
|
|
|
|
uint sz;
|
|
|
|
|
uint m= 1;
|
|
|
|
|
|
|
|
|
|
if (cond_equal && cond_equal->max_members)
|
|
|
|
|
m= cond_equal->max_members;
|
|
|
|
|
|
|
|
|
|
if (!(key_fields=(KEY_FIELD*)
|
|
|
|
|
thd->alloc(sizeof(key_fields[0])*
|
|
|
|
|
(thd->lex->current_select->cond_count+1)*2*m)))
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
We use the same piece of memory to store both KEY_FIELD
|
|
|
|
|
and SARGABLE_PARAM structure.
|
|
|
|
|
KEY_FIELD values are placed at the beginning this memory
|
|
|
|
|
while SARGABLE_PARAM values are put at the end.
|
|
|
|
|
All predicates that are used to fill arrays of KEY_FIELD
|
|
|
|
|
and SARGABLE_PARAM structures have at most 2 arguments
|
|
|
|
|
except BETWEEN predicates that have 3 arguments and
|
|
|
|
|
IN predicates.
|
|
|
|
|
This any predicate if it's not BETWEEN/IN can be used
|
|
|
|
|
directly to fill at most 2 array elements, either of KEY_FIELD
|
|
|
|
|
or SARGABLE_PARAM type. For a BETWEEN predicate 3 elements
|
|
|
|
|
can be filled as this predicate is considered as
|
|
|
|
|
saragable with respect to each of its argument.
|
|
|
|
|
An IN predicate can require at most 1 element as currently
|
|
|
|
|
it is considered as sargable only for its first argument.
|
|
|
|
|
Multiple equality can add elements that are filled after
|
|
|
|
|
substitution of field arguments by equal fields. There
|
|
|
|
|
can be not more than cond_equal->max_members such substitutions.
|
|
|
|
|
*/
|
|
|
|
|
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
|
|
|
|
(((thd->lex->current_select->cond_count+1)*2 +
|
|
|
|
|
thd->lex->current_select->between_count)*m+1);
|
|
|
|
|
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
|
|
|
|
return TRUE; /* purecov: inspected */
|
|
|
|
|
and_level= 0;
|
|
|
|
|
field= end= key_fields;
|
|
|
|
|
*sargables= (SARGABLE_PARAM *) key_fields +
|
|
|
|
|
(sz - sizeof((*sargables)[0].field))/sizeof(SARGABLE_PARAM);
|
|
|
|
|
/* set a barrier for the array of SARGABLE_PARAM */
|
|
|
|
|
(*sargables)[0].field= 0;
|
|
|
|
|
|
|
|
|
|
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (cond)
|
|
|
|
|
{
|
|
|
|
|
add_key_fields(&end,&and_level,cond,normal_tables);
|
|
|
|
|
add_key_fields(&end,&and_level,cond,normal_tables,sargables);
|
|
|
|
|
for (; field != end ; field++)
|
|
|
|
|
{
|
|
|
|
|
add_key_part(keyuse,field);
|
|
|
|
@ -3202,7 +3292,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|
|
|
|
*/
|
|
|
|
|
if (*join_tab[i].on_expr_ref)
|
|
|
|
|
add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref,
|
|
|
|
|
join_tab[i].table->map);
|
|
|
|
|
join_tab[i].table->map,sargables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process ON conditions for the nested joins */
|
|
|
|
@ -3212,7 +3302,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|
|
|
|
while ((table= li++))
|
|
|
|
|
{
|
|
|
|
|
if (table->nested_join)
|
|
|
|
|
add_key_fields_for_nj(table, &end, &and_level);
|
|
|
|
|
add_key_fields_for_nj(table, &end, &and_level, sargables);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -7355,7 +7445,22 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
|
|
|
|
|
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
|
|
|
|
{
|
|
|
|
|
Item_equal *item_equal= (Item_equal *) cond;
|
|
|
|
|
bool contained_const= item_equal->get_const() != NULL;
|
|
|
|
|
item_equal->update_const();
|
|
|
|
|
if (!contained_const && item_equal->get_const())
|
|
|
|
|
{
|
|
|
|
|
/* Update keys for range analysis */
|
|
|
|
|
Item_equal_iterator it(*item_equal);
|
|
|
|
|
Item_field *item_field;
|
|
|
|
|
while ((item_field= it++))
|
|
|
|
|
{
|
|
|
|
|
Field *field= item_field->field;
|
|
|
|
|
JOIN_TAB *stat= field->table->reginfo.join_tab;
|
|
|
|
|
key_map possible_keys= field->key_start;
|
|
|
|
|
possible_keys.intersect(field->table->keys_in_use_for_query);
|
|
|
|
|
stat[0].const_keys.merge(possible_keys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|