Commit be69f13d authored by gshchepa/uchum@gleb.loc's avatar gshchepa/uchum@gleb.loc
Browse files

Merge gshchepa@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  gleb.loc:/home/uchum/work/bk/mysql-5.0-opt-28598
parents 85b6e3f0 e16953df
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -123,3 +123,5 @@ release_lock("lock27563")
drop table t1, t2;
drop function bug27563;
drop procedure proc27563;
PREPARE stmt FROM 'EXPLAIN SELECT * FROM t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40 WHERE a1=a2 AND a2=a3 AND a3=a4 AND a4=a5 AND a5=a6 AND a6=a7 AND a7=a8 AND a8=a9 AND a9=a10 AND a10=a11 AND a11=a12 AND a12=a13 AND a13=a14 AND a14=a15 AND a15=a16 AND a16=a17 AND a17=a18 AND a18=a19 AND a19=a20 AND a20=a21 AND a21=a22 AND a22=a23 AND a23=a24 AND a24=a25 AND a25=a26 AND a26=a27 AND a27=a28 AND a28=a29 AND a29=a30 AND a30=a31 AND a31=a32 AND a32=a33 AND a33=a34 AND a34=a35 AND a35=a36 AND a36=a37 AND a37=a38 AND a38=a39 AND a39=a40  ';
EXECUTE stmt;
+53 −0
Original line number Diff line number Diff line
@@ -249,3 +249,56 @@ select release_lock("lock27563");
drop table t1, t2;
drop function bug27563;
drop procedure proc27563;

#
# Bug#28598: mysqld crash when killing a long-running explain query.
#
--disable_query_log
connection con1;
let $ID= `select connection_id()`;
let $tab_count= 40;

let $i= $tab_count;
while ($i)
{
  eval CREATE TABLE t$i (a$i int, KEY(a$i));
  eval INSERT INTO t$i VALUES (1),(2),(3),(4),(5),(6),(7);
  dec $i ;
}
set session optimizer_search_depth=0;

let $i=$tab_count;
while ($i)
{
 let $a= a$i;
 let $t= t$i;
 dec $i;
 if ($i)
 {
   let $comma=,;
   let $from=$comma$t$from;
   let $where=a$i=$a $and $where;
 }
 if (!$i) 
 {
   let $from=FROM $t$from;
   let $where=WHERE $where;
 }
 let $and=AND;
}

--enable_query_log
eval PREPARE stmt FROM 'EXPLAIN SELECT * $from $where';
send EXECUTE stmt;
--disable_query_log

connection con2;
real_sleep 2;
eval kill query $ID;
let $i= $tab_count;
while ($i)
{
  eval DROP TABLE t$i;
  dec $i ;
}
--enable_query_log
+53 −40
Original line number Diff line number Diff line
@@ -49,15 +49,15 @@ 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,
			       table_map used_tables);
static void choose_plan(JOIN *join,table_map join_tables);
static bool choose_plan(JOIN *join,table_map join_tables);

static void best_access_path(JOIN *join, JOIN_TAB *s, THD *thd,
                             table_map remaining_tables, uint idx,
                             double record_count, double read_time);
static void optimize_straight_join(JOIN *join, table_map join_tables);
static void greedy_search(JOIN *join, table_map remaining_tables,
static bool greedy_search(JOIN *join, table_map remaining_tables,
                             uint depth, uint prune_level);
static void best_extension_by_limited_search(JOIN *join,
static bool best_extension_by_limited_search(JOIN *join,
                                             table_map remaining_tables,
                                             uint idx, double record_count,
                                             double read_time, uint depth,
@@ -69,7 +69,7 @@ static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
  TODO: 'find_best' is here only temporarily until 'greedy_search' is
  tested and approved.
*/
static void find_best(JOIN *join,table_map rest_tables,uint index,
static bool find_best(JOIN *join,table_map rest_tables,uint index,
		      double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join,table_map found_ref);
@@ -2717,7 +2717,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
  if (join->const_tables != join->tables)
  {
    optimize_keyuse(join, keyuse_array);
    choose_plan(join, all_table_map & ~join->const_table_map);
    if (choose_plan(join, all_table_map & ~join->const_table_map))
      DBUG_RETURN(TRUE);
  }
  else
  {
@@ -4307,11 +4308,12 @@ best_access_path(JOIN *join,
    the array 'join->best_positions', and the cost of the plan in
    'join->best_read'.

  RETURN
    None
  RETURN VALUES
    FALSE       ok
    TRUE        Fatal error
*/

static void
static bool
choose_plan(JOIN *join, table_map join_tables)
{
  uint search_depth= join->thd->variables.optimizer_search_depth;
@@ -4344,14 +4346,16 @@ choose_plan(JOIN *join, table_map join_tables)
        the greedy version. Will be removed when greedy_search is approved.
      */
      join->best_read= DBL_MAX;
      find_best(join, join_tables, join->const_tables, 1.0, 0.0);
      if (find_best(join, join_tables, join->const_tables, 1.0, 0.0))
        DBUG_RETURN(TRUE);
    } 
    else
    {
      if (search_depth == 0)
        /* Automatically determine a reasonable value for 'search_depth' */
        search_depth= determine_search_depth(join);
      greedy_search(join, join_tables, search_depth, prune_level);
      if (greedy_search(join, join_tables, search_depth, prune_level))
        DBUG_RETURN(TRUE);
    }
  }

@@ -4361,7 +4365,7 @@ choose_plan(JOIN *join, table_map join_tables)
  */
  if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS)
    join->thd->status_var.last_query_cost= join->best_read;
  DBUG_VOID_RETURN;
  DBUG_RETURN(FALSE);
}


@@ -4589,11 +4593,12 @@ optimize_straight_join(JOIN *join, table_map join_tables)
    In the future, 'greedy_search' might be extended to support other
    implementations of 'best_extension', e.g. some simpler quadratic procedure.

  RETURN
    None
  RETURN VALUES
    FALSE       ok
    TRUE        Fatal error
*/

static void
static bool
greedy_search(JOIN      *join,
              table_map remaining_tables,
              uint      search_depth,
@@ -4615,8 +4620,9 @@ greedy_search(JOIN *join,
  do {
    /* Find the extension of the current QEP with the lowest cost */
    join->best_read= DBL_MAX;
    best_extension_by_limited_search(join, remaining_tables, idx, record_count,
                                     read_time, search_depth, prune_level);
    if (best_extension_by_limited_search(join, remaining_tables, idx, record_count,
                                         read_time, search_depth, prune_level))
      DBUG_RETURN(TRUE);

    if (size_remain <= search_depth)
    {
@@ -4627,7 +4633,7 @@ greedy_search(JOIN *join,
      DBUG_EXECUTE("opt", print_plan(join, join->tables,
                                     record_count, read_time, read_time,
                                     "optimal"););
      DBUG_VOID_RETURN;
      DBUG_RETURN(FALSE);
    }

    /* select the first table in the optimal extension as most promising */
@@ -4772,11 +4778,12 @@ greedy_search(JOIN *join,
    The parameter 'search_depth' provides control over the recursion
    depth, and thus the size of the resulting optimal plan.

  RETURN
    None
  RETURN VALUES
    FALSE       ok
    TRUE        Fatal error
*/

static void
static bool
best_extension_by_limited_search(JOIN      *join,
                                 table_map remaining_tables,
                                 uint      idx,
@@ -4785,11 +4792,11 @@ best_extension_by_limited_search(JOIN *join,
                                 uint      search_depth,
                                 uint      prune_level)
{
  DBUG_ENTER("best_extension_by_limited_search");

  THD *thd= join->thd;
  if (thd->killed)  // Abort
    return;

  DBUG_ENTER("best_extension_by_limited_search");
    DBUG_RETURN(TRUE);

  /* 
     'join' is a partial plan with lower cost than the best plan so far,
@@ -4869,15 +4876,14 @@ best_extension_by_limited_search(JOIN *join,
      if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) )
      { /* Recursively expand the current partial plan */
        swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
        best_extension_by_limited_search(join,
        if (best_extension_by_limited_search(join,
                                             remaining_tables & ~real_table_bit,
                                             idx + 1,
                                             current_record_count,
                                             current_read_time,
                                             search_depth - 1,
                                         prune_level);
        if (thd->killed)
          DBUG_VOID_RETURN;
                                             prune_level))
          DBUG_RETURN(TRUE);
        swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
      }
      else
@@ -4906,19 +4912,26 @@ best_extension_by_limited_search(JOIN *join,
      restore_prev_nj_state(s);
    }
  }
  DBUG_VOID_RETURN;
  DBUG_RETURN(FALSE);
}


/*
  TODO: this function is here only temporarily until 'greedy_search' is
  tested and accepted.

  RETURN VALUES
    FALSE       ok
    TRUE        Fatal error
*/
static void
static bool
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
	  double read_time)
{
  DBUG_ENTER("find_best");
  THD *thd= join->thd;
  if (thd->killed)
    DBUG_RETURN(TRUE);
  if (!rest_tables)
  {
    DBUG_PRINT("best",("read_time: %g  record_count: %g",read_time,
@@ -4935,10 +4948,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
	     sizeof(POSITION)*idx);
      join->best_read= read_time - 0.001;
    }
    return;
    DBUG_RETURN(FALSE);
  }
  if (read_time+record_count/(double) TIME_FOR_COMPARE >= join->best_read)
    return;					/* Found better before */
    DBUG_RETURN(FALSE);					/* Found better before */

  JOIN_TAB *s;
  double best_record_count=DBL_MAX,best_read_time=DBL_MAX;
@@ -4971,10 +4984,9 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
	  best_read_time=current_read_time;
	}
	swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
	find_best(join,rest_tables & ~real_table_bit,idx+1,
		  current_record_count,current_read_time);
        if (thd->killed)
          return;
	if (find_best(join,rest_tables & ~real_table_bit,idx+1,
                      current_record_count,current_read_time))
          DBUG_RETURN(TRUE);
	swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
      }
      restore_prev_nj_state(s);
@@ -4982,6 +4994,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
	break;				// Don't test all combinations
    }
  }
  DBUG_RETURN(FALSE);
}