1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00
This commit is contained in:
serg@serg.mylan
2003-10-15 12:25:44 +02:00
45 changed files with 912 additions and 280 deletions

View File

@ -35,6 +35,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"ref_or_null","unique_subquery","index_subquery"
};
const key_map key_map_empty(0);
const key_map key_map_full(~0);
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
@ -114,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static uint find_shortest_key(TABLE *table, const key_map& usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
@ -831,7 +834,7 @@ JOIN::optimize()
conds,
1)));
}
}
/*
Need to tell Innobase that to play it safe, it should fetch all
@ -1558,7 +1561,7 @@ err:
JOIN *curr_join= (join->need_tmp&&join->tmp_join?
(join->tmp_join->error=join->error,join->tmp_join):
join);
thd->proc_info="end";
err= join->cleanup();
if (thd->net.report_error)
@ -1575,7 +1578,7 @@ err:
*****************************************************************************/
static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
key_map keys,ha_rows limit)
const key_map& keys,ha_rows limit)
{
int error;
DBUG_ENTER("get_quick_record_count");
@ -1637,9 +1640,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
TABLE *table;
stat_vector[i]=s;
s->keys.init();
s->const_keys.init();
s->checked_keys.init();
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
table->quick_keys=0;
table->quick_keys.clear_all();
table->reginfo.join_tab=s;
table->reginfo.not_exists_optimize=0;
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
@ -1785,24 +1792,25 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
start_keyuse=keyuse;
key=keyuse->key;
s->keys|= (key_map) 1 << key; // QQ: remove this ?
s->keys.set_bit(key); // QQ: remove this ?
refs=const_ref=0;
eq_part=0;
refs=0;
const_ref.clear_all();
eq_part.clear_all();
do
{
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
{
if (!((~found_const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
const_ref.set_bit(keyuse->keypart);
else
refs|=keyuse->used_tables;
eq_part|= (key_map) 1 << keyuse->keypart;
eq_part.set_bit(keyuse->keypart);
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
if (eq_part.is_prefix(table->key_info[key].key_parts) &&
(table->key_info[key].flags & HA_NOSAME) &&
!table->fulltext_searched)
{
@ -1858,7 +1866,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
if (s->const_keys)
if (! s->const_keys.is_clear_all())
{
ha_rows records;
SQL_SELECT *select;
@ -2095,9 +2103,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
key_map possible_keys= (field->key_start &
field->table->keys_in_use_for_query);
stat[0].keys|= possible_keys; // Add possible keys
key_map possible_keys;
possible_keys=field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
stat[0].keys.merge(possible_keys); // Add possible keys
/*
Save the following cases:
@ -2116,7 +2125,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
for (uint i=0; i<num_values; i++)
is_const&= (*value)->const_item();
if (is_const)
stat[0].const_keys |= possible_keys;
stat[0].const_keys.merge(possible_keys);
/*
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.
@ -2247,14 +2256,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
*/
static uint
max_part_bit(key_map bits)
max_part_bit(key_part_map bits)
{
uint found;
for (found=0; bits & 1 ; found++,bits>>=1) ;
return found;
}
static void
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
@ -2266,7 +2274,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
for (uint key=0 ; key < form->keys ; key++)
{
if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
if (!(form->keys_in_use_for_query.is_set(key)))
continue;
if (form->key_info[key].flags & HA_FULLTEXT)
continue; // ToDo: ft-keys in non-ft queries. SerG
@ -2457,7 +2465,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* Save ptr to first use */
if (!use->table->reginfo.join_tab->keyuse)
use->table->reginfo.join_tab->keyuse=save_pos;
use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
@ -2598,7 +2606,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
key_map found_part=0;
key_part_map found_part=0;
table_map found_ref=0;
uint key=keyuse->key;
KEY *keyinfo=table->key_info+key;
@ -2667,7 +2675,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
if (!found_ref)
{ // We found a const key
if (table->quick_keys & ((key_map) 1 << key))
if (table->quick_keys.is_set(key))
records= (double) table->quick_rows[key];
else
{
@ -2691,7 +2699,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@ -2718,7 +2726,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
Check if quick_range could determinate how many rows we
will match
*/
if (table->quick_keys & ((key_map) 1 << key) &&
if (table->quick_keys.is_set(key) &&
table->quick_key_parts[key] <= max_key_part)
tmp=records= (double) table->quick_rows[key];
else
@ -2770,7 +2778,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@ -2809,7 +2817,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
s->table->used_keys && best_key) &&
! s->table->used_keys.is_clear_all() && best_key) &&
!(s->table->force_index && best_key))
{ // Check full join
ha_rows rnd_records= s->found_records;
@ -3023,7 +3031,7 @@ get_best_combination(JOIN *join)
if (j->type == JT_SYSTEM)
continue;
if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
@ -3254,7 +3262,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select_cond=0;
join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys= (uint) ~0; /* test everything in quick */
join_tab->keys.init().set_all(); /* test everything in quick */
join_tab->info=0;
join_tab->on_expr=0;
join_tab->ref.key = -1;
@ -3336,13 +3344,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Use quick key read if it's a constant and it's not used
with key reading */
if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF ||
(uint) tab->ref.key == tab->quick->index))
{
sel->quick=tab->quick; // Use value from get_quick_...
sel->quick_keys=0;
sel->needed_reg=0;
sel->quick_keys.clear_all();
sel->needed_reg.clear_all();
}
else
{
@ -3353,12 +3361,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
if (i == join->const_tables && ref_key)
{
if (tab->const_keys && tab->table->reginfo.impossible_range)
if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1);
}
else if (tab->type == JT_ALL && ! use_quick_range)
{
if (tab->const_keys &&
if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1); // Impossible range
/*
@ -3368,9 +3377,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
if ((tab->keys & ~ tab->const_keys && i > 0) ||
(tab->const_keys && i == join->const_tables &&
join->unit->select_limit_cnt <
if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
@ -3408,13 +3417,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
else
{
sel->needed_reg=tab->needed_reg;
sel->quick_keys=0;
sel->quick_keys.clear_all();
}
if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
if (!sel->quick_keys.is_subset(tab->checked_keys) ||
!sel->needed_reg.is_subset(tab->checked_keys))
{
tab->keys=sel->quick_keys | sel->needed_reg;
tab->use_quick= (sel->needed_reg &&
(!select->quick_keys ||
tab->keys=sel->quick_keys;
tab->keys.merge(sel->needed_reg);
tab->use_quick= (!sel->needed_reg.is_clear_all() &&
(select->quick_keys.is_clear_all() ||
(select->quick &&
(select->quick->records >= 100L)))) ?
2 : 1;
@ -3479,7 +3490,7 @@ make_join_readinfo(JOIN *join, uint options)
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -3497,7 +3508,7 @@ make_join_readinfo(JOIN *join, uint options)
delete tab->quick;
tab->quick=0;
table->file->index_init(tab->ref.key);
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -3572,12 +3583,12 @@ make_join_readinfo(JOIN *join, uint options)
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
table->used_keys & ((key_map) 1 << tab->select->quick->index))
table->used_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (table->used_keys && ! (tab->select && tab->select->quick))
else if (!table->used_keys.is_clear_all() && ! (tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, table->used_keys);
tab->table->file->index_init(tab->index);
@ -3923,7 +3934,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
{
{
select_describe(join, false, false, false, info);
DBUG_RETURN(0);
}
@ -4653,6 +4664,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
table->keys_for_keyread.init();
table->keys_in_use.init();
table->read_only_keys.init();
table->quick_keys.init();
table->used_keys.init();
table->keys_in_use_for_query.init();
/* Calculate which type of fields we will store in the temporary table */
@ -5848,7 +5865,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -5885,7 +5902,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -6583,18 +6600,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return reverse;
}
static uint find_shortest_key(TABLE *table, key_map usable_keys)
static uint find_shortest_key(TABLE *table, const key_map& usable_keys)
{
uint min_length= (uint) ~0;
uint best= MAX_KEY;
for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
if (!usable_keys.is_clear_all())
{
if (usable_keys & 1)
for (uint nr=0; nr < usable_keys.length() ; nr++)
{
if (table->key_info[nr].key_length < min_length)
if (usable_keys.is_set(nr))
{
min_length=table->key_info[nr].key_length;
best=nr;
if (table->key_info[nr].key_length < min_length)
{
min_length=table->key_info[nr].key_length;
best=nr;
}
}
}
}
@ -6640,7 +6660,7 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
key_map usable_keys)
const key_map& usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
@ -6648,10 +6668,10 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
uint not_used;
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
for (nr= 0; nr < usable_keys.length(); nr++)
{
if ((usable_keys & 1) &&
if (usable_keys.is_set(nr) &&
table->key_info[nr].key_length < min_length &&
table->key_info[nr].key_parts >= ref_key_parts &&
is_subkey(table->key_info[nr].key_part, ref_key_part,
@ -6689,16 +6709,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY */
usable_keys= ~(key_map) 0;
usable_keys.set_all();
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
{
usable_keys=0;
usable_keys.clear_all();
break;
}
if (!(usable_keys&= (((Item_field*) (*tmp_order->item))->field->
part_of_sortkey)))
usable_keys.intersect(
((Item_field*) (*tmp_order->item))->field->part_of_sortkey);
if (usable_keys.is_clear_all())
break; // No usable keys
}
@ -6724,7 +6745,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
int order_direction;
uint used_key_parts;
if (!(usable_keys & ((key_map) 1 << ref_key)))
if (!usable_keys.is_set(ref_key))
{
/*
We come here when ref_key is not among usable_keys
@ -6734,8 +6755,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
if (table->used_keys & (((key_map) 1 << ref_key)))
usable_keys|= table->used_keys;
if (table->used_keys.is_set(ref_key))
usable_keys.merge(table->used_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
{
@ -6751,10 +6772,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->quick->init();
}
ref_key= new_ref_key;
}
}
}
/* Check if we get the rows in requested sorted order by using the key */
if ((usable_keys & ((key_map) 1 << ref_key)) &&
if (usable_keys.is_set(ref_key) &&
(order_direction = test_if_order_by_key(order,table,ref_key,
&used_key_parts)))
{
@ -6805,7 +6826,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* check if we can use a key to resolve the group */
/* Tables using JT_NEXT are handled here */
uint nr;
key_map keys=usable_keys;
key_map keys;
/*
If not used with LIMIT, only use keys if the whole query can be
@ -6813,12 +6834,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
retrieving all rows through an index.
*/
if (select_limit >= table->file->records)
keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
{
keys=table->file->keys_to_use_for_scanning();
keys.merge(table->used_keys);
}
else
keys.set_all();
for (nr=0; keys ; keys>>=1, nr++)
keys.intersect(usable_keys);
for (nr=0; nr < keys.length() ; nr++)
{
uint not_used;
if (keys & 1)
if (keys.is_set(nr))
{
int flag;
if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
@ -6830,7 +6858,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join_read_last);
table->file->index_init(nr);
tab->type=JT_NEXT; // Read with index_first(), index_next()
if (table->used_keys & ((key_map) 1 << nr))
if (table->used_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@ -6855,7 +6883,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
order How table should be sorted
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
Used to decide if we should use index or not
Used to decide if we should use index or not
IMPLEMENTATION
@ -8684,7 +8712,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Item *item_null= new Item_null();
CHARSET_INFO *cs= &my_charset_latin1;
DBUG_ENTER("select_describe");
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
message));
/* Don't log this into the slow query log */
@ -8718,7 +8746,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
tmp2.length(0);
item_list.empty();
item_list.push_back(new Item_int((int32)
item_list.push_back(new Item_int((int32)
join->select_lex->select_number));
item_list.push_back(new Item_string(join->select_lex->type,
strlen(join->select_lex->type),
@ -8740,21 +8768,23 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
cs));
key_map bits;
uint j;
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
if (!tab->keys.is_clear_all())
{
if (bits & 1)
{
if (tmp1.length())
tmp1.append(',');
tmp1.append(table->key_info[j].name);
}
for (j=0 ; j < tab->keys.length() ; j++)
{
if (tab->keys.is_set(j))
{
if (tmp1.length())
tmp1.append(',');
tmp1.append(table->key_info[j].name);
}
}
}
if (tmp1.length())
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
else
item_list.push_back(item_null);
item_list.push_back(item_null);
if (tab->ref.key_parts)
{
KEY *key_info=table->key_info+ tab->ref.key;
@ -8797,10 +8827,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
join->best_positions[i]. records_read,
21));
my_bool key_read=table->key_read;
if (tab->type == JT_NEXT &&
((table->used_keys & ((key_map) 1 << tab->index))))
if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
key_read=1;
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
else
@ -8809,8 +8838,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
tab->keys);
char buf[MAX_KEY/8+1];
sprintf(buff_ptr,"; Range checked for each record (index map: %s)",
tab->keys.print(buf));
buff_ptr=strend(buff_ptr);
}
else