diff options
author | unknown <igor@rurik.mysql.com> | 2006-10-17 12:25:53 -0700 |
---|---|---|
committer | unknown <igor@rurik.mysql.com> | 2006-10-17 12:25:53 -0700 |
commit | e2698fa7530fa000cb05cf6e253804788df67f68 (patch) | |
tree | 83aa27601892ef0f41ff11248ac9cd08ad027b9d /sql/sql_select.cc | |
parent | 71b67e4a534fd4d261a00d682790d5667dbc6c8f (diff) | |
parent | 711021a464a3475ceac47ec2c35e855b95dce20c (diff) | |
download | mariadb-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.cc | 171 |
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); + } + } } } |