Commit 7d81acb5 authored by unknown's avatar unknown
Browse files

Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-4.1

into mysql.com:/home/psergey/mysql-4.1-bug12915-r2


sql/sql_update.cc:
  Auto merged
parents 3867a5db 8ff8fac5
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -263,3 +263,62 @@ test
delete from t1 where count(*)=1;
ERROR HY000: Invalid use of group function
drop table t1;
create table t1 ( a int, index (a) );
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);
flush status;
select a from t1 order by a limit 1;
a
0
show status like 'handler_read%';
Variable_name	Value
Handler_read_first	1
Handler_read_key	0
Handler_read_next	0
Handler_read_prev	0
Handler_read_rnd	0
Handler_read_rnd_next	0
flush status;
update t1 set a=unix_timestamp() order by a limit 1;
show status like 'handler_read%';
Variable_name	Value
Handler_read_first	1
Handler_read_key	0
Handler_read_next	0
Handler_read_prev	0
Handler_read_rnd	1
Handler_read_rnd_next	0
flush status;
delete from t1 order by a limit 1;
show status like 'handler_read%';
Variable_name	Value
Handler_read_first	1
Handler_read_key	0
Handler_read_next	0
Handler_read_prev	0
Handler_read_rnd	0
Handler_read_rnd_next	0
flush status;
delete from t1 order by a desc limit 1;
show status like 'handler_read%';
Variable_name	Value
Handler_read_first	0
Handler_read_key	0
Handler_read_next	0
Handler_read_prev	0
Handler_read_rnd	1
Handler_read_rnd_next	9
alter table t1 disable keys;
flush status;
delete from t1 order by a limit 1;
show status like 'handler_read%';
Variable_name	Value
Handler_read_first	0
Handler_read_key	0
Handler_read_next	0
Handler_read_prev	0
Handler_read_rnd	1
Handler_read_rnd_next	9
select count(*) from t1;
count(*)
5
drop table t1;
+29 −0
Original line number Diff line number Diff line
@@ -227,4 +227,33 @@ select DATABASE();
delete from t1 where count(*)=1;
drop table t1;

# BUG#12915: Optimize "DELETE|UPDATE ... ORDER BY ... LIMIT n" to use an index
create table t1 ( a int, index (a) );
insert into t1 values (0),(0),(0),(0),(0),(0),(0),(0);

flush status;
select a from t1 order by a limit 1;
show status like 'handler_read%';

flush status;
update t1 set a=unix_timestamp() order by a limit 1;
show status like 'handler_read%';

flush status;
delete from t1 order by a limit 1;
show status like 'handler_read%';

flush status;
delete from t1 order by a desc limit 1;
show status like 'handler_read%';

alter table t1 disable keys;

flush status;
delete from t1 order by a limit 1;
show status like 'handler_read%';

select count(*) from t1;

drop table t1;
# End of 4.1 tests
+2 −0
Original line number Diff line number Diff line
@@ -1105,6 +1105,8 @@ void change_byte(byte *,uint,char,char);
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
		      SQL_SELECT *select,
		      int use_record_cache, bool print_errors);
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, 
                          bool print_error, uint idx);
void end_read_record(READ_RECORD *info);
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
		 uint s_length, SQL_SELECT *select,
+90 −0
Original line number Diff line number Diff line
@@ -582,6 +582,96 @@ SEL_ARG *SEL_ARG::clone_tree()
  return root;
}


/*
  Find the best index to retrieve first N records in given order

  SYNOPSIS
    get_index_for_order()
      table  Table to be accessed
      order  Required ordering
      limit  Number of records that will be retrieved

  DESCRIPTION
    Find the best index that allows to retrieve first #limit records in the 
    given order cheaper then one would retrieve them using full table scan.

  IMPLEMENTATION
    Run through all table indexes and find the shortest index that allows
    records to be retrieved in given order. We look for the shortest index
    as we will have fewer index pages to read with it.

    This function is used only by UPDATE/DELETE, so we take into account how
    the UPDATE/DELETE code will work:
     * index can only be scanned in forward direction
     * HA_EXTRA_KEYREAD will not be used
    Perhaps these assumptions could be relaxed

  RETURN
    index number
    MAX_KEY if no such index was found.
*/

uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit)
{
  uint idx;
  uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1;
  ORDER *ord;
  
  for (ord= order; ord; ord= ord->next)
    if (!ord->asc)
      return MAX_KEY;

  for (idx= 0; idx < table->keys; idx++)
  {
    if (!(table->keys_in_use_for_query.is_set(idx)))
      continue;
    KEY_PART_INFO *keyinfo= table->key_info[idx].key_part;
    uint partno= 0;
    
    /* 
      The below check is sufficient considering we now have either BTREE 
      indexes (records are returned in order for any index prefix) or HASH 
      indexes (records are not returned in order for any index prefix).
    */
    if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER))
      continue;
    for (ord= order; ord; ord= ord->next, partno++)
    {
      Item *item= order->item[0];
      if (!(item->type() == Item::FIELD_ITEM &&
           ((Item_field*)item)->field->eq(keyinfo[partno].field)))
        break;
    }
    
    if (!ord && table->key_info[idx].key_length < match_key_len)
    {
      /* 
        Ok, the ordering is compatible and this key is shorter then
        previous match (we want shorter keys as we'll have to read fewer
        index pages for the same number of records)
      */
      match_key= idx;
      match_key_len= table->key_info[idx].key_length;
    }
  }

  if (match_key != MAX_KEY)
  {
    /* 
      Found an index that allows records to be retrieved in the requested 
      order. Now we'll check if using the index is cheaper then doing a table
      scan.
    */
    double full_scan_time= table->file->scan_time();
    double index_scan_time= table->file->read_time(match_key, 1, limit);
    if (index_scan_time > full_scan_time)
      match_key= MAX_KEY;
  }
  return match_key;
}


/*
  Test if a key can be used in different ranges

+2 −0
Original line number Diff line number Diff line
@@ -167,4 +167,6 @@ class FT_SELECT: public QUICK_SELECT {
QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
				       struct st_table_ref *ref);

uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);

#endif
Loading