The pilot patch for mwl#253.
This commit is contained in:
parent
938d47dcdc
commit
fc1c8ffdad
@ -500,6 +500,18 @@ The following options may be given as the first argument:
|
||||
partial_match_table_scan, semijoin, semijoin_with_cache,
|
||||
subquery_cache, table_elimination, extended_keys,
|
||||
exists_to_in } and val is one of {on, off, default}
|
||||
--optimizer-use-condition-selectivity=#
|
||||
Controls selectivity of which conditions the optimizer
|
||||
takes into account to calculate cardinality of a partial
|
||||
join when it searches for the best execution plan
|
||||
Meaning: 1 - use selectivity of index backed range
|
||||
conditions to calculate cardinality of the partial join
|
||||
if the last joined table is accessed by full table scan
|
||||
or an index scan 2 - use selectivity of index backed
|
||||
range conditions to calculate cardinality of the partial
|
||||
join in any case 3 - additionally always use selectivity
|
||||
of range conditions that are not backed by any index to
|
||||
calculate cardinality of the partial join
|
||||
--performance-schema
|
||||
Enable the performance schema.
|
||||
--performance-schema-events-waits-history-long-size=#
|
||||
@ -1004,6 +1016,7 @@ old-style-user-limits FALSE
|
||||
optimizer-prune-level 1
|
||||
optimizer-search-depth 62
|
||||
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on
|
||||
optimizer-use-condition-selectivity 1
|
||||
performance-schema FALSE
|
||||
performance-schema-events-waits-history-long-size 10000
|
||||
performance-schema-events-waits-history-size 10
|
||||
|
114
mysql-test/r/selectivity.result
Normal file
114
mysql-test/r/selectivity.result
Normal file
@ -0,0 +1,114 @@
|
||||
select @@global.use_stat_tables;
|
||||
@@global.use_stat_tables
|
||||
COMPLEMENTARY
|
||||
select @@session.use_stat_tables;
|
||||
@@session.use_stat_tables
|
||||
COMPLEMENTARY
|
||||
set @save_use_stat_tables=@@use_stat_tables;
|
||||
set use_stat_tables='preferably';
|
||||
DROP DATABASE IF EXISTS dbt3_s001;
|
||||
CREATE DATABASE dbt3_s001;
|
||||
use dbt3_s001;
|
||||
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
|
||||
EXPLAIN EXTENDED select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY supplier ALL PRIMARY,i_s_nationkey NULL NULL NULL 10 100.00 Using where; Using filesort
|
||||
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
|
||||
1 PRIMARY nation eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1 100.00 Using where
|
||||
2 MATERIALIZED part ALL PRIMARY NULL NULL NULL 200 100.00 Using where
|
||||
2 MATERIALIZED partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey PRIMARY 4 dbt3_s001.part.p_partkey 3 100.00 Using where
|
||||
4 DEPENDENT SUBQUERY lineitem ref i_l_shipdate,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey i_l_suppkey_partkey 10 dbt3_s001.partsupp.ps_partkey,dbt3_s001.partsupp.ps_suppkey 8 100.00 Using where
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_partkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_suppkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1003 select sql_calc_found_rows `dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`supplier`.`s_address` AS `s_address` from `dbt3_s001`.`supplier` semi join (`dbt3_s001`.`part` join `dbt3_s001`.`partsupp`) join `dbt3_s001`.`nation` where ((`dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey`) and (`dbt3_s001`.`nation`.`n_name` = 'UNITED STATES') and (`dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey`) and (`dbt3_s001`.`partsupp`.`ps_availqty` > <expr_cache><`dbt3_s001`.`partsupp`.`ps_partkey`,`dbt3_s001`.`partsupp`.`ps_suppkey`>((select (0.5 * sum(`dbt3_s001`.`lineitem`.`l_quantity`)) from `dbt3_s001`.`lineitem` where ((`dbt3_s001`.`lineitem`.`l_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`) and (`dbt3_s001`.`lineitem`.`l_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey`) and (`dbt3_s001`.`lineitem`.`l_shipDATE` >= <cache>(cast('1993-01-01' as date))) and (`dbt3_s001`.`lineitem`.`l_shipDATE` < <cache>((cast('1993-01-01' as date) + interval '1' year))))))) and (`dbt3_s001`.`part`.`p_name` like 'g%')) order by `dbt3_s001`.`supplier`.`s_name` limit 10
|
||||
select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
s_name s_address
|
||||
Supplier#000000010 Saygah3gYWMp72i PY
|
||||
set optimizer_use_condition_selectivity=3;
|
||||
EXPLAIN EXTENDED select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY nation ALL PRIMARY NULL NULL NULL 25 4.00 Using where; Using temporary; Using filesort
|
||||
1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 1 100.00
|
||||
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
|
||||
2 MATERIALIZED part ALL PRIMARY NULL NULL NULL 200 4.17 Using where
|
||||
2 MATERIALIZED partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey PRIMARY 4 dbt3_s001.part.p_partkey 3 100.00 Using where
|
||||
4 DEPENDENT SUBQUERY lineitem ref i_l_shipdate,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey i_l_suppkey_partkey 10 dbt3_s001.partsupp.ps_partkey,dbt3_s001.partsupp.ps_suppkey 8 100.00 Using where
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_partkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_suppkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1003 select sql_calc_found_rows `dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`supplier`.`s_address` AS `s_address` from `dbt3_s001`.`supplier` semi join (`dbt3_s001`.`part` join `dbt3_s001`.`partsupp`) join `dbt3_s001`.`nation` where ((`dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey`) and (`dbt3_s001`.`nation`.`n_name` = 'UNITED STATES') and (`dbt3_s001`.`supplier`.`s_nationkey` = `dbt3_s001`.`nation`.`n_nationkey`) and (`dbt3_s001`.`partsupp`.`ps_availqty` > <expr_cache><`dbt3_s001`.`partsupp`.`ps_partkey`,`dbt3_s001`.`partsupp`.`ps_suppkey`>((select (0.5 * sum(`dbt3_s001`.`lineitem`.`l_quantity`)) from `dbt3_s001`.`lineitem` where ((`dbt3_s001`.`lineitem`.`l_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`) and (`dbt3_s001`.`lineitem`.`l_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey`) and (`dbt3_s001`.`lineitem`.`l_shipDATE` >= <cache>(cast('1993-01-01' as date))) and (`dbt3_s001`.`lineitem`.`l_shipDATE` < <cache>((cast('1993-01-01' as date) + interval '1' year))))))) and (`dbt3_s001`.`part`.`p_name` like 'g%')) order by `dbt3_s001`.`supplier`.`s_name` limit 10
|
||||
select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
s_name s_address
|
||||
Supplier#000000010 Saygah3gYWMp72i PY
|
||||
DROP DATABASE dbt3_s001;
|
||||
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
|
||||
set use_stat_tables=@save_use_stat_tables;
|
119
mysql-test/r/selectivity_innodb.result
Normal file
119
mysql-test/r/selectivity_innodb.result
Normal file
@ -0,0 +1,119 @@
|
||||
SET SESSION STORAGE_ENGINE='InnoDB';
|
||||
set @save_optimizer_switch_for_selectivity_test=@@optimizer_switch;
|
||||
set optimizer_switch='extended_keys=on';
|
||||
select @@global.use_stat_tables;
|
||||
@@global.use_stat_tables
|
||||
COMPLEMENTARY
|
||||
select @@session.use_stat_tables;
|
||||
@@session.use_stat_tables
|
||||
COMPLEMENTARY
|
||||
set @save_use_stat_tables=@@use_stat_tables;
|
||||
set use_stat_tables='preferably';
|
||||
DROP DATABASE IF EXISTS dbt3_s001;
|
||||
CREATE DATABASE dbt3_s001;
|
||||
use dbt3_s001;
|
||||
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
|
||||
EXPLAIN EXTENDED select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY supplier ALL PRIMARY,i_s_nationkey NULL NULL NULL 10 100.00 Using where; Using filesort
|
||||
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
|
||||
1 PRIMARY nation eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1 100.00 Using where
|
||||
2 MATERIALIZED part ALL PRIMARY NULL NULL NULL 200 100.00 Using where
|
||||
2 MATERIALIZED partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey PRIMARY 4 dbt3_s001.part.p_partkey 3 100.00 Using where
|
||||
4 DEPENDENT SUBQUERY lineitem ref i_l_shipdate,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey i_l_suppkey_partkey 10 dbt3_s001.partsupp.ps_partkey,dbt3_s001.partsupp.ps_suppkey 8 100.00 Using where
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_partkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_suppkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1003 select sql_calc_found_rows `dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`supplier`.`s_address` AS `s_address` from `dbt3_s001`.`supplier` semi join (`dbt3_s001`.`part` join `dbt3_s001`.`partsupp`) join `dbt3_s001`.`nation` where ((`dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey`) and (`dbt3_s001`.`nation`.`n_name` = 'UNITED STATES') and (`dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey`) and (`dbt3_s001`.`partsupp`.`ps_availqty` > <expr_cache><`dbt3_s001`.`partsupp`.`ps_partkey`,`dbt3_s001`.`partsupp`.`ps_suppkey`>((select (0.5 * sum(`dbt3_s001`.`lineitem`.`l_quantity`)) from `dbt3_s001`.`lineitem` where ((`dbt3_s001`.`lineitem`.`l_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`) and (`dbt3_s001`.`lineitem`.`l_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey`) and (`dbt3_s001`.`lineitem`.`l_shipDATE` >= <cache>(cast('1993-01-01' as date))) and (`dbt3_s001`.`lineitem`.`l_shipDATE` < <cache>((cast('1993-01-01' as date) + interval '1' year))))))) and (`dbt3_s001`.`part`.`p_name` like 'g%')) order by `dbt3_s001`.`supplier`.`s_name` limit 10
|
||||
select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
s_name s_address
|
||||
Supplier#000000010 Saygah3gYWMp72i PY
|
||||
set optimizer_use_condition_selectivity=3;
|
||||
EXPLAIN EXTENDED select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY nation ALL PRIMARY NULL NULL NULL 25 4.00 Using where; Using temporary; Using filesort
|
||||
1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 1 100.00
|
||||
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
|
||||
2 MATERIALIZED part ALL PRIMARY NULL NULL NULL 200 4.17 Using where
|
||||
2 MATERIALIZED partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey PRIMARY 4 dbt3_s001.part.p_partkey 3 100.00 Using where
|
||||
4 DEPENDENT SUBQUERY lineitem ref i_l_shipdate,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey i_l_suppkey_partkey 10 dbt3_s001.partsupp.ps_partkey,dbt3_s001.partsupp.ps_suppkey 8 100.00 Using where
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_partkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1276 Field or reference 'dbt3_s001.partsupp.ps_suppkey' of SELECT #4 was resolved in SELECT #2
|
||||
Note 1003 select sql_calc_found_rows `dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`supplier`.`s_address` AS `s_address` from `dbt3_s001`.`supplier` semi join (`dbt3_s001`.`part` join `dbt3_s001`.`partsupp`) join `dbt3_s001`.`nation` where ((`dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey`) and (`dbt3_s001`.`nation`.`n_name` = 'UNITED STATES') and (`dbt3_s001`.`supplier`.`s_nationkey` = `dbt3_s001`.`nation`.`n_nationkey`) and (`dbt3_s001`.`partsupp`.`ps_availqty` > <expr_cache><`dbt3_s001`.`partsupp`.`ps_partkey`,`dbt3_s001`.`partsupp`.`ps_suppkey`>((select (0.5 * sum(`dbt3_s001`.`lineitem`.`l_quantity`)) from `dbt3_s001`.`lineitem` where ((`dbt3_s001`.`lineitem`.`l_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`) and (`dbt3_s001`.`lineitem`.`l_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey`) and (`dbt3_s001`.`lineitem`.`l_shipDATE` >= <cache>(cast('1993-01-01' as date))) and (`dbt3_s001`.`lineitem`.`l_shipDATE` < <cache>((cast('1993-01-01' as date) + interval '1' year))))))) and (`dbt3_s001`.`part`.`p_name` like 'g%')) order by `dbt3_s001`.`supplier`.`s_name` limit 10
|
||||
select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
s_name s_address
|
||||
Supplier#000000010 Saygah3gYWMp72i PY
|
||||
DROP DATABASE dbt3_s001;
|
||||
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
|
||||
set use_stat_tables=@save_use_stat_tables;
|
||||
set optimizer_switch=@save_optimizer_switch_for_selectivity_test;
|
||||
SET SESSION STORAGE_ENGINE=DEFAULT;
|
@ -0,0 +1,101 @@
|
||||
SET @start_global_value = @@global.optimizer_use_condition_selectivity;
|
||||
SELECT @start_global_value;
|
||||
@start_global_value
|
||||
1
|
||||
SET @start_session_value = @@session.optimizer_use_condition_selectivity;
|
||||
SELECT @start_session_value;
|
||||
@start_session_value
|
||||
1
|
||||
'#--------------------FN_DYNVARS_115_01-------------------------#'
|
||||
SET @@global.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@session.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
1
|
||||
'#--------------------FN_DYNVARS_115_02-------------------------#'
|
||||
SET @@global.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@global.optimizer_use_condition_selectivity = 1;
|
||||
@@global.optimizer_use_condition_selectivity = 1
|
||||
1
|
||||
SET @@session.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@session.optimizer_use_condition_selectivity = 1;
|
||||
@@session.optimizer_use_condition_selectivity = 1
|
||||
1
|
||||
'#--------------------FN_DYNVARS_115_03-------------------------#'
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@global.optimizer_use_condition_selectivity = 1;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@global.optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
2
|
||||
SET @@global.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
3
|
||||
'#--------------------FN_DYNVARS_115_04-------------------------#'
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@session.optimizer_use_condition_selectivity = 1;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@session.optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
2
|
||||
SET @@session.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
3
|
||||
'#------------------FN_DYNVARS_115_05-----------------------#'
|
||||
SET @@global.optimizer_use_condition_selectivity = ON;
|
||||
ERROR 42000: Incorrect argument type to variable 'optimizer_use_condition_selectivity'
|
||||
SET @@global.optimizer_use_condition_selectivity = OFF;
|
||||
ERROR 42000: Incorrect argument type to variable 'optimizer_use_condition_selectivity'
|
||||
SET @@session.optimizer_use_condition_selectivity = 65530.34;
|
||||
ERROR 42000: Incorrect argument type to variable 'optimizer_use_condition_selectivity'
|
||||
SET @@session.optimizer_use_condition_selectivity = test;
|
||||
ERROR 42000: Incorrect argument type to variable 'optimizer_use_condition_selectivity'
|
||||
'#------------------FN_DYNVARS_115_06-----------------------#'
|
||||
SELECT @@global.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||
WHERE VARIABLE_NAME='optimizer_use_condition_selectivity';
|
||||
@@global.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
1
|
||||
'#------------------FN_DYNVARS_115_07-----------------------#'
|
||||
SELECT @@session.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
FROM INFORMATION_SCHEMA.SESSION_VARIABLES
|
||||
WHERE VARIABLE_NAME='optimizer_use_condition_selectivity';
|
||||
@@session.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
1
|
||||
'#---------------------FN_DYNVARS_115_08----------------------#'
|
||||
SET @@optimizer_use_condition_selectivity = 1;
|
||||
SET @@global.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@optimizer_use_condition_selectivity = @@global.optimizer_use_condition_selectivity;
|
||||
@@optimizer_use_condition_selectivity = @@global.optimizer_use_condition_selectivity
|
||||
0
|
||||
'#---------------------FN_DYNVARS_115_09----------------------#'
|
||||
SET @@optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@optimizer_use_condition_selectivity = @@local.optimizer_use_condition_selectivity;
|
||||
@@optimizer_use_condition_selectivity = @@local.optimizer_use_condition_selectivity
|
||||
1
|
||||
SELECT @@local.optimizer_use_condition_selectivity = @@session.optimizer_use_condition_selectivity;
|
||||
@@local.optimizer_use_condition_selectivity = @@session.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@global.optimizer_use_condition_selectivity = @start_global_value;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
@@global.optimizer_use_condition_selectivity
|
||||
1
|
||||
SET @@session.optimizer_use_condition_selectivity = @start_session_value;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
@@session.optimizer_use_condition_selectivity
|
||||
1
|
@ -0,0 +1,138 @@
|
||||
|
||||
--source include/load_sysvars.inc
|
||||
|
||||
#################################################################
|
||||
# START OF optimizer_use_condition_selectivity TESTS #
|
||||
#################################################################
|
||||
|
||||
|
||||
#############################################################
|
||||
# Save initial value #
|
||||
#############################################################
|
||||
|
||||
SET @start_global_value = @@global.optimizer_use_condition_selectivity;
|
||||
SELECT @start_global_value;
|
||||
SET @start_session_value = @@session.optimizer_use_condition_selectivity;
|
||||
SELECT @start_session_value;
|
||||
|
||||
|
||||
--echo '#--------------------FN_DYNVARS_115_01-------------------------#'
|
||||
#########################################################################
|
||||
# Display the DEFAULT value of optimizer_use_condition_selectivity #
|
||||
#########################################################################
|
||||
|
||||
SET @@global.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
|
||||
SET @@session.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
|
||||
|
||||
--echo '#--------------------FN_DYNVARS_115_02-------------------------#'
|
||||
#########################################################################
|
||||
# Check the DEFAULT value of optimizer_use_condition_selectivity #
|
||||
#########################################################################
|
||||
|
||||
SET @@global.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@global.optimizer_use_condition_selectivity = 1;
|
||||
|
||||
SET @@session.optimizer_use_condition_selectivity = DEFAULT;
|
||||
SELECT @@session.optimizer_use_condition_selectivity = 1;
|
||||
|
||||
|
||||
--echo '#--------------------FN_DYNVARS_115_03-------------------------#'
|
||||
#############################################################################################
|
||||
# Change the value of optimizer_use_condition_selectivity to a valid value for GLOBAL Scope #
|
||||
#############################################################################################
|
||||
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
SET @@global.optimizer_use_condition_selectivity = 1;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
SET @@global.optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
SET @@global.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
|
||||
|
||||
--echo '#--------------------FN_DYNVARS_115_04-------------------------#'
|
||||
#############################################################################################
|
||||
# Change the value of optimizer_use_condition_selectivity to a valid value for SESSION Scope#
|
||||
#############################################################################################
|
||||
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
SET @@session.optimizer_use_condition_selectivity = 1;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
SET @@session.optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
SET @@session.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
|
||||
|
||||
--echo '#------------------FN_DYNVARS_115_05-----------------------#'
|
||||
###############################################################################
|
||||
# Change the value of optimizer_use_condition_selectivity to an invalid value #
|
||||
##############################################################################
|
||||
|
||||
--Error ER_WRONG_TYPE_FOR_VAR
|
||||
SET @@global.optimizer_use_condition_selectivity = ON;
|
||||
--Error ER_WRONG_TYPE_FOR_VAR
|
||||
SET @@global.optimizer_use_condition_selectivity = OFF;
|
||||
--Error ER_WRONG_TYPE_FOR_VAR
|
||||
SET @@session.optimizer_use_condition_selectivity = 65530.34;
|
||||
--Error ER_WRONG_TYPE_FOR_VAR
|
||||
SET @@session.optimizer_use_condition_selectivity = test;
|
||||
|
||||
--echo '#------------------FN_DYNVARS_115_06-----------------------#'
|
||||
####################################################################
|
||||
# Check if the value in GLOBAL Table matches value in variable #
|
||||
####################################################################
|
||||
|
||||
|
||||
SELECT @@global.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||
WHERE VARIABLE_NAME='optimizer_use_condition_selectivity';
|
||||
|
||||
--echo '#------------------FN_DYNVARS_115_07-----------------------#'
|
||||
####################################################################
|
||||
# Check if the value in SESSION Table matches value in variable #
|
||||
####################################################################
|
||||
|
||||
SELECT @@session.optimizer_use_condition_selectivity = VARIABLE_VALUE
|
||||
FROM INFORMATION_SCHEMA.SESSION_VARIABLES
|
||||
WHERE VARIABLE_NAME='optimizer_use_condition_selectivity';
|
||||
|
||||
|
||||
--echo '#---------------------FN_DYNVARS_115_08----------------------#'
|
||||
###############################################################################
|
||||
# Check if global and session variable are independent of each other #
|
||||
###############################################################################
|
||||
|
||||
SET @@optimizer_use_condition_selectivity = 1;
|
||||
SET @@global.optimizer_use_condition_selectivity = 3;
|
||||
SELECT @@optimizer_use_condition_selectivity = @@global.optimizer_use_condition_selectivity;
|
||||
|
||||
|
||||
--echo '#---------------------FN_DYNVARS_115_09----------------------#'
|
||||
###############################################################################
|
||||
# Check if accessing variable with SESSION,LOCAL and without SCOPE points #
|
||||
# to same session variable #
|
||||
###############################################################################
|
||||
|
||||
SET @@optimizer_use_condition_selectivity = 2;
|
||||
SELECT @@optimizer_use_condition_selectivity = @@local.optimizer_use_condition_selectivity;
|
||||
SELECT @@local.optimizer_use_condition_selectivity = @@session.optimizer_use_condition_selectivity;
|
||||
|
||||
|
||||
####################################
|
||||
# Restore initial value #
|
||||
####################################
|
||||
|
||||
SET @@global.optimizer_use_condition_selectivity = @start_global_value;
|
||||
SELECT @@global.optimizer_use_condition_selectivity;
|
||||
SET @@session.optimizer_use_condition_selectivity = @start_session_value;
|
||||
SELECT @@session.optimizer_use_condition_selectivity;
|
||||
|
||||
########################################################################
|
||||
# END OF optimizer_use_condition_selectivity TESTS #
|
||||
########################################################################
|
||||
|
65
mysql-test/t/selectivity.test
Normal file
65
mysql-test/t/selectivity.test
Normal file
@ -0,0 +1,65 @@
|
||||
--source include/have_stat_tables.inc
|
||||
|
||||
select @@global.use_stat_tables;
|
||||
select @@session.use_stat_tables;
|
||||
|
||||
set @save_use_stat_tables=@@use_stat_tables;
|
||||
|
||||
set use_stat_tables='preferably';
|
||||
|
||||
--disable_warnings
|
||||
DROP DATABASE IF EXISTS dbt3_s001;
|
||||
--enable_warnings
|
||||
|
||||
CREATE DATABASE dbt3_s001;
|
||||
|
||||
use dbt3_s001;
|
||||
|
||||
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
|
||||
|
||||
--disable_query_log
|
||||
--disable_result_log
|
||||
--disable_warnings
|
||||
--source include/dbt3_s001.inc
|
||||
|
||||
ANALYZE TABLE
|
||||
customer, lineitem, nation, orders, part, partsupp, region, supplier;
|
||||
FLUSH TABLE
|
||||
customer, lineitem, nation, orders, part, partsupp, region, supplier;
|
||||
--enable_warnings
|
||||
--enable_result_log
|
||||
--enable_query_log
|
||||
|
||||
let $Q20=
|
||||
select sql_calc_found_rows
|
||||
s_name, s_address
|
||||
from supplier, nation
|
||||
where s_suppkey in (select ps_suppkey from partsupp
|
||||
where ps_partkey in (select p_partkey from part
|
||||
where p_name like 'g%')
|
||||
and ps_availqty >
|
||||
(select 0.5 * sum(l_quantity)
|
||||
from lineitem
|
||||
where l_partkey = ps_partkey
|
||||
and l_suppkey = ps_suppkey
|
||||
and l_shipdate >= date('1993-01-01')
|
||||
and l_shipdate < date('1993-01-01') +
|
||||
interval '1' year ))
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'UNITED STATES'
|
||||
order by s_name
|
||||
limit 10;
|
||||
|
||||
eval EXPLAIN EXTENDED $Q20;
|
||||
eval $Q20;
|
||||
|
||||
set optimizer_use_condition_selectivity=3;
|
||||
|
||||
eval EXPLAIN EXTENDED $Q20;
|
||||
eval $Q20;
|
||||
|
||||
DROP DATABASE dbt3_s001;
|
||||
|
||||
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
|
||||
|
||||
set use_stat_tables=@save_use_stat_tables;
|
12
mysql-test/t/selectivity_innodb.test
Normal file
12
mysql-test/t/selectivity_innodb.test
Normal file
@ -0,0 +1,12 @@
|
||||
--source include/have_innodb.inc
|
||||
|
||||
SET SESSION STORAGE_ENGINE='InnoDB';
|
||||
|
||||
set @save_optimizer_switch_for_selectivity_test=@@optimizer_switch;
|
||||
set optimizer_switch='extended_keys=on';
|
||||
|
||||
--source selectivity.test
|
||||
|
||||
set optimizer_switch=@save_optimizer_switch_for_selectivity_test;
|
||||
|
||||
SET SESSION STORAGE_ENGINE=DEFAULT;
|
56
sql/field.cc
56
sql/field.cc
@ -1273,6 +1273,20 @@ out_of_range:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
double Field_num::middle_point_pos(Field *min, Field *max)
|
||||
{
|
||||
double n, d;
|
||||
n= val_real() - min->val_real();
|
||||
if (n < 0)
|
||||
return 0.0;
|
||||
d= max->val_real() - min->val_real();
|
||||
if (d <= 0)
|
||||
return 1.0;
|
||||
return min(n/d, 1.0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process decimal library return codes and issue warnings for overflow and
|
||||
truncation.
|
||||
@ -1344,6 +1358,8 @@ Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
|
||||
comment.length=0;
|
||||
field_index= 0;
|
||||
is_stat_field= FALSE;
|
||||
cond_selectivity= 1.0;
|
||||
next_equal_field= NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -6167,6 +6183,46 @@ int Field_str::store(double nr)
|
||||
return store(buff, length, &my_charset_numeric);
|
||||
}
|
||||
|
||||
static
|
||||
inline ulonglong char_prefix_to_ulonglong(uchar *src)
|
||||
{
|
||||
uint sz= sizeof(ulonglong);
|
||||
for (uint i= 0; i < sz/2; i++)
|
||||
{
|
||||
uchar tmp= src[i];
|
||||
src[i]= src[sz-1-i];
|
||||
src[sz-1-i]= tmp;
|
||||
}
|
||||
return uint8korr(src);
|
||||
}
|
||||
|
||||
double Field_str::middle_point_pos(Field *min, Field *max)
|
||||
{
|
||||
uchar mp_prefix[sizeof(ulonglong)];
|
||||
uchar minp_prefix[sizeof(ulonglong)];
|
||||
uchar maxp_prefix[sizeof(ulonglong)];
|
||||
ulonglong mp, minp, maxp;
|
||||
my_strnxfrm(charset(), mp_prefix, sizeof(mp),
|
||||
ptr + length_size(), sizeof(mp) * charset()->mbmaxlen);
|
||||
my_strnxfrm(charset(), minp_prefix, sizeof(minp),
|
||||
min->ptr + length_size(),
|
||||
sizeof(minp) * charset()->mbmaxlen);
|
||||
my_strnxfrm(charset(), maxp_prefix, sizeof(maxp),
|
||||
max->ptr + length_size(),
|
||||
sizeof(maxp) * charset()->mbmaxlen);
|
||||
mp= char_prefix_to_ulonglong(mp_prefix);
|
||||
minp= char_prefix_to_ulonglong(minp_prefix);
|
||||
maxp= char_prefix_to_ulonglong(maxp_prefix);
|
||||
double n, d;
|
||||
n= mp - minp;
|
||||
if (n < 0)
|
||||
return 0.0;
|
||||
d= maxp - minp;
|
||||
if (d <= 0)
|
||||
return 1.0;
|
||||
return min(n/d, 1.0);
|
||||
}
|
||||
|
||||
|
||||
uint Field::is_equal(Create_field *new_field)
|
||||
{
|
||||
|
27
sql/field.h
27
sql/field.h
@ -220,7 +220,23 @@ public:
|
||||
*/
|
||||
bool is_created_from_null_item;
|
||||
|
||||
bool is_stat_field; /* TRUE in Field objects created for column min/max values */
|
||||
/* TRUE in Field objects created for column min/max values */
|
||||
bool is_stat_field;
|
||||
|
||||
/*
|
||||
Selectivity of the range condition over this field.
|
||||
When calculating this selectivity a range predicate
|
||||
is taken into account only if:
|
||||
- it is extracted from the WHERE clause
|
||||
- it depends only on the table the field belongs to
|
||||
*/
|
||||
double cond_selectivity;
|
||||
|
||||
/*
|
||||
The next field in the class of equal fields at the top AND level
|
||||
of the WHERE clause
|
||||
*/
|
||||
Field *next_equal_field;
|
||||
|
||||
/*
|
||||
This structure is used for statistical data on the column
|
||||
@ -703,6 +719,11 @@ public:
|
||||
virtual bool hash_join_is_possible() { return TRUE; }
|
||||
virtual bool eq_cmp_as_binary() { return TRUE; }
|
||||
|
||||
virtual double middle_point_pos(Field *min, Field *max)
|
||||
{
|
||||
return (double) 1.0;
|
||||
}
|
||||
|
||||
friend int cre_myisam(char * name, register TABLE *form, uint options,
|
||||
ulonglong auto_increment_value);
|
||||
friend class Copy_field;
|
||||
@ -821,6 +842,7 @@ public:
|
||||
bool get_int(CHARSET_INFO *cs, const char *from, uint len,
|
||||
longlong *rnd, ulonglong unsigned_max,
|
||||
longlong signed_min, longlong signed_max);
|
||||
double middle_point_pos(Field *min, Field *max);
|
||||
};
|
||||
|
||||
|
||||
@ -866,6 +888,8 @@ public:
|
||||
virtual bool str_needs_quotes() { return TRUE; }
|
||||
uint is_equal(Create_field *new_field);
|
||||
bool eq_cmp_as_binary() { return test(flags & BINARY_FLAG); }
|
||||
virtual uint length_size() { return 0; }
|
||||
double middle_point_pos(Field *min, Field *max);
|
||||
};
|
||||
|
||||
/* base class for Field_string, Field_varstring and Field_blob */
|
||||
@ -1894,6 +1918,7 @@ public:
|
||||
uint new_null_bit);
|
||||
uint is_equal(Create_field *new_field);
|
||||
void hash(ulong *nr, ulong *nr2);
|
||||
uint length_size() { return length_bytes; }
|
||||
private:
|
||||
int do_save_field_metadata(uchar *first_byte);
|
||||
};
|
||||
|
@ -5567,7 +5567,8 @@ Item *Item_bool_rowready_func2::negated_item()
|
||||
*/
|
||||
|
||||
Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
|
||||
: Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL)
|
||||
: Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL),
|
||||
link_equal_fields(FALSE)
|
||||
{
|
||||
const_item_cache= 0;
|
||||
with_const= with_const_item;
|
||||
@ -5590,7 +5591,8 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
|
||||
*/
|
||||
|
||||
Item_equal::Item_equal(Item_equal *item_equal)
|
||||
: Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL)
|
||||
: Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL),
|
||||
link_equal_fields(FALSE)
|
||||
{
|
||||
const_item_cache= 0;
|
||||
List_iterator_fast<Item> li(item_equal->equal_items);
|
||||
@ -5833,6 +5835,9 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
|
||||
DBUG_ASSERT(fixed == 0);
|
||||
Item_equal_fields_iterator it(*this);
|
||||
Item *item;
|
||||
Field *first_equal_field;
|
||||
Field *last_equal_field;
|
||||
Field *prev_equal_field= NULL;
|
||||
not_null_tables_cache= used_tables_cache= 0;
|
||||
const_item_cache= 0;
|
||||
while ((item= it++))
|
||||
@ -5846,7 +5851,18 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
|
||||
maybe_null= 1;
|
||||
if (!item->get_item_equal())
|
||||
item->set_item_equal(this);
|
||||
if (link_equal_fields && item->real_item()->type() == FIELD_ITEM)
|
||||
{
|
||||
last_equal_field= ((Item_field *) (item->real_item()))->field;
|
||||
if (!prev_equal_field)
|
||||
first_equal_field= last_equal_field;
|
||||
else
|
||||
prev_equal_field->next_equal_field= last_equal_field;
|
||||
prev_equal_field= last_equal_field;
|
||||
}
|
||||
}
|
||||
if (prev_equal_field && last_equal_field != first_equal_field)
|
||||
last_equal_field->next_equal_field= first_equal_field;
|
||||
fix_length_and_dec();
|
||||
fixed= 1;
|
||||
return FALSE;
|
||||
|
@ -1730,6 +1730,7 @@ class Item_equal: public Item_bool_func
|
||||
used in the original equality.
|
||||
*/
|
||||
Item_field *context_field;
|
||||
bool link_equal_fields;
|
||||
public:
|
||||
inline Item_equal()
|
||||
: Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0),
|
||||
@ -1762,6 +1763,7 @@ public:
|
||||
CHARSET_INFO *compare_collation();
|
||||
|
||||
void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
|
||||
void set_link_equal_fields(bool flag) { link_equal_fields= flag; }
|
||||
friend class Item_equal_fields_iterator;
|
||||
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
|
||||
Item_equal *item_equal);
|
||||
|
219
sql/opt_range.cc
219
sql/opt_range.cc
@ -117,6 +117,7 @@
|
||||
#include "records.h" // init_read_record, end_read_record
|
||||
#include <m_ctype.h>
|
||||
#include "sql_select.h"
|
||||
#include "sql_statistics.h"
|
||||
#include "filesort.h" // filesort_free_buffers
|
||||
|
||||
#ifndef EXTRA_DEBUG
|
||||
@ -3211,6 +3212,224 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
||||
DBUG_RETURN(records ? test(quick) : -1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Condition selectivity module
|
||||
****************************************************************************/
|
||||
|
||||
static
|
||||
bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
|
||||
MY_BITMAP *used_fields)
|
||||
{
|
||||
Field **field_ptr;
|
||||
TABLE *table= param->table;
|
||||
uint parts= 0;
|
||||
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
|
||||
parts++;
|
||||
}
|
||||
|
||||
KEY_PART *key_part;
|
||||
uint keys= 0;
|
||||
|
||||
if (!(key_part= (KEY_PART *) alloc_root(param->mem_root,
|
||||
sizeof(KEY_PART) * parts)))
|
||||
return TRUE;
|
||||
|
||||
param->key_parts= key_part;
|
||||
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
|
||||
{
|
||||
Field *field= *field_ptr;
|
||||
uint16 store_length;
|
||||
key_part->key= keys;
|
||||
key_part->part= 0;
|
||||
key_part->length= (uint16) field->key_length();
|
||||
store_length= key_part->length;
|
||||
if (field->real_maybe_null())
|
||||
store_length+= HA_KEY_NULL_LENGTH;
|
||||
if (field->real_type() == MYSQL_TYPE_VARCHAR)
|
||||
store_length+= HA_KEY_BLOB_LENGTH;
|
||||
key_part->store_length= store_length;
|
||||
key_part->field= field;
|
||||
key_part->image_type= Field::itRAW;
|
||||
param->key[keys]= key_part;
|
||||
keys++;
|
||||
key_part++;
|
||||
}
|
||||
}
|
||||
param->keys= keys;
|
||||
param->key_parts_end= key_part;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
double records_in_column_ranges(PARAM *param, uint idx,
|
||||
SEL_ARG *tree)
|
||||
{
|
||||
SEL_ARG_RANGE_SEQ seq;
|
||||
KEY_MULTI_RANGE range;
|
||||
range_seq_t seq_it;
|
||||
double rows;
|
||||
Field *field;
|
||||
uint flags= 0;
|
||||
double total_rows= 0;
|
||||
RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init,
|
||||
sel_arg_range_seq_next, 0, 0};
|
||||
|
||||
/* Handle cases when we don't have a valid non-empty list of range */
|
||||
if (!tree)
|
||||
return HA_POS_ERROR;
|
||||
if (tree->type == SEL_ARG::IMPOSSIBLE)
|
||||
return (0L);
|
||||
|
||||
field= tree->field;
|
||||
|
||||
seq.keyno= idx;
|
||||
seq.real_keyno= MAX_KEY;
|
||||
seq.param= param;
|
||||
seq.start= tree;
|
||||
|
||||
seq_it= seq_if.init((void *) &seq, 0, flags);
|
||||
|
||||
while (!seq_if.next(seq_it, &range))
|
||||
{
|
||||
key_range *min_endp, *max_endp;
|
||||
min_endp= range.start_key.length? &range.start_key : NULL;
|
||||
max_endp= range.end_key.length? &range.end_key : NULL;
|
||||
rows= get_column_range_cardinality(field, min_endp, max_endp);
|
||||
if (HA_POS_ERROR == rows)
|
||||
{
|
||||
total_rows= HA_POS_ERROR;
|
||||
break;
|
||||
}
|
||||
total_rows += rows;
|
||||
}
|
||||
return total_rows;
|
||||
}
|
||||
|
||||
|
||||
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
|
||||
{
|
||||
uint keynr;
|
||||
uint max_quick_key_parts= 0;
|
||||
MY_BITMAP *used_fields= &table->cond_set;
|
||||
double table_records= table->stat_records();
|
||||
DBUG_ENTER("calculate_cond_selectivity_for_table");
|
||||
|
||||
table->cond_selectivity= 1.0;
|
||||
|
||||
if (bitmap_is_clear_all(used_fields))
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
PARAM param;
|
||||
MEM_ROOT alloc;
|
||||
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0,
|
||||
MYF(MY_THREAD_SPECIFIC));
|
||||
param.thd= thd;
|
||||
param.mem_root= &alloc;
|
||||
param.old_root= thd->mem_root;
|
||||
param.table= table;
|
||||
param.is_ror_scan= FALSE;
|
||||
|
||||
if (create_key_parts_for_pseudo_indexes(¶m, used_fields))
|
||||
{
|
||||
free_root(&alloc, MYF(0));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
param.prev_tables= param.read_tables= 0;
|
||||
param.current_table= table->map;
|
||||
param.using_real_indexes= FALSE;
|
||||
param.real_keynr[0]= 0;
|
||||
param.alloced_sel_args= 0;
|
||||
|
||||
thd->no_errors=1; // Don't warn about NULL
|
||||
|
||||
SEL_TREE *tree;
|
||||
SEL_ARG **key, **end;
|
||||
uint idx= 0;
|
||||
|
||||
tree= get_mm_tree(¶m, cond);
|
||||
|
||||
if (!tree)
|
||||
goto end;
|
||||
|
||||
|
||||
for (key= tree->keys, end= key + param.keys; key != end; key++, idx++)
|
||||
{
|
||||
double rows;
|
||||
if (*key)
|
||||
{
|
||||
rows= records_in_column_ranges(¶m, idx, *key);
|
||||
if (rows != HA_POS_ERROR)
|
||||
(*key)->field->cond_selectivity= rows/table_records;
|
||||
}
|
||||
}
|
||||
|
||||
for (Field **field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
Field *table_field= *field_ptr;
|
||||
if (bitmap_is_set(table->read_set, table_field->field_index) &&
|
||||
table_field->cond_selectivity < 1.0)
|
||||
table->cond_selectivity*= table_field->cond_selectivity;
|
||||
}
|
||||
|
||||
/* Calculate the selectivity of the range conditions supported by indexes */
|
||||
|
||||
bitmap_clear_all(used_fields);
|
||||
|
||||
for (keynr= 0; keynr < table->s->keys; keynr++)
|
||||
{
|
||||
if (table->quick_keys.is_set(keynr))
|
||||
set_if_bigger(max_quick_key_parts, table->quick_key_parts[keynr]);
|
||||
}
|
||||
|
||||
for (uint quick_key_parts= max_quick_key_parts;
|
||||
quick_key_parts; quick_key_parts--)
|
||||
{
|
||||
for (keynr= 0; keynr < table->s->keys; keynr++)
|
||||
{
|
||||
if (table->quick_keys.is_set(keynr) &&
|
||||
table->quick_key_parts[keynr] == quick_key_parts)
|
||||
{
|
||||
uint i;
|
||||
uint used_key_parts= table->quick_key_parts[keynr];
|
||||
double quick_cond_selectivity= table->quick_rows[keynr] /
|
||||
table_records;
|
||||
KEY *key_info= table->key_info + keynr;
|
||||
KEY_PART_INFO* key_part= key_info->key_part;
|
||||
for (i= 0; i < used_key_parts; i++, key_part++)
|
||||
{
|
||||
if (bitmap_is_set(used_fields, key_part->fieldnr-1))
|
||||
break;
|
||||
bitmap_set_bit(used_fields, key_part->fieldnr-1);
|
||||
}
|
||||
if (i)
|
||||
{
|
||||
double f1= key_info->actual_rec_per_key(i-1);
|
||||
double f2= key_info->actual_rec_per_key(i);
|
||||
table->cond_selectivity*= quick_cond_selectivity * f1 / f2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
thd->mem_root= param.old_root;
|
||||
free_root(&alloc, MYF(0));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Condition selectivity code ends
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Partition pruning module
|
||||
****************************************************************************/
|
||||
|
@ -1042,6 +1042,8 @@ 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);
|
||||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
|
||||
void store_key_image_to_rec(Field *field, uchar *ptr, uint len);
|
||||
|
@ -268,8 +268,10 @@ walk_up_n_right:
|
||||
range->end_key.keypart_map= make_prev_keypart_map(cur->max_key_parts);
|
||||
|
||||
if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag &&
|
||||
(uint)key_tree->part+1 == seq->param->table->key_info[seq->real_keyno].key_parts &&
|
||||
(seq->param->table->key_info[seq->real_keyno].flags & HA_NOSAME) &&
|
||||
(seq->real_keyno == MAX_KEY ||
|
||||
((uint)key_tree->part+1 ==
|
||||
seq->param->table->key_info[seq->real_keyno].key_parts &&
|
||||
(seq->param->table->key_info[seq->real_keyno].flags & HA_NOSAME))) &&
|
||||
range->start_key.length == range->end_key.length &&
|
||||
!memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length))
|
||||
range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE);
|
||||
|
@ -3889,7 +3889,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
|
||||
&tmpname, (uint) strlen(path)+1,
|
||||
&group_buff, (!using_unique_constraint ?
|
||||
uniq_tuple_length_arg : 0),
|
||||
&bitmaps, bitmap_buffer_size(1)*3,
|
||||
&bitmaps, bitmap_buffer_size(1)*5,
|
||||
NullS))
|
||||
{
|
||||
if (temp_pool_slot != MY_BIT_NONE)
|
||||
|
@ -283,6 +283,7 @@ public:
|
||||
{
|
||||
pos->records_read= best_loose_scan_records;
|
||||
pos->key= best_loose_scan_start_key;
|
||||
pos->cond_selectivity= 1.0;
|
||||
pos->loosescan_picker.loosescan_key= best_loose_scan_key;
|
||||
pos->loosescan_picker.loosescan_parts= best_max_loose_keypart + 1;
|
||||
pos->use_join_buffer= FALSE;
|
||||
|
@ -499,6 +499,7 @@ typedef struct system_variables
|
||||
ulong net_write_timeout;
|
||||
ulong optimizer_prune_level;
|
||||
ulong optimizer_search_depth;
|
||||
ulong optimizer_use_condition_selectivity;
|
||||
ulong use_stat_tables;
|
||||
ulong preload_buff_size;
|
||||
ulong profiling_history_size;
|
||||
|
@ -228,6 +228,7 @@ template <class T> bool valid_buffer_range(T jump,
|
||||
#define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 26)
|
||||
#define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 27)
|
||||
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28)
|
||||
#define OPTIMIZER_SWITCH_USE_CONDITION_SELECTIVITY (1ULL << 29)
|
||||
|
||||
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
|
||||
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
|
||||
|
@ -89,12 +89,14 @@ void best_access_path(JOIN *join, JOIN_TAB *s,
|
||||
POSITION *pos, POSITION *loose_scan_pos);
|
||||
static void optimize_straight_join(JOIN *join, table_map join_tables);
|
||||
static bool greedy_search(JOIN *join, table_map remaining_tables,
|
||||
uint depth, uint prune_level);
|
||||
uint depth, uint prune_level,
|
||||
uint use_cond_selectivity);
|
||||
static bool best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx, double record_count,
|
||||
double read_time, uint depth,
|
||||
uint prune_level);
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity);
|
||||
static uint determine_search_depth(JOIN* join);
|
||||
C_MODE_START
|
||||
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
|
||||
@ -133,7 +135,8 @@ static int return_zero_rows(JOIN *join, select_result *res,
|
||||
static COND *build_equal_items(THD *thd, COND *cond,
|
||||
COND_EQUAL *inherited,
|
||||
List<TABLE_LIST> *join_list,
|
||||
COND_EQUAL **cond_equal_ref);
|
||||
COND_EQUAL **cond_equal_ref,
|
||||
bool link_equal_fields= FALSE);
|
||||
static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab,
|
||||
COND *cond,
|
||||
COND_EQUAL *cond_equal,
|
||||
@ -149,7 +152,8 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
|
||||
static COND *optimize_cond(JOIN *join, COND *conds,
|
||||
List<TABLE_LIST> *join_list,
|
||||
Item::cond_result *cond_value,
|
||||
COND_EQUAL **cond_equal);
|
||||
COND_EQUAL **cond_equal,
|
||||
int flags= 0);
|
||||
bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
|
||||
static bool create_internal_tmp_table_from_heap2(THD *, TABLE *,
|
||||
ENGINE_COLUMNDEF *, ENGINE_COLUMNDEF **,
|
||||
@ -277,6 +281,8 @@ enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS};
|
||||
JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind);
|
||||
JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind,
|
||||
JOIN_TAB *tab);
|
||||
static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
|
||||
table_map rem_tables);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
|
||||
@ -1155,7 +1161,8 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
|
||||
if (setup_jtbm_semi_joins(this, join_list, &conds))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal);
|
||||
conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal,
|
||||
OPT_LINK_EQUAL_FIELDS);
|
||||
|
||||
if (thd->is_error())
|
||||
{
|
||||
@ -3350,6 +3357,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
||||
table->pos_in_table_list= tables;
|
||||
error= tables->fetch_number_of_rows();
|
||||
set_statistics_for_table(join->thd, table);
|
||||
bitmap_clear_all(&table->cond_set);
|
||||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
const bool no_partitions_used= table->no_partitions_used;
|
||||
@ -3837,6 +3845,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
||||
}
|
||||
delete select;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (pull_out_semijoin_tables(join))
|
||||
@ -4190,11 +4203,12 @@ add_key_field(JOIN *join,
|
||||
else if (!(field->flags & PART_KEY_FLAG))
|
||||
{
|
||||
// Don't remove column IS NULL on a LEFT JOIN table
|
||||
if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
|
||||
!field->table->maybe_null || field->null_ptr)
|
||||
return; // Not a key. Skip it
|
||||
optimize= KEY_OPTIMIZE_EXISTS;
|
||||
DBUG_ASSERT(num_values == 1);
|
||||
if (eq_func && (*value)->type() == Item::NULL_ITEM &&
|
||||
field->table->maybe_null && !field->null_ptr)
|
||||
{
|
||||
optimize= KEY_OPTIMIZE_EXISTS;
|
||||
DBUG_ASSERT(num_values == 1);
|
||||
}
|
||||
}
|
||||
if (optimize != KEY_OPTIMIZE_EXISTS)
|
||||
{
|
||||
@ -4243,7 +4257,11 @@ add_key_field(JOIN *join,
|
||||
break;
|
||||
}
|
||||
if (is_const)
|
||||
{
|
||||
stat[0].const_keys.merge(possible_keys);
|
||||
if (possible_keys.is_clear_all())
|
||||
bitmap_set_bit(&field->table->cond_set, field->field_index);
|
||||
}
|
||||
else if (!eq_func)
|
||||
{
|
||||
/*
|
||||
@ -5313,6 +5331,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
|
||||
join->positions[idx].table= table;
|
||||
join->positions[idx].key=key;
|
||||
join->positions[idx].records_read=1.0; /* This is a const table */
|
||||
join->positions[idx].cond_selectivity= 1.0;
|
||||
join->positions[idx].ref_depend_map= 0;
|
||||
|
||||
// join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */
|
||||
@ -6127,6 +6146,8 @@ choose_plan(JOIN *join, table_map join_tables)
|
||||
{
|
||||
uint search_depth= join->thd->variables.optimizer_search_depth;
|
||||
uint prune_level= join->thd->variables.optimizer_prune_level;
|
||||
uint use_cond_selectivity=
|
||||
join->thd->variables.optimizer_use_condition_selectivity;
|
||||
bool straight_join= test(join->select_options & SELECT_STRAIGHT_JOIN);
|
||||
DBUG_ENTER("choose_plan");
|
||||
|
||||
@ -6191,7 +6212,8 @@ choose_plan(JOIN *join, table_map join_tables)
|
||||
if (search_depth == 0)
|
||||
/* Automatically determine a reasonable value for 'search_depth' */
|
||||
search_depth= determine_search_depth(join);
|
||||
if (greedy_search(join, join_tables, search_depth, prune_level))
|
||||
if (greedy_search(join, join_tables, search_depth, prune_level,
|
||||
use_cond_selectivity))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
@ -6465,6 +6487,8 @@ optimize_straight_join(JOIN *join, table_map join_tables)
|
||||
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
|
||||
double record_count= 1.0;
|
||||
double read_time= 0.0;
|
||||
uint use_cond_selectivity=
|
||||
join->thd->variables.optimizer_use_condition_selectivity;
|
||||
POSITION loose_scan_pos;
|
||||
|
||||
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
||||
@ -6481,6 +6505,11 @@ optimize_straight_join(JOIN *join, table_map join_tables)
|
||||
&loose_scan_pos);
|
||||
|
||||
join_tables&= ~(s->table->map);
|
||||
double pushdown_cond_selectivity= 1.0;
|
||||
if (use_cond_selectivity > 1)
|
||||
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s,
|
||||
join_tables);
|
||||
join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
|
||||
++idx;
|
||||
}
|
||||
|
||||
@ -6568,6 +6597,8 @@ optimize_straight_join(JOIN *join, table_map join_tables)
|
||||
@param search_depth controlls the exhaustiveness of the search
|
||||
@param prune_level the pruning heuristics that should be applied during
|
||||
search
|
||||
@param use_cond_selectivity specifies how the selectivity of the conditions
|
||||
pushed to a table should be taken into account
|
||||
|
||||
@retval
|
||||
FALSE ok
|
||||
@ -6579,7 +6610,8 @@ static bool
|
||||
greedy_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint search_depth,
|
||||
uint prune_level)
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity)
|
||||
{
|
||||
double record_count= 1.0;
|
||||
double read_time= 0.0;
|
||||
@ -6604,7 +6636,8 @@ greedy_search(JOIN *join,
|
||||
/* Find the extension of the current QEP with the lowest cost */
|
||||
join->best_read= DBL_MAX;
|
||||
if (best_extension_by_limited_search(join, remaining_tables, idx, record_count,
|
||||
read_time, search_depth, prune_level))
|
||||
read_time, search_depth, prune_level,
|
||||
use_cond_selectivity))
|
||||
DBUG_RETURN(TRUE);
|
||||
/*
|
||||
'best_read < DBL_MAX' means that optimizer managed to find
|
||||
@ -6843,6 +6876,158 @@ double JOIN::get_examined_rows()
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
double table_multi_eq_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
|
||||
table_map rem_tables, TABLE_REF *ref)
|
||||
{
|
||||
double sel= 1.0;
|
||||
COND_EQUAL *cond_equal= join->cond_equal;
|
||||
|
||||
if (!cond_equal || !cond_equal->current_level.elements)
|
||||
return sel;
|
||||
|
||||
Item_equal *item_equal;
|
||||
List_iterator_fast<Item_equal> it(cond_equal->current_level);
|
||||
table_map table_bit= s->table->map;
|
||||
|
||||
if (!s->keyuse)
|
||||
return sel;
|
||||
|
||||
KEY *key_info= s->get_keyinfo_by_key_no(s->ref.key);
|
||||
|
||||
while ((item_equal= it++))
|
||||
{
|
||||
/*
|
||||
Check whether we need to take into account the selectivity of
|
||||
multiple equality item_equal. If this is the case multiply
|
||||
the current value of sel by this selectivity
|
||||
*/
|
||||
table_map used_tables= item_equal->used_tables();
|
||||
if (!(used_tables & table_bit))
|
||||
continue;
|
||||
if (item_equal->get_const())
|
||||
continue;
|
||||
|
||||
Field *fld;
|
||||
bool adjust_sel= FALSE;
|
||||
Item_equal_fields_iterator fi(*item_equal);
|
||||
while((fi++) && !adjust_sel)
|
||||
{
|
||||
Field *fld= fi.get_curr_field();
|
||||
if (fld->table->map != table_bit)
|
||||
continue;
|
||||
if (ref == 0)
|
||||
adjust_sel= TRUE;
|
||||
else
|
||||
{
|
||||
uint i;
|
||||
for (i= 0; i < ref->key_parts; i++)
|
||||
{
|
||||
if (fld->field_index == key_info->key_part[i].fieldnr - 1)
|
||||
break;
|
||||
}
|
||||
if (i == ref->key_parts)
|
||||
{
|
||||
/*
|
||||
Field fld is included in multiple equality item_equal
|
||||
and is not a part of the ref key.
|
||||
The selectivity of the multiple equality must be taken
|
||||
into account unless one of the ref arguments is
|
||||
equal to fld.
|
||||
*/
|
||||
adjust_sel= TRUE;
|
||||
for (uint j= 0; j < ref->key_parts && adjust_sel; j++)
|
||||
{
|
||||
if (ref->items[j]->real_item()->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
Item_field *field_item= (Item_field *) (ref->items[j]);
|
||||
if (item_equal->contains(field_item->field))
|
||||
adjust_sel= FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adjust_sel)
|
||||
{
|
||||
/*
|
||||
If ref == 0 and there are no fields in the multiple equality
|
||||
item_equal that belong to the tables joined prior to s
|
||||
then the selectivity of multiple equality will be set to 1.0.
|
||||
*/
|
||||
double eq_fld_sel= 1.0;
|
||||
fi.rewind();
|
||||
while ((fi++))
|
||||
{
|
||||
double curr_eq_fld_sel;
|
||||
fld= fi.get_curr_field();
|
||||
if (!fld->table->map & ~(table_bit | rem_tables))
|
||||
continue;
|
||||
curr_eq_fld_sel= get_column_avg_frequency(fld) /
|
||||
fld->table->stat_records();
|
||||
if (curr_eq_fld_sel < 1.0)
|
||||
set_if_bigger(eq_fld_sel, curr_eq_fld_sel);
|
||||
}
|
||||
sel*= eq_fld_sel;
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
static
|
||||
double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
|
||||
table_map rem_tables)
|
||||
{
|
||||
Field *field;
|
||||
TABLE *table= s->table;
|
||||
MY_BITMAP *read_set= table->read_set;
|
||||
double sel= s->table->cond_selectivity;
|
||||
double table_records= table->stat_records();
|
||||
TABLE_REF *ref= s->type == JT_REF || s->type == JT_EQ_REF ? &s->ref : NULL;
|
||||
|
||||
/* Discount the selectivity of the access method used to join table s */
|
||||
if (s->quick && s->quick->index != MAX_KEY)
|
||||
{
|
||||
/* A range scan by index s->quick->index is used to access table s */
|
||||
sel*= table_records/table->quick_rows[s->quick->index];
|
||||
}
|
||||
else if (ref)
|
||||
{
|
||||
/* A ref/ access or hash join is used to join table s */
|
||||
KEY *key_info= s->get_keyinfo_by_key_no(ref->key);
|
||||
for (uint i= 0; i < ref->key_parts; i++)
|
||||
{
|
||||
if (ref->items[i]->const_item())
|
||||
{
|
||||
uint fldno= key_info->key_part[i].fieldnr - 1;
|
||||
sel*= table->field[fldno]->cond_selectivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Field **f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
||||
{
|
||||
if (!bitmap_is_set(read_set, field->field_index) ||
|
||||
!field->next_equal_field)
|
||||
continue;
|
||||
for (Field *next_field= field->next_equal_field;
|
||||
next_field != field;
|
||||
next_field= next_field->next_equal_field)
|
||||
{
|
||||
if (!(next_field->table->map & rem_tables) && next_field->table != table)
|
||||
{
|
||||
sel/= field->cond_selectivity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sel*= table_multi_eq_cond_selectivity(join, idx, s, rem_tables, ref);
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Find a good, possibly optimal, query execution plan (QEP) by a possibly
|
||||
exhaustive search.
|
||||
@ -6953,6 +7138,8 @@ double JOIN::get_examined_rows()
|
||||
@param prune_level pruning heuristics that should be applied during
|
||||
optimization
|
||||
(values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS)
|
||||
@param use_cond_selectivity specifies how the selectivity of the conditions
|
||||
pushed to a table should be taken into account
|
||||
|
||||
@retval
|
||||
FALSE ok
|
||||
@ -6967,7 +7154,8 @@ best_extension_by_limited_search(JOIN *join,
|
||||
double record_count,
|
||||
double read_time,
|
||||
uint search_depth,
|
||||
uint prune_level)
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity)
|
||||
{
|
||||
DBUG_ENTER("best_extension_by_limited_search");
|
||||
|
||||
@ -7070,16 +7258,25 @@ best_extension_by_limited_search(JOIN *join,
|
||||
}
|
||||
}
|
||||
|
||||
double pushdown_cond_selectivity= 1.0;
|
||||
if (use_cond_selectivity > 1)
|
||||
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s,
|
||||
remaining_tables &
|
||||
~real_table_bit);
|
||||
join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
|
||||
double partial_join_cardinality= current_record_count *
|
||||
pushdown_cond_selectivity;
|
||||
if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables )
|
||||
{ /* Recursively expand the current partial plan */
|
||||
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
if (best_extension_by_limited_search(join,
|
||||
remaining_tables & ~real_table_bit,
|
||||
idx + 1,
|
||||
current_record_count,
|
||||
partial_join_cardinality,
|
||||
current_read_time,
|
||||
search_depth - 1,
|
||||
prune_level))
|
||||
prune_level,
|
||||
use_cond_selectivity))
|
||||
DBUG_RETURN(TRUE);
|
||||
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
}
|
||||
@ -7097,7 +7294,7 @@ best_extension_by_limited_search(JOIN *join,
|
||||
{
|
||||
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
|
||||
sizeof(POSITION) * (idx + 1));
|
||||
join->record_count= current_record_count;
|
||||
join->record_count= partial_join_cardinality;
|
||||
join->best_read= current_read_time - 0.001;
|
||||
}
|
||||
DBUG_EXECUTE("opt", print_plan(join, idx+1,
|
||||
@ -7742,6 +7939,7 @@ get_best_combination(JOIN *join)
|
||||
*/
|
||||
SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info;
|
||||
j->records= j->records_read= (ha_rows)(sjm->is_sj_scan? sjm->rows : 1);
|
||||
j->cond_selectivity= 1.0;
|
||||
JOIN_TAB *jt;
|
||||
JOIN_TAB_RANGE *jt_range;
|
||||
if (!(jt= (JOIN_TAB*)join->thd->alloc(sizeof(JOIN_TAB)*sjm->tables)) ||
|
||||
@ -7805,6 +8003,7 @@ get_best_combination(JOIN *join)
|
||||
to access join->best_positions[].
|
||||
*/
|
||||
j->records_read= (ha_rows)join->best_positions[tablenr].records_read;
|
||||
j->cond_selectivity= join->best_positions[tablenr].cond_selectivity;
|
||||
join->map2table[j->table->tablenr]= j;
|
||||
|
||||
/* If we've reached the end of sjm nest, switch back to main sequence */
|
||||
@ -11779,7 +11978,8 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
|
||||
*/
|
||||
|
||||
static COND *build_equal_items_for_cond(THD *thd, COND *cond,
|
||||
COND_EQUAL *inherited)
|
||||
COND_EQUAL *inherited,
|
||||
bool link_item_fields)
|
||||
{
|
||||
Item_equal *item_equal;
|
||||
COND_EQUAL cond_equal;
|
||||
@ -11826,6 +12026,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
|
||||
List_iterator_fast<Item_equal> it(cond_equal.current_level);
|
||||
while ((item_equal= it++))
|
||||
{
|
||||
item_equal->set_link_equal_fields(link_item_fields);
|
||||
item_equal->fix_fields(thd, NULL);
|
||||
item_equal->update_used_tables();
|
||||
set_if_bigger(thd->lex->current_select->max_equal_elems,
|
||||
@ -11843,7 +12044,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
|
||||
while ((item= li++))
|
||||
{
|
||||
Item *new_item;
|
||||
if ((new_item= build_equal_items_for_cond(thd, item, inherited)) != item)
|
||||
if ((new_item= build_equal_items_for_cond(thd, item, inherited, FALSE))
|
||||
!= item)
|
||||
{
|
||||
/* This replacement happens only for standalone equalities */
|
||||
/*
|
||||
@ -12000,13 +12202,14 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
|
||||
|
||||
static COND *build_equal_items(THD *thd, COND *cond, COND_EQUAL *inherited,
|
||||
List<TABLE_LIST> *join_list,
|
||||
COND_EQUAL **cond_equal_ref)
|
||||
COND_EQUAL **cond_equal_ref,
|
||||
bool link_equal_fields)
|
||||
{
|
||||
COND_EQUAL *cond_equal= 0;
|
||||
|
||||
if (cond)
|
||||
{
|
||||
cond= build_equal_items_for_cond(thd, cond, inherited);
|
||||
cond= build_equal_items_for_cond(thd, cond, inherited, link_equal_fields);
|
||||
cond->update_used_tables();
|
||||
if (cond->type() == Item::COND_ITEM &&
|
||||
((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
|
||||
@ -13454,7 +13657,8 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
|
||||
|
||||
static COND *
|
||||
optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
|
||||
Item::cond_result *cond_value, COND_EQUAL **cond_equal)
|
||||
Item::cond_result *cond_value, COND_EQUAL **cond_equal,
|
||||
int flags)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
DBUG_ENTER("optimize_cond");
|
||||
@ -13475,8 +13679,9 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
|
||||
multiple equality contains a constant.
|
||||
*/
|
||||
DBUG_EXECUTE("where", print_where(conds, "original", QT_ORDINARY););
|
||||
conds= build_equal_items(join->thd, conds, NULL, join_list, cond_equal);
|
||||
DBUG_EXECUTE("where",print_where(conds,"after equal_items", QT_ORDINARY););
|
||||
conds= build_equal_items(join->thd, conds, NULL, join_list, cond_equal,
|
||||
test(flags & OPT_LINK_EQUAL_FIELDS));
|
||||
DBUG_EXECUTE("where",print_where(conds,"after equal_items", QT_ORDINARY););
|
||||
|
||||
/* change field = field to field = const for each found field = const */
|
||||
propagate_cond_constants(thd, (I_List<COND_CMP> *) 0, conds, conds);
|
||||
@ -14258,6 +14463,9 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
|
||||
bitmap_init(&table->eq_join_set,
|
||||
(my_bitmap_map*) (bitmaps+ 3*bitmap_buffer_size(field_count)),
|
||||
field_count, FALSE);
|
||||
bitmap_init(&table->cond_set,
|
||||
(my_bitmap_map*) (bitmaps+ 4*bitmap_buffer_size(field_count)),
|
||||
field_count, FALSE);
|
||||
/* write_set and all_set are copies of read_set */
|
||||
table->def_write_set= table->def_read_set;
|
||||
table->s->all_set= table->def_read_set;
|
||||
@ -14421,7 +14629,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
|
||||
&tmpname, (uint) strlen(path)+1,
|
||||
&group_buff, (group && ! using_unique_constraint ?
|
||||
param->group_length : 0),
|
||||
&bitmaps, bitmap_buffer_size(field_count)*4,
|
||||
&bitmaps, bitmap_buffer_size(field_count)*5,
|
||||
NullS))
|
||||
{
|
||||
if (temp_pool_slot != MY_BIT_NONE)
|
||||
@ -15176,7 +15384,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
|
||||
&share, sizeof(*share),
|
||||
&field, (field_count + 1) * sizeof(Field*),
|
||||
&blob_field, (field_count+1) *sizeof(uint),
|
||||
&bitmaps, bitmap_buffer_size(field_count)*4,
|
||||
&bitmaps, bitmap_buffer_size(field_count)*5,
|
||||
NullS))
|
||||
return 0;
|
||||
|
||||
@ -22068,7 +22276,13 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags,
|
||||
{
|
||||
float f= 0.0;
|
||||
if (examined_rows)
|
||||
f= (float) (100.0 * tab->records_read / examined_rows);
|
||||
{
|
||||
double pushdown_cond_selectivity= tab->cond_selectivity;
|
||||
if (pushdown_cond_selectivity == 1.0)
|
||||
f= (float) (100.0 * tab->records_read / examined_rows);
|
||||
else
|
||||
f= (float) (100.0 * pushdown_cond_selectivity);
|
||||
}
|
||||
set_if_smaller(f, 100.0);
|
||||
item_list.push_back(new Item_float(f, 2));
|
||||
}
|
||||
|
@ -292,6 +292,8 @@ typedef struct st_join_table {
|
||||
/* psergey-todo: make the below have type double, like POSITION::records_read? */
|
||||
ha_rows records_read;
|
||||
|
||||
double cond_selectivity;
|
||||
|
||||
/* Startup cost for execution */
|
||||
double startup_cost;
|
||||
|
||||
@ -762,6 +764,8 @@ typedef struct st_position :public Sql_alloc
|
||||
*/
|
||||
double records_read;
|
||||
|
||||
double cond_selectivity;
|
||||
|
||||
/*
|
||||
Cost accessing the table in course of the entire complete join execution,
|
||||
i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times
|
||||
@ -1804,6 +1808,8 @@ void eliminate_tables(JOIN *join);
|
||||
/* Index Condition Pushdown entry point function */
|
||||
void push_index_cond(JOIN_TAB *tab, uint keyno);
|
||||
|
||||
#define OPT_LINK_EQUAL_FIELDS 1
|
||||
|
||||
/****************************************************************************
|
||||
Temporary table support for SQL Runtime
|
||||
***************************************************************************/
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "sql_base.h"
|
||||
#include "key.h"
|
||||
#include "sql_statistics.h"
|
||||
#include "opt_range.h"
|
||||
#include "my_atomic.h"
|
||||
|
||||
/*
|
||||
@ -3054,3 +3055,51 @@ void set_statistics_for_table(THD *thd, TABLE *table)
|
||||
key_info->read_stats->get_avg_frequency(0) > 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double get_column_avg_frequency(Field * field)
|
||||
{
|
||||
double res;
|
||||
TABLE *table= field->table;
|
||||
Column_statistics *col_stats= table->s->field[field->field_index]->read_stats;
|
||||
|
||||
if (!col_stats)
|
||||
res= table->stat_records();
|
||||
else
|
||||
res= col_stats->get_avg_frequency();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
double get_column_range_cardinality(Field *field,
|
||||
key_range *min_endp,
|
||||
key_range *max_endp)
|
||||
{
|
||||
double res;
|
||||
TABLE *table= field->table;
|
||||
Column_statistics *col_stats= table->field[field->field_index]->read_stats;
|
||||
|
||||
if (!col_stats)
|
||||
res= table->stat_records();
|
||||
else if (min_endp->length == max_endp->length &&
|
||||
!memcmp(min_endp->key, max_endp->key, min_endp->length))
|
||||
{
|
||||
res= col_stats->get_avg_frequency();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col_stats->min_value && col_stats->max_value)
|
||||
{
|
||||
store_key_image_to_rec(field, (uchar *) min_endp->key, min_endp->length);
|
||||
double min_mp_pos= field->middle_point_pos(col_stats->min_value,
|
||||
col_stats->max_value);
|
||||
store_key_image_to_rec(field, (uchar *) max_endp->key, max_endp->length);
|
||||
double max_mp_pos= field->middle_point_pos(col_stats->min_value,
|
||||
col_stats->max_value);
|
||||
res= table->stat_records() * (max_mp_pos - min_mp_pos);
|
||||
}
|
||||
else
|
||||
res= table->stat_records();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -90,6 +90,12 @@ int rename_column_in_stat_tables(THD *thd, TABLE *tab, Field *col,
|
||||
const char *new_name);
|
||||
void set_statistics_for_table(THD *thd, TABLE *table);
|
||||
|
||||
double get_column_avg_frequency(Field * field);
|
||||
|
||||
double get_column_range_cardinality(Field *field,
|
||||
key_range *min_endp,
|
||||
key_range *max_endp);
|
||||
|
||||
class Columns_statistics;
|
||||
class Index_statistics;
|
||||
|
||||
|
@ -1424,6 +1424,22 @@ static Sys_var_ulong Sys_optimizer_prune_level(
|
||||
SESSION_VAR(optimizer_prune_level), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(0, 1), DEFAULT(1), BLOCK_SIZE(1));
|
||||
|
||||
static Sys_var_ulong Sys_optimizer_use_condition_selectivity(
|
||||
"optimizer_use_condition_selectivity",
|
||||
"Controls selectivity of which conditions the optimizer takes into "
|
||||
"account to calculate cardinality of a partial join when it searches "
|
||||
"for the best execution plan "
|
||||
"Meaning: "
|
||||
"1 - use selectivity of index backed range conditions to calculate "
|
||||
"cardinality of the partial join if the last joined table is "
|
||||
"accessed by full table scan or an index scan "
|
||||
"2 - use selectivity of index backed range conditions to calculate "
|
||||
"cardinality of the partial join in any case "
|
||||
"3 - additionally always use selectivity of range conditions that are "
|
||||
"not backed by any index to calculate cardinality of the partial join",
|
||||
SESSION_VAR(optimizer_use_condition_selectivity), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(1, 3), DEFAULT(1), BLOCK_SIZE(1));
|
||||
|
||||
/** Warns about deprecated value 63 */
|
||||
static bool fix_optimizer_search_depth(sys_var *self, THD *thd,
|
||||
enum_var_type type)
|
||||
|
@ -2630,7 +2630,7 @@ partititon_err:
|
||||
/* Allocate bitmaps */
|
||||
|
||||
bitmap_size= share->column_bitmap_size;
|
||||
if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*5)))
|
||||
if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*6)))
|
||||
goto err;
|
||||
bitmap_init(&outparam->def_read_set,
|
||||
(my_bitmap_map*) bitmaps, share->fields, FALSE);
|
||||
@ -2642,8 +2642,12 @@ partititon_err:
|
||||
(my_bitmap_map*) (bitmaps+bitmap_size*3), share->fields, FALSE);
|
||||
bitmap_init(&outparam->eq_join_set,
|
||||
(my_bitmap_map*) (bitmaps+bitmap_size*4), share->fields, FALSE);
|
||||
bitmap_init(&outparam->cond_set,
|
||||
(my_bitmap_map*) (bitmaps+bitmap_size*5), share->fields, FALSE);
|
||||
outparam->default_column_bitmaps();
|
||||
|
||||
outparam->cond_selectivity= 1.0;
|
||||
|
||||
/* The table struct is now initialized; Open the table */
|
||||
error= 2;
|
||||
if (db_stat)
|
||||
|
@ -1026,6 +1026,7 @@ public:
|
||||
my_bitmap_map *bitmap_init_value;
|
||||
MY_BITMAP def_read_set, def_write_set, def_vcol_set, tmp_set;
|
||||
MY_BITMAP eq_join_set; /* used to mark equi-joined fields */
|
||||
MY_BITMAP cond_set; /* used to mark fields from sargable conditions*/
|
||||
MY_BITMAP *read_set, *write_set, *vcol_set; /* Active column sets */
|
||||
/*
|
||||
The ID of the query that opened and is using this table. Has different
|
||||
@ -1078,6 +1079,8 @@ public:
|
||||
*/
|
||||
ha_rows quick_condition_rows;
|
||||
|
||||
double cond_selectivity;
|
||||
|
||||
table_map map; /* ID bit of table (1,2,4,8,16...) */
|
||||
|
||||
uint lock_position; /* Position in MYSQL_LOCK.table */
|
||||
|
Loading…
x
Reference in New Issue
Block a user