Commit a19eee45 authored by timour@mysql.com's avatar timour@mysql.com

Manual merge with implementation for WL#1724

parent f2a78b13
...@@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (!head->used_keys.is_clear_all()) if (!head->used_keys.is_clear_all())
{ {
int key_for_use= find_shortest_key(head, &head->used_keys); int key_for_use= find_shortest_key(head, &head->used_keys);
double key_read_time= get_index_only_read_time(&param, records, double key_read_time= (get_index_only_read_time(&param, records,
key_for_use); key_for_use) +
(double) records / TIME_FOR_COMPARE);
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, " DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
"read time %g", key_for_use, key_read_time)); "read time %g", key_for_use, key_read_time));
if (key_read_time < read_time) if (key_read_time < read_time)
...@@ -2176,6 +2177,12 @@ skip_to_ror_scan: ...@@ -2176,6 +2177,12 @@ skip_to_ror_scan:
assumed that each time we read the next key from the index, the handler assumed that each time we read the next key from the index, the handler
performs a random seek, thus the cost is proportional to the number of performs a random seek, thus the cost is proportional to the number of
blocks read. blocks read.
TODO:
Move this to handler->read_time() by adding a flag 'index-only-read' to
this call. The reason for doing this is that the current function doesn't
handle the case when the row is stored in the b-tree (like in innodb
clustered index)
*/ */
inline double get_index_only_read_time(const PARAM* param, ha_rows records, inline double get_index_only_read_time(const PARAM* param, ha_rows records,
...@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records, ...@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
return read_time; return read_time;
} }
typedef struct st_ror_scan_info typedef struct st_ror_scan_info
{ {
uint idx; /* # of used key in param->keys */ uint idx; /* # of used key in param->keys */
...@@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, ...@@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
tree->n_ror_scans++; tree->n_ror_scans++;
tree->ror_scans_map.set_bit(idx); tree->ror_scans_map.set_bit(idx);
} }
double cpu_cost= (double) found_records / TIME_FOR_COMPARE;
if (found_records != HA_POS_ERROR && found_records > 2 && if (found_records != HA_POS_ERROR && found_records > 2 &&
read_index_only && read_index_only &&
(param->table->file->index_flags(keynr, param->max_key_part,1) & (param->table->file->index_flags(keynr, param->max_key_part,1) &
HA_KEYREAD_ONLY) && HA_KEYREAD_ONLY) &&
!(pk_is_clustered && keynr == param->table->primary_key)) !(pk_is_clustered && keynr == param->table->primary_key))
/* We can resolve this by only reading through this key. */ /* We can resolve this by only reading through this key. */
found_read_time= get_index_only_read_time(param,found_records,keynr); found_read_time= get_index_only_read_time(param,found_records,keynr) +
cpu_cost;
else else
/* /*
cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks) cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function. The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
*/ */
found_read_time= (param->table->file->read_time(keynr, found_read_time= param->table->file->read_time(keynr,
param->range_count, param->range_count,
found_records)+ found_records) +
(double) found_records / TIME_FOR_COMPARE); cpu_cost;
DBUG_PRINT("info",("read_time: %g found_read_time: %g", DBUG_PRINT("info",("read_time: %g found_read_time: %g",
read_time, found_read_time)); read_time, found_read_time));
...@@ -3424,6 +3434,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, ...@@ -3424,6 +3434,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
{ {
uint maybe_null=(uint) field->real_maybe_null(), copies; uint maybe_null=(uint) field->real_maybe_null(), copies;
uint field_length=field->pack_length()+maybe_null; uint field_length=field->pack_length()+maybe_null;
bool optimize_range;
SEL_ARG *tree; SEL_ARG *tree;
char *str, *str2; char *str, *str2;
DBUG_ENTER("get_mm_leaf"); DBUG_ENTER("get_mm_leaf");
...@@ -3454,6 +3465,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, ...@@ -3454,6 +3465,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
((Field_str*)field)->charset() != conf_func->compare_collation()) ((Field_str*)field)->charset() != conf_func->compare_collation())
DBUG_RETURN(0); DBUG_RETURN(0);
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
key_part->part);
if (type == Item_func::LIKE_FUNC) if (type == Item_func::LIKE_FUNC)
{ {
bool like_error; bool like_error;
...@@ -3461,8 +3475,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, ...@@ -3461,8 +3475,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
String tmp(buff1,sizeof(buff1),value->collation.collation),*res; String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
uint length,offset,min_length,max_length; uint length,offset,min_length,max_length;
if (!field->optimize_range(param->real_keynr[key_part->key], if (!optimize_range)
key_part->part))
DBUG_RETURN(0); // Can't optimize this DBUG_RETURN(0); // Can't optimize this
if (!(res= value->val_str(&tmp))) if (!(res= value->val_str(&tmp)))
DBUG_RETURN(&null_element); DBUG_RETURN(&null_element);
...@@ -3527,8 +3540,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, ...@@ -3527,8 +3540,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
} }
if (!field->optimize_range(param->real_keynr[key_part->key], if (!optimize_range &&
key_part->part) &&
type != Item_func::EQ_FUNC && type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC) type != Item_func::EQUAL_FUNC)
DBUG_RETURN(0); // Can't optimize this DBUG_RETURN(0); // Can't optimize this
...@@ -3542,7 +3554,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, ...@@ -3542,7 +3554,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
field->cmp_type() != value->result_type()) field->cmp_type() != value->result_type())
DBUG_RETURN(0); DBUG_RETURN(0);
if (value->save_in_field(field, 1) < 0) if (value->save_in_field_no_warnings(field, 1) < 0)
{ {
/* This happens when we try to insert a NULL field in a not null column */ /* This happens when we try to insert a NULL field in a not null column */
DBUG_RETURN(&null_element); // cmp with NULL is never TRUE DBUG_RETURN(&null_element); // cmp with NULL is never TRUE
...@@ -3736,14 +3748,15 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -3736,14 +3748,15 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if (*key2 && !(*key2)->simple_key()) if (*key2 && !(*key2)->simple_key())
flag|=CLONE_KEY2_MAYBE; flag|=CLONE_KEY2_MAYBE;
*key1=key_and(*key1,*key2,flag); *key1=key_and(*key1,*key2,flag);
if ((*key1)->type == SEL_ARG::IMPOSSIBLE) if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{ {
tree1->type= SEL_TREE::IMPOSSIBLE; tree1->type= SEL_TREE::IMPOSSIBLE;
DBUG_RETURN(tree1); DBUG_RETURN(tree1);
} }
result_keys.set_bit(key1 - tree1->keys); result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG #ifdef EXTRA_DEBUG
(*key1)->test_use_count(*key1); if (*key1)
(*key1)->test_use_count(*key1);
#endif #endif
} }
} }
...@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) ...@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
return key1; return key1;
} }
if ((key1->min_flag | key2->min_flag) & GEOM_FLAG)
{
key1->free_tree();
key2->free_tree();
return 0; // Can't optimize this
}
key1->use_count--; key1->use_count--;
key2->use_count--; key2->use_count--;
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
...@@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) ...@@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
key1->use_count--; key1->use_count--;
key2->use_count--; key2->use_count--;
if (key1->part != key2->part) if (key1->part != key2->part ||
(key1->min_flag | key2->min_flag) & GEOM_FLAG)
{ {
key1->free_tree(); key1->free_tree();
key2->free_tree(); key2->free_tree();
...@@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root) ...@@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
ulong count=count_key_part_usage(root,pos->next_key_part); ulong count=count_key_part_usage(root,pos->next_key_part);
if (count > pos->next_key_part->use_count) if (count > pos->next_key_part->use_count)
{ {
sql_print_error("Note: Use_count: Wrong count for key at %lx, %lu should be %lu", sql_print_error("Note: Use_count: Wrong count for key at 0x%lx, %lu should be %lu",
pos,pos->next_key_part->use_count,count); pos,pos->next_key_part->use_count,count);
return; return;
} }
...@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root) ...@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
} }
} }
if (e_count != elements) if (e_count != elements)
sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at %lx", sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at 0x%lx",
e_count, elements, (gptr) this); e_count, elements, (gptr) this);
} }
......
This diff is collapsed.
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