Commit ad370e3d authored by unknown's avatar unknown

Merge rurik.mysql.com:/home/igor/mysql-5.0

into  rurik.mysql.com:/home/igor/dev/mysql-5.0-0


mysql-test/r/subselect.result:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sql_select.cc:
  Auto merged
parents 5cefbe59 21d61c2b
...@@ -186,8 +186,8 @@ a b a b a b ...@@ -186,8 +186,8 @@ a b a b a b
explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 1 SIMPLE t1 ALL NULL NULL NULL NULL 3
1 SIMPLE t2 index PRIMARY PRIMARY 8 NULL 3 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1 Using index
1 SIMPLE t3 index PRIMARY PRIMARY 8 NULL 3 Using where; Using index 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 8 test.t2.b,test.t1.b 1 Using index
delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b;
select * from t3; select * from t3;
a b a b
......
...@@ -1354,10 +1354,10 @@ a ...@@ -1354,10 +1354,10 @@ a
explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 Using where; Using index
2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1167 Using where; Using index 2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
Warnings: Warnings:
Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`a`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`)))) Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))
insert into t1 values (3,31); insert into t1 values (3,31);
select * from t2 where t2.a in (select a from t1 where t1.b <> 30); select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
a a
......
...@@ -1066,8 +1066,8 @@ pthread_handler_t handle_manager(void *arg); ...@@ -1066,8 +1066,8 @@ pthread_handler_t handle_manager(void *arg);
void print_where(COND *cond,const char *info); void print_where(COND *cond,const char *info);
void print_cached_tables(void); void print_cached_tables(void);
void TEST_filesort(SORT_FIELD *sortorder,uint s_length); void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
void print_plan(JOIN* join, double read_time, double record_count, void print_plan(JOIN* join,uint idx, double record_count, double read_time,
uint idx, const char *info); double current_read_time, const char *info);
#endif #endif
void mysql_print_status(); void mysql_print_status();
/* key.cc */ /* key.cc */
......
...@@ -3319,32 +3319,45 @@ best_access_path(JOIN *join, ...@@ -3319,32 +3319,45 @@ best_access_path(JOIN *join,
{ {
key_part_map found_part= 0; key_part_map found_part= 0;
table_map found_ref= 0; table_map found_ref= 0;
uint found_ref_or_null= 0;
uint key= keyuse->key; uint key= keyuse->key;
KEY *keyinfo= table->key_info+key; KEY *keyinfo= table->key_info+key;
bool ft_key= (keyuse->keypart == FT_KEYPART); bool ft_key= (keyuse->keypart == FT_KEYPART);
uint found_ref_or_null= 0;
/* Calculate how many key segments of the current key we can use */ /* Calculate how many key segments of the current key we can use */
start_key= keyuse; start_key= keyuse;
do do
{ /* for each keypart */ { /* for each keypart */
uint keypart= keyuse->keypart; uint keypart= keyuse->keypart;
uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL; table_map best_part_found_ref= 0;
double best_prev_record_reads= DBL_MAX;
do do
{ {
if (!(remaining_tables & keyuse->used_tables) && if (!(remaining_tables & keyuse->used_tables) &&
!(found_ref_or_null & keyuse->optimize)) !(found_ref_or_null & keyuse->optimize))
{ {
found_part|= keyuse->keypart_map; found_part|= keyuse->keypart_map;
found_ref|= keyuse->used_tables; double tmp= prev_record_reads(join,
(found_ref |
keyuse->used_tables));
if (tmp < best_prev_record_reads)
{
best_part_found_ref= keyuse->used_tables;
best_prev_record_reads= tmp;
}
if (rec > keyuse->ref_table_rows) if (rec > keyuse->ref_table_rows)
rec= keyuse->ref_table_rows; rec= keyuse->ref_table_rows;
found_part_ref_or_null&= keyuse->optimize; /*
If there is one 'key_column IS NULL' expression, we can
use this ref_or_null optimisation of this field
*/
found_ref_or_null|= (keyuse->optimize &
KEY_OPTIMIZE_REF_OR_NULL);
} }
keyuse++; keyuse++;
found_ref_or_null|= found_part_ref_or_null;
} while (keyuse->table == table && keyuse->key == key && } while (keyuse->table == table && keyuse->key == key &&
keyuse->keypart == keypart); keyuse->keypart == keypart);
found_ref|= best_part_found_ref;
} while (keyuse->table == table && keyuse->key == key); } while (keyuse->table == table && keyuse->key == key);
/* /*
...@@ -3409,17 +3422,17 @@ best_access_path(JOIN *join, ...@@ -3409,17 +3422,17 @@ best_access_path(JOIN *join,
} }
} }
/* Limit the number of matched rows */ /* Limit the number of matched rows */
tmp = records; tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys.is_set(key)) if (table->used_keys.is_set(key))
{ {
/* we can use only index tree */ /* we can use only index tree */
uint keys_per_block= table->file->block_size/2/ uint keys_per_block= table->file->block_size/2/
(keyinfo->key_length+table->file->ref_length)+1; (keyinfo->key_length+table->file->ref_length)+1;
tmp = record_count*(tmp+keys_per_block-1)/keys_per_block; tmp= record_count*(tmp+keys_per_block-1)/keys_per_block;
} }
else else
tmp = record_count*min(tmp,s->worst_seeks); tmp= record_count*min(tmp,s->worst_seeks);
} }
} }
else else
...@@ -3433,7 +3446,7 @@ best_access_path(JOIN *join, ...@@ -3433,7 +3446,7 @@ best_access_path(JOIN *join,
(!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) || (!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) ||
found_part == PREV_BITS(uint,keyinfo->key_parts))) found_part == PREV_BITS(uint,keyinfo->key_parts)))
{ {
max_key_part=max_part_bit(found_part); max_key_part= max_part_bit(found_part);
/* /*
Check if quick_range could determinate how many rows we Check if quick_range could determinate how many rows we
will match will match
...@@ -3444,8 +3457,8 @@ best_access_path(JOIN *join, ...@@ -3444,8 +3457,8 @@ best_access_path(JOIN *join,
else else
{ {
/* Check if we have statistic about the distribution */ /* Check if we have statistic about the distribution */
if ((records = keyinfo->rec_per_key[max_key_part-1])) if ((records= keyinfo->rec_per_key[max_key_part-1]))
tmp = records; tmp= records;
else else
{ {
/* /*
...@@ -3506,13 +3519,13 @@ best_access_path(JOIN *join, ...@@ -3506,13 +3519,13 @@ best_access_path(JOIN *join,
/* we can use only index tree */ /* we can use only index tree */
uint keys_per_block= table->file->block_size/2/ uint keys_per_block= table->file->block_size/2/
(keyinfo->key_length+table->file->ref_length)+1; (keyinfo->key_length+table->file->ref_length)+1;
tmp = record_count*(tmp+keys_per_block-1)/keys_per_block; tmp= record_count*(tmp+keys_per_block-1)/keys_per_block;
} }
else else
tmp = record_count*min(tmp,s->worst_seeks); tmp= record_count*min(tmp,s->worst_seeks);
} }
else else
tmp = best_time; // Do nothing tmp= best_time; // Do nothing
} }
} /* not ft_key */ } /* not ft_key */
if (tmp < best_time - records/(double) TIME_FOR_COMPARE) if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
...@@ -3864,7 +3877,8 @@ optimize_straight_join(JOIN *join, table_map join_tables) ...@@ -3864,7 +3877,8 @@ optimize_straight_join(JOIN *join, table_map join_tables)
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++) for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{ {
/* Find the best access method from 's' to the current partial plan */ /* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, join->thd, join_tables, idx, record_count, read_time); best_access_path(join, s, join->thd, join_tables, idx,
record_count, read_time);
/* compute the cost of the new plan extended with 's' */ /* compute the cost of the new plan extended with 's' */
record_count*= join->positions[idx].records_read; record_count*= join->positions[idx].records_read;
read_time+= join->positions[idx].read_time; read_time+= join->positions[idx].read_time;
...@@ -3987,8 +4001,9 @@ greedy_search(JOIN *join, ...@@ -3987,8 +4001,9 @@ greedy_search(JOIN *join,
'join->best_positions' contains a complete optimal extension of the 'join->best_positions' contains a complete optimal extension of the
current partial QEP. current partial QEP.
*/ */
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, DBUG_EXECUTE("opt", print_plan(join, join->tables,
join->tables, "optimal");); record_count, read_time, read_time,
"optimal"););
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -4019,8 +4034,9 @@ greedy_search(JOIN *join, ...@@ -4019,8 +4034,9 @@ greedy_search(JOIN *join,
--rem_size; --rem_size;
++idx; ++idx;
DBUG_EXECUTE("opt", DBUG_EXECUTE("opt", print_plan(join, join->tables,
print_plan(join, read_time, record_count, idx, "extended");); record_count, read_time, read_time,
"extended"););
} while (TRUE); } while (TRUE);
} }
...@@ -4043,13 +4059,14 @@ greedy_search(JOIN *join, ...@@ -4043,13 +4059,14 @@ greedy_search(JOIN *join,
read_time the cost of the best partial plan read_time the cost of the best partial plan
search_depth maximum depth of the recursion and thus size of the found search_depth maximum depth of the recursion and thus size of the found
optimal plan (0 < search_depth <= join->tables+1). optimal plan (0 < search_depth <= join->tables+1).
prune_level pruning heuristics that should be applied during optimization prune_level pruning heuristics that should be applied during
optimization
(values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS) (values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS)
DESCRIPTION DESCRIPTION
The procedure searches for the optimal ordering of the query tables in set The procedure searches for the optimal ordering of the query tables in set
'remaining_tables' of size N, and the corresponding optimal access paths to each 'remaining_tables' of size N, and the corresponding optimal access paths to
table. The choice of a table order and an access path for each table each table. The choice of a table order and an access path for each table
constitutes a query execution plan (QEP) that fully specifies how to constitutes a query execution plan (QEP) that fully specifies how to
execute the query. execute the query.
...@@ -4159,8 +4176,8 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4159,8 +4176,8 @@ best_extension_by_limited_search(JOIN *join,
double best_record_count= DBL_MAX; double best_record_count= DBL_MAX;
double best_read_time= DBL_MAX; double best_read_time= DBL_MAX;
DBUG_EXECUTE("opt", DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
print_plan(join, read_time, record_count, idx, "part_plan");); "part_plan"););
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++) for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{ {
...@@ -4172,7 +4189,8 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4172,7 +4189,8 @@ best_extension_by_limited_search(JOIN *join,
double current_record_count, current_read_time; double current_record_count, current_read_time;
/* Find the best access method from 's' to the current partial plan */ /* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, thd, remaining_tables, idx, record_count, read_time); best_access_path(join, s, thd, remaining_tables, idx,
record_count, read_time);
/* Compute the cost of extending the plan with 's' */ /* Compute the cost of extending the plan with 's' */
current_record_count= record_count * join->positions[idx].records_read; current_record_count= record_count * join->positions[idx].records_read;
current_read_time= read_time + join->positions[idx].read_time; current_read_time= read_time + join->positions[idx].read_time;
...@@ -4181,7 +4199,12 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4181,7 +4199,12 @@ best_extension_by_limited_search(JOIN *join,
if ((current_read_time + if ((current_read_time +
current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read) current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read)
{ {
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, DBUG_EXECUTE("opt", print_plan(join, idx+1,
current_record_count,
read_time,
(current_read_time +
current_record_count /
(double) TIME_FOR_COMPARE),
"prune_by_cost");); "prune_by_cost"););
restore_prev_nj_state(s); restore_prev_nj_state(s);
continue; continue;
...@@ -4210,7 +4233,10 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4210,7 +4233,10 @@ best_extension_by_limited_search(JOIN *join,
} }
else else
{ {
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, DBUG_EXECUTE("opt", print_plan(join, idx+1,
current_record_count,
read_time,
current_read_time,
"pruned_by_heuristic");); "pruned_by_heuristic"););
restore_prev_nj_state(s); restore_prev_nj_state(s);
continue; continue;
...@@ -4238,7 +4264,8 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4238,7 +4264,8 @@ best_extension_by_limited_search(JOIN *join,
*/ */
current_read_time+= current_record_count / (double) TIME_FOR_COMPARE; current_read_time+= current_record_count / (double) TIME_FOR_COMPARE;
if (join->sort_by_table && if (join->sort_by_table &&
join->sort_by_table != join->positions[join->const_tables].table->table) join->sort_by_table !=
join->positions[join->const_tables].table->table)
/* We have to make a temp table */ /* We have to make a temp table */
current_read_time+= current_record_count; current_read_time+= current_record_count;
if ((search_depth == 1) || (current_read_time < join->best_read)) if ((search_depth == 1) || (current_read_time < join->best_read))
...@@ -4247,8 +4274,10 @@ best_extension_by_limited_search(JOIN *join, ...@@ -4247,8 +4274,10 @@ best_extension_by_limited_search(JOIN *join,
sizeof(POSITION) * (idx + 1)); sizeof(POSITION) * (idx + 1));
join->best_read= current_read_time - 0.001; join->best_read= current_read_time - 0.001;
} }
DBUG_EXECUTE("opt", print_plan(join, current_read_time, DBUG_EXECUTE("opt", print_plan(join, idx+1,
current_record_count, idx, current_record_count,
read_time,
current_read_time,
"full_plan");); "full_plan"););
} }
restore_prev_nj_state(s); restore_prev_nj_state(s);
...@@ -4269,7 +4298,6 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, ...@@ -4269,7 +4298,6 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
ha_rows rec; ha_rows rec;
double tmp; double tmp;
THD *thd= join->thd; THD *thd= join->thd;
if (!rest_tables) if (!rest_tables)
{ {
DBUG_PRINT("best",("read_time: %g record_count: %g",read_time, DBUG_PRINT("best",("read_time: %g record_count: %g",read_time,
......
...@@ -230,8 +230,8 @@ TEST_join(JOIN *join) ...@@ -230,8 +230,8 @@ TEST_join(JOIN *join)
*/ */
void void
print_plan(JOIN* join, double read_time, double record_count, print_plan(JOIN* join, uint idx, double record_count, double read_time,
uint idx, const char *info) double current_read_time, const char *info)
{ {
uint i; uint i;
POSITION pos; POSITION pos;
...@@ -245,13 +245,15 @@ print_plan(JOIN* join, double read_time, double record_count, ...@@ -245,13 +245,15 @@ print_plan(JOIN* join, double read_time, double record_count,
DBUG_LOCK_FILE; DBUG_LOCK_FILE;
if (join->best_read == DBL_MAX) if (join->best_read == DBL_MAX)
{ {
fprintf(DBUG_FILE,"%s; idx:%u, best: DBL_MAX, current:%g\n", fprintf(DBUG_FILE,
info, idx, read_time); "%s; idx:%u, best: DBL_MAX, atime: %g, itime: %g, count: %g\n",
info, idx, current_read_time, read_time, record_count);
} }
else else
{ {
fprintf(DBUG_FILE,"%s; idx: %u, best: %g, current: %g\n", fprintf(DBUG_FILE,
info, idx, join->best_read, read_time); "%s; idx:%u, best: %g, atime: %g, itime: %g, count: %g\n",
info, idx, join->best_read, current_read_time, read_time, record_count);
} }
/* Print the tables in JOIN->positions */ /* Print the tables in JOIN->positions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment