summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
authorunknown <igor@rurik.mysql.com>2006-10-17 12:25:53 -0700
committerunknown <igor@rurik.mysql.com>2006-10-17 12:25:53 -0700
commite2698fa7530fa000cb05cf6e253804788df67f68 (patch)
tree83aa27601892ef0f41ff11248ac9cd08ad027b9d /sql/sql_select.cc
parent71b67e4a534fd4d261a00d682790d5667dbc6c8f (diff)
parent711021a464a3475ceac47ec2c35e855b95dce20c (diff)
downloadmariadb-git-e2698fa7530fa000cb05cf6e253804788df67f68.tar.gz
Merge ibabaev@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into rurik.mysql.com:/home/igor/mysql-5.0-opt sql/sql_select.cc: Auto merged
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc171
1 files changed, 138 insertions, 33 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4da47e87393..1dce7390ef1 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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);
+ }
+ }
}
}