Commit 8bd47162 authored by Sergei Petrunia's avatar Sergei Petrunia

Merge ../10.1-orderby-fixes into 10.1

parents 26e048ff f8f8a59c
......@@ -74,7 +74,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 17 Using sort_union(i1,i2); Using where
explain select * from t0 where key2 = 45 or key1 <=> null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using where
1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using index condition
explain select * from t0 where key2 = 45 or key1 is not null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where
......
......@@ -1002,7 +1002,7 @@ insert into t2 (b) values (null), (null), (null);
set optimizer_switch='extended_keys=on';
explain select a from t1 where b is null order by a desc limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref b b 9 const 2 Using where; Using filesort
1 SIMPLE t1 index b PRIMARY 8 NULL 3 Using where
select a from t1 where b is null order by a desc limit 2;
a
3
......
......@@ -2090,10 +2090,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort
1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where
1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00
Warnings:
Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b`
Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b`
SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
......
......@@ -2101,10 +2101,10 @@ SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where; Using filesort
1 SIMPLE t1 ref PRIMARY,idx idx 4 const 2 100.00 Using where
1 SIMPLE t2 ref c c 5 test.t1.a 2 100.00
Warnings:
Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (((`test`.`t1`.`pk` between 5 and 6) and isnull(`test`.`t1`.`b`)) or (`test`.`t1`.`b` = 5))) order by `test`.`t1`.`b`
Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` join `test`.`t1` where ((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = 5)) order by `test`.`t1`.`b`
SELECT t1.b, t2.c, t2.d FROM t2 LEFT JOIN t1 ON t2.c = t1.a
WHERE t1.pk BETWEEN 5 AND 6 AND t1.b IS NULL OR t1.b = 5
ORDER BY t1.b;
......
......@@ -2196,3 +2196,48 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index
drop table t1,t2,t3;
#
# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
#
create table t1(a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, c int, key(a), key(b));
insert into t2
select
A.a + B.a* 10 + C.a * 100,
A.a + B.a* 10 + C.a * 100,
12345
from
t1 A, t1 B, t1 C;
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or a<44;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
# Here, conditions b will not be removed, because "c<44" is not sargable
# and hence (b.. and .. b) part is not analyzed at all:
explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15)))
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44))
# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0
drop table t1,t2;
......@@ -2198,4 +2198,49 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t2 range a a 5 NULL 1 Using where; Using index
drop table t1,t2,t3;
#
# MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
#
create table t1(a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, c int, key(a), key(b));
insert into t2
select
A.a + B.a* 10 + C.a * 100,
A.a + B.a* 10 + C.a * 100,
12345
from
t1 A, t1 B, t1 C;
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or a<44;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 range a,b a 5 NULL 43 100.00 Using index condition; Rowid-ordered scan
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`a` < 44)
# Here, conditions b will not be removed, because "c<44" is not sargable
# and hence (b.. and .. b) part is not analyzed at all:
explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44) or ((`test`.`t2`.`b` > 25) and (`test`.`t2`.`b` < 15)))
# EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL b NULL NULL NULL 1000 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` < 44))
# Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where 0
drop table t1,t2;
set optimizer_switch=@mrr_icp_extra_tmp;
......@@ -1745,3 +1745,35 @@ explain select * from t3, t2 where t2.a < t3.b and t3.a=1;
--echo # The second table should use 'range':
explain select * from t3, t2 where t3.b > t2.a and t3.a=1;
drop table t1,t2,t3;
--echo #
--echo # MDEV-6480: Remove conditions for which range optimizer returned SEL_ARG::IMPOSSIBLE.
--echo #
create table t1(a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, c int, key(a), key(b));
insert into t2
select
A.a + B.a* 10 + C.a * 100,
A.a + B.a* 10 + C.a * 100,
12345
from
t1 A, t1 B, t1 C;
--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or a<44;
--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where a < 44 or (b > 25 and b < 15);
--echo # Here, conditions b will not be removed, because "c<44" is not sargable
--echo # and hence (b.. and .. b) part is not analyzed at all:
explain extended select * from t2 where c < 44 or (b > 25 and b < 15);
--echo # EXPLAIN EXTENDED should show that 'b > 25 and b < 15' is removed from the WHERE:
explain extended select * from t2 where (b > 25 and b < 15) or c < 44;
--echo # Try a case where both OR parts produce SEL_ARG::IMPOSSIBLE:
explain extended select * from t2 where (b > 25 and b < 15) or (a>55 and a<44);
drop table t1,t2;
......@@ -829,6 +829,12 @@ class RANGE_OPT_PARAM
*/
bool remove_jump_scans;
/*
TRUE <=> Range analyzer should remove parts of condition that are found
to be always FALSE.
*/
bool remove_false_where_parts;
/*
used_key_no -> table_key_no translation table. Only makes sense if
using_real_indexes==TRUE
......@@ -908,7 +914,7 @@ static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *fie
static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
KEY_PART *key_part,
Item_func::Functype type,Item *value);
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond);
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond);
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
......@@ -2941,7 +2947,8 @@ static int fill_used_fields_bitmap(PARAM *param)
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
table_map prev_tables,
ha_rows limit, bool force_quick_range,
bool ordered_output)
bool ordered_output,
bool remove_false_parts_of_where)
{
uint idx;
double scan_time;
......@@ -3000,6 +3007,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.imerge_cost_buff_size= 0;
param.using_real_indexes= TRUE;
param.remove_jump_scans= TRUE;
param.remove_false_where_parts= remove_false_parts_of_where;
param.force_default_mrr= ordered_output;
param.possible_keys.clear_all();
......@@ -3073,7 +3081,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (cond)
{
if ((tree= get_mm_tree(&param,cond)))
if ((tree= get_mm_tree(&param, &cond)))
{
if (tree->type == SEL_TREE::IMPOSSIBLE)
{
......@@ -3415,7 +3423,7 @@ double records_in_column_ranges(PARAM *param, uint idx,
TRUE otherwise
*/
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
{
uint keynr;
uint max_quick_key_parts= 0;
......@@ -3425,7 +3433,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
table->cond_selectivity= 1.0;
if (!cond || table_records == 0)
if (!*cond || table_records == 0)
DBUG_RETURN(FALSE);
if (table->pos_in_table_list->schema_table)
......@@ -3529,6 +3537,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
param.old_root= thd->mem_root;
param.table= table;
param.is_ror_scan= FALSE;
param.remove_false_where_parts= true;
if (create_key_parts_for_pseudo_indexes(&param, used_fields))
goto free_alloc;
......@@ -3606,7 +3615,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
ulong check_rows=
MY_MIN(thd->variables.optimizer_selectivity_sampling_limit,
(ulong) (table_records * SELECTIVITY_SAMPLING_SHARE));
if (cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD &&
if (*cond && check_rows > SELECTIVITY_SAMPLING_THRESHOLD &&
thd->variables.optimizer_use_condition_selectivity > 4)
{
find_selective_predicates_list_processor_data *dt=
......@@ -3617,8 +3626,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
DBUG_RETURN(TRUE);
dt->list.empty();
dt->table= table;
if (cond->walk(&Item::find_selective_predicates_list_processor, 0,
(uchar*) dt))
if ((*cond)->walk(&Item::find_selective_predicates_list_processor, 0,
(uchar*) dt))
DBUG_RETURN(TRUE);
if (dt->list.elements > 0)
{
......@@ -3951,6 +3960,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
/* range_par->cond doesn't need initialization */
range_par->prev_tables= range_par->read_tables= 0;
range_par->current_table= table->map;
/* It should be possible to switch the following ON: */
range_par->remove_false_where_parts= false;
range_par->keys= 1; // one index
range_par->using_real_indexes= FALSE;
......@@ -3967,7 +3978,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
SEL_TREE *tree;
int res;
tree= get_mm_tree(range_par, pprune_cond);
tree= get_mm_tree(range_par, &pprune_cond);
if (!tree)
goto all_used;
......@@ -7855,15 +7866,33 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
DBUG_RETURN(ftree);
}
/* make a select tree of all keys in condition */
/*
make a select tree of all keys in condition
@param param Context
@param cond INOUT condition to perform range analysis on.
@detail
Range analysis may infer that some conditions are never true.
- If the condition is never true, SEL_TREE(type=IMPOSSIBLE) is returned
- if parts of condition are never true, the function may remove these parts
from the condition 'cond'. Sometimes, this will cause the condition to
be substituted for something else.
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
@return
NULL - Could not infer anything from condition cond.
SEL_TREE with type=IMPOSSIBLE - condition can never be true.
*/
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
SEL_TREE *tree=0;
SEL_TREE *ftree= 0;
Item_field *field_item= 0;
bool inv= FALSE;
Item *value= 0;
Item *cond= *cond_ptr;
DBUG_ENTER("get_mm_tree");
if (cond->type() == Item::COND_ITEM)
......@@ -7876,31 +7905,75 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
Item *item;
while ((item=li++))
{
SEL_TREE *new_tree= get_mm_tree(param,item);
SEL_TREE *new_tree= get_mm_tree(param,li.ref());
if (param->statement_should_be_aborted())
DBUG_RETURN(NULL);
tree= tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
{
/*
Do not remove 'item' from 'cond'. We return a SEL_TREE::IMPOSSIBLE
and that is sufficient for the caller to see that the whole
condition is never true.
*/
break;
}
}
}
else
{ // COND OR
tree= get_mm_tree(param,li++);
bool replace_cond= false;
Item *replacement_item= li++;
tree= get_mm_tree(param, li.ref());
if (param->statement_should_be_aborted())
DBUG_RETURN(NULL);
if (tree)
{
if (tree->type == SEL_TREE::IMPOSSIBLE &&
param->remove_false_where_parts)
{
/* See the other li.remove() call below */
li.remove();
if (((Item_cond*)cond)->argument_list()->elements <= 1)
replace_cond= true;
}
Item *item;
while ((item=li++))
{
SEL_TREE *new_tree=get_mm_tree(param,item);
SEL_TREE *new_tree=get_mm_tree(param,li.ref());
if (new_tree == NULL || param->statement_should_be_aborted())
DBUG_RETURN(NULL);
tree= tree_or(param,tree,new_tree);
if (tree == NULL || tree->type == SEL_TREE::ALWAYS)
{
replacement_item= *li.ref();
break;
}
if (new_tree && new_tree->type == SEL_TREE::IMPOSSIBLE &&
param->remove_false_where_parts)
{
/*
This is a condition in form
cond = item1 OR ... OR item_i OR ... itemN
and item_i produces SEL_TREE(IMPOSSIBLE). We should remove item_i
from cond. This may cause 'cond' to become a degenerate,
one-way OR. In that case, we replace 'cond' with the remaining
item_i.
*/
li.remove();
if (((Item_cond*)cond)->argument_list()->elements <= 1)
replace_cond= true;
}
else
replacement_item= *li.ref();
}
if (replace_cond)
*cond_ptr= replacement_item;
}
}
DBUG_RETURN(tree);
......@@ -10617,6 +10690,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
param->table->quick_condition_rows=
MY_MIN(param->table->quick_condition_rows, rows);
param->table->quick_rows[keynr]= rows;
param->table->quick_costs[keynr]= cost->total_cost();
}
}
/* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
......
......@@ -994,7 +994,7 @@ class SQL_SELECT :public Sql_alloc {
{
key_map tmp;
tmp.set_all();
return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0;
return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE, FALSE) < 0;
}
/*
RETURN
......@@ -1011,7 +1011,7 @@ class SQL_SELECT :public Sql_alloc {
}
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
ha_rows limit, bool force_quick_range,
bool ordered_output);
bool ordered_output, bool remove_false_parts_of_where);
};
......@@ -1036,7 +1036,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond, int *error);
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond);
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
......
......@@ -69,7 +69,7 @@ struct st_sargable_param;
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves,
COND *conds, DYNAMIC_ARRAY *keyuse);
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
uint tables, COND *conds,
......@@ -1338,7 +1338,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
/* Calculate how to do the join */
THD_STAGE_INFO(thd, stage_statistics);
if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
if (make_join_statistics(this, select_lex->leaf_tables, &keyuse) ||
thd->is_fatal_error)
{
DBUG_PRINT("error",("Error: make_join_statistics() failed"));
......@@ -3355,7 +3355,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
select->head=table;
table->reginfo.impossible_range=0;
if ((error= select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,
limit, 0, FALSE)) == 1)
limit, 0, FALSE,
TRUE /* remove_where_parts*/)) == 1)
DBUG_RETURN(select->quick->records);
if (error == -1)
{
......@@ -3393,7 +3394,7 @@ typedef struct st_sargable_param
static bool
make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
COND *conds, DYNAMIC_ARRAY *keyuse_array)
DYNAMIC_ARRAY *keyuse_array)
{
int error= 0;
TABLE *table;
......@@ -3597,10 +3598,10 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
if (conds || outer_join)
if (join->conds || outer_join)
{
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->table_count,
conds, ~outer_join, join->select_lex, &sargables))
join->conds, ~outer_join, join->select_lex, &sargables))
goto error;
/*
Keyparts without prefixes may be useful if this JOIN is a subquery, and
......@@ -3844,8 +3845,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
join->impossible_where= false;
if (conds && const_count)
{
if (join->conds && const_count)
{
Item* &conds= join->conds;
conds->update_used_tables();
conds= remove_eq_conds(join->thd, conds, &join->cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
......@@ -3857,7 +3859,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->impossible_where= true;
conds=new Item_int((longlong) 0,1);
}
join->conds= conds;
join->cond_equal= NULL;
if (conds)
{
......@@ -3942,12 +3944,18 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
{
select= make_select(s->table, found_const_table_map,
found_const_table_map,
*s->on_expr_ref ? *s->on_expr_ref : conds,
*s->on_expr_ref ? *s->on_expr_ref : join->conds,
1, &error);
if (!select)
goto error;
records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit);
/* Range analyzer could modify the condition. */
if (*s->on_expr_ref)
*s->on_expr_ref= select->cond;
else
join->conds= select->cond;
s->quick=select->quick;
s->needed_reg=select->needed_reg;
select->quick=0;
......@@ -3958,7 +3966,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->thd->variables.optimizer_use_condition_selectivity > 1)
calculate_cond_selectivity_for_table(join->thd, s->table,
*s->on_expr_ref ?
*s->on_expr_ref : conds);
s->on_expr_ref : &join->conds);
if (s->table->reginfo.impossible_range)
{
impossible_range= TRUE;
......@@ -9658,7 +9666,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt), 0,
FALSE) < 0)
FALSE, FALSE) < 0)
{
/*
Before reporting "Impossible WHERE" for the whole query
......@@ -9672,7 +9680,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt),0,
FALSE) < 0)
FALSE, FALSE) < 0)
DBUG_RETURN(1); // Impossible WHERE
}
else
......@@ -18496,7 +18504,7 @@ test_if_quick_select(JOIN_TAB *tab)
tab->select->quick=0;
return tab->select->test_quick_select(tab->join->thd, tab->keys,
(table_map) 0, HA_POS_ERROR, 0,
FALSE);
FALSE, /*remove where parts*/FALSE);
}
......@@ -20169,7 +20177,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
OPTION_FOUND_ROWS) ?
HA_POS_ERROR :
tab->join->unit->select_limit_cnt,0,
TRUE) <= 0;
TRUE, FALSE) <= 0;
if (res)
{
select->cond= save_cond;
......@@ -20216,7 +20224,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
!(table->file->index_flags(best_key, 0, 1) & HA_CLUSTERED_INDEX)))
goto use_filesort;
if (select &&
if (select && // psergey: why doesn't this use a quick?
table->quick_keys.is_set(best_key) && best_key != ref_key)
{
key_map map;
......@@ -20227,7 +20235,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join->select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt,
TRUE, FALSE);
TRUE, FALSE, FALSE);
}
order_direction= best_key_direction;
/*
......@@ -24689,6 +24697,109 @@ void JOIN::cache_const_exprs()
}
}
/*
Get a cost of reading rows_limit rows through index keynr.
@detail
- If there is a quick select, we try to use it.
- if there is a ref(const) access, we try to use it, too.
- quick and ref(const) use different cost formulas, so if both are possible
we should make a cost-based choice.
@return
true There was a possible quick or ref access, its cost is in the OUT
parameters.
false No quick or ref(const) possible (and so, the caller will attempt
to use a full index scan on this index).
*/
static bool get_range_limit_read_cost(const JOIN_TAB *tab,
const TABLE *table,
uint keynr,
ha_rows rows_limit,
double *read_time)
{
bool res= false;
/*
We need to adjust the estimates if we had a quick select (or ref(const)) on
index keynr.
*/
if (table->quick_keys.is_set(keynr))
{
/*
Start from quick select's rows and cost. These are always cheaper than
full index scan/cost.
*/
double best_rows= table->quick_rows[keynr];
double best_cost= table->quick_costs[keynr];
/*
Check if ref(const) access was possible on this index.
*/
if (tab)
{
key_part_map const_parts= 0;
key_part_map map= 1;
uint kp;
/* Find how many key parts would be used by ref(const) */
for (kp=0; kp < MAX_REF_PARTS; map=map << 1, kp++)
{
if (!(table->const_key_parts[keynr] & map))
break;
const_parts |= map;
}
if (kp > 0)
{
ha_rows ref_rows;
/*
Two possible cases:
1. ref(const) uses the same #key parts as range access.
2. ref(const) uses fewer key parts, becasue there is a
range_cond(key_part+1).
*/
if (kp == table->quick_key_parts[keynr])
ref_rows= table->quick_rows[keynr];
else
ref_rows= table->key_info[keynr].actual_rec_per_key(kp-1);
if (ref_rows > 0)
{
double tmp= ref_rows;
/* Reuse the cost formula from best_access_path: */
set_if_smaller(tmp, (double) tab->join->thd->variables.max_seeks_for_key);
if (table->covering_keys.is_set(keynr))
tmp= table->file->keyread_time(keynr, 1, (ha_rows) tmp);
else
tmp= table->file->read_time(keynr, 1,
(ha_rows) MY_MIN(tmp,tab->worst_seeks));
if (tmp < best_cost)
{
best_cost= tmp;
best_rows= ref_rows;
}
}
}
}
if (best_rows > rows_limit)
{
/*
LIMIT clause specifies that we will need to read fewer records than
quick select will return. Assume that quick select's cost is
proportional to the number of records we need to return (e.g. if we
only need 1/3rd of records, it will cost us 1/3rd of quick select's
read time)
*/
best_cost *= rows_limit / best_rows;
}
*read_time= best_cost;
res= true;
}
return res;
}
/**
Find a cheaper access key than a given @a key
......@@ -24782,6 +24893,11 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
}
else
read_time= table->file->scan_time();
/*
TODO: add cost of sorting here.
*/
read_time += COST_EPS;
/*
Calculate the selectivity of the ref_key for REF_ACCESS. For
......@@ -24941,6 +25057,14 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
*/
index_scan_time= select_limit/rec_per_key *
MY_MIN(rec_per_key, table->file->scan_time());
double range_scan_time;
if (get_range_limit_read_cost(tab, table, nr, select_limit,
&range_scan_time))
{
if (range_scan_time < index_scan_time)
index_scan_time= range_scan_time;
}
if ((ref_key < 0 && (group || table->force_index || is_covering)) ||
index_scan_time < read_time)
{
......
......@@ -1113,6 +1113,7 @@ struct TABLE
and max #key parts that range access would use.
*/
ha_rows quick_rows[MAX_KEY];
double quick_costs[MAX_KEY];
/*
Bitmaps of key parts that =const for the duration of join execution. If
......
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