mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Make the most important optimizer constants user variables
Variables added: - optimizer_index_block_copy_cost - optimizer_key_copy_cost - optimizer_key_next_find_cost - optimizer_key_compare_cost - optimizer_row_copy_cost - optimizer_where_compare_cost Some rename of defines was done to make the internal defines similar to the visible ones: TIME_FOR_COMPARE -> WHERE_COST; WHERE_COST was also "inverted" to be a number between 0 and 1 that is multiply with accepted records (similar to other optimizer variables). TIME_FOR_COMPARE_IDX -> KEY_COMPARE_COST. This is also inverted, similar to TIME_FOR_COMPARE. TIME_FOR_COMPARE_ROWID -> ROWID_COMPARE_COST. This is also inverted, similar to TIME_FOR_COMPARE. All default costs are identical to what they where before this patch. Other things: - Compare factor in get_merge_buffers_cost() was inverted. - Changed namespace to static in filesort_utils.cc
This commit is contained in:
@@ -80,7 +80,7 @@ EXPLAIN
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE Name LIKE 'M%' AND Population > 7000000;
|
WHERE Name LIKE 'M%' AND Population > 7000000;
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge Population,Name Population,Name 4,35 NULL # Using sort_intersect(Population,Name); Using where
|
1 SIMPLE City range Population,Name Population 4 NULL # Using index condition; Using where
|
||||||
SELECT * FROM City USE INDEX ()
|
SELECT * FROM City USE INDEX ()
|
||||||
WHERE Name LIKE 'C%' AND Population > 1000000;
|
WHERE Name LIKE 'C%' AND Population > 1000000;
|
||||||
ID Name Country Population
|
ID Name Country Population
|
||||||
@@ -335,8 +335,8 @@ ID Name Country Population
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE Name LIKE 'M%' AND Population > 7000000;
|
WHERE Name LIKE 'M%' AND Population > 7000000;
|
||||||
ID Name Country Population
|
ID Name Country Population
|
||||||
1024 Mumbai (Bombay) IND 10500000
|
|
||||||
3580 Moscow RUS 8389200
|
3580 Moscow RUS 8389200
|
||||||
|
1024 Mumbai (Bombay) IND 10500000
|
||||||
SELECT COUNT(*) FROM City WHERE Name BETWEEN 'M' AND 'N';
|
SELECT COUNT(*) FROM City WHERE Name BETWEEN 'M' AND 'N';
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
301
|
301
|
||||||
@@ -372,7 +372,7 @@ EXPLAIN
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE Name BETWEEN 'G' AND 'K' AND Population > 500000 AND Country LIKE 'C%';
|
WHERE Name BETWEEN 'G' AND 'K' AND Population > 500000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge Population,Name,Country Name,Country,Population # NULL # Using sort_intersect(Name,Country,Population); Using where
|
1 SIMPLE City index_merge Population,Name,Country Name,Country # NULL # Using sort_intersect(Name,Country); Using where
|
||||||
SELECT * FROM City USE INDEX ()
|
SELECT * FROM City USE INDEX ()
|
||||||
WHERE Name BETWEEN 'M' AND 'N' AND Population > 1000000 AND Country LIKE 'C%';
|
WHERE Name BETWEEN 'M' AND 'N' AND Population > 1000000 AND Country LIKE 'C%';
|
||||||
ID Name Country Population
|
ID Name Country Population
|
||||||
@@ -463,12 +463,12 @@ EXPLAIN
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 501 AND 1000 AND Population > 700000 AND Country LIKE 'C%';
|
WHERE ID BETWEEN 501 AND 1000 AND Population > 700000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge PRIMARY,Population,Country Population,PRIMARY,Country 4,4,3 NULL # Using sort_intersect(Population,PRIMARY,Country); Using where
|
1 SIMPLE City index_merge PRIMARY,Population,Country Population,PRIMARY 4,4 NULL # Using sort_intersect(Population,PRIMARY); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge PRIMARY,Population,Country Population,PRIMARY,Country 4,4,3 NULL # Using sort_intersect(Population,PRIMARY,Country); Using where
|
1 SIMPLE City index_merge PRIMARY,Population,Country Population,PRIMARY 4,4 NULL # Using sort_intersect(Population,PRIMARY); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 2001 AND 2500 AND Population > 300000 AND Country LIKE 'H%';
|
WHERE ID BETWEEN 2001 AND 2500 AND Population > 300000 AND Country LIKE 'H%';
|
||||||
|
@@ -469,12 +469,12 @@ EXPLAIN
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 501 AND 1000 AND Population > 700000 AND Country LIKE 'C%';
|
WHERE ID BETWEEN 501 AND 1000 AND Population > 700000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population,Country 4,4,7 NULL # Using sort_intersect(PRIMARY,Population,Country); Using where
|
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population 4,4 NULL # Using sort_intersect(PRIMARY,Population); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population,Country 4,4,7 NULL # Using sort_intersect(PRIMARY,Population,Country); Using where
|
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population 4,4 NULL # Using sort_intersect(PRIMARY,Population); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 2001 AND 2500 AND Population > 300000 AND Country LIKE 'H%';
|
WHERE ID BETWEEN 2001 AND 2500 AND Population > 300000 AND Country LIKE 'H%';
|
||||||
@@ -718,12 +718,12 @@ EXPLAIN
|
|||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE Name BETWEEN 'G' AND 'J' AND Population > 500000 AND Country LIKE 'C%';
|
WHERE Name BETWEEN 'G' AND 'J' AND Population > 500000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge Population,Country,Name Name,Population,Country 35,4,3 NULL # Using sort_intersect(Name,Population,Country); Using where
|
1 SIMPLE City index_merge Population,Country,Name Name,Population 35,4 NULL # Using sort_intersect(Name,Population); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
WHERE ID BETWEEN 1 AND 500 AND Population > 700000 AND Country LIKE 'C%';
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population,Country 4,4,7 NULL # Using sort_intersect(PRIMARY,Population,Country); Using where
|
1 SIMPLE City index_merge PRIMARY,Population,Country PRIMARY,Population 4,4 NULL # Using sort_intersect(PRIMARY,Population); Using where
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM City
|
SELECT * FROM City
|
||||||
WHERE ID BETWEEN 3001 AND 4000 AND Population > 600000
|
WHERE ID BETWEEN 3001 AND 4000 AND Population > 600000
|
||||||
|
@@ -724,11 +724,22 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
Expected hit rate of the row and index cache in storage
|
Expected hit rate of the row and index cache in storage
|
||||||
engines. The value should be an integer between 0 and 99,
|
engines. The value should be an integer between 0 and 99,
|
||||||
where 0 means cache is empty and 99 means that value is
|
where 0 means cache is empty and 99 means that value is
|
||||||
almost always in the cache
|
almost always in the cache.
|
||||||
--optimizer-extra-pruning-depth=#
|
--optimizer-extra-pruning-depth=#
|
||||||
If the optimizer needs to enumerate join prefix of this
|
If the optimizer needs to enumerate join prefix of this
|
||||||
size or larger, then it will try agressively prune away
|
size or larger, then it will try agressively prune away
|
||||||
the search space.
|
the search space.
|
||||||
|
--optimizer-index-block-copy-cost=#
|
||||||
|
Cost of copying a key block from the cache to intern
|
||||||
|
storage as part of an index scan.
|
||||||
|
--optimizer-key-compare-cost=#
|
||||||
|
Cost of checking a key against the end key condition.
|
||||||
|
--optimizer-key-copy-cost=#
|
||||||
|
Cost of finding the next key in the engine and copying it
|
||||||
|
to the SQL layer.
|
||||||
|
--optimizer-key-next-find-cost=#
|
||||||
|
Cost of finding the next key and rowid when using
|
||||||
|
filters.
|
||||||
--optimizer-max-sel-arg-weight=#
|
--optimizer-max-sel-arg-weight=#
|
||||||
The maximum weight of the SEL_ARG graph. Set to 0 for no
|
The maximum weight of the SEL_ARG graph. Set to 0 for no
|
||||||
limit
|
limit
|
||||||
@@ -739,6 +750,9 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
heuristic, thus perform exhaustive search: 1 - prune
|
heuristic, thus perform exhaustive search: 1 - prune
|
||||||
plans based on cost and number of retrieved rows eq_ref:
|
plans based on cost and number of retrieved rows eq_ref:
|
||||||
2 - prune also if we find an eq_ref chain
|
2 - prune also if we find an eq_ref chain
|
||||||
|
--optimizer-row-copy-cost=#
|
||||||
|
Cost of copying a row from the engine or the join cache
|
||||||
|
to the SQL layer.
|
||||||
--optimizer-search-depth=#
|
--optimizer-search-depth=#
|
||||||
Maximum depth of search performed by the query optimizer.
|
Maximum depth of search performed by the query optimizer.
|
||||||
Values larger than the number of relations in a query
|
Values larger than the number of relations in a query
|
||||||
@@ -791,6 +805,8 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
the cardinality of a partial join.5 - additionally use
|
the cardinality of a partial join.5 - additionally use
|
||||||
selectivity of certain non-range predicates calculated on
|
selectivity of certain non-range predicates calculated on
|
||||||
record samples
|
record samples
|
||||||
|
--optimizer-where-cost=#
|
||||||
|
Cost of checking the row against the WHERE clause.
|
||||||
--performance-schema
|
--performance-schema
|
||||||
Enable the performance schema.
|
Enable the performance schema.
|
||||||
--performance-schema-accounts-size=#
|
--performance-schema-accounts-size=#
|
||||||
@@ -1705,14 +1721,20 @@ old-passwords FALSE
|
|||||||
old-style-user-limits FALSE
|
old-style-user-limits FALSE
|
||||||
optimizer-cache-hit-ratio 50
|
optimizer-cache-hit-ratio 50
|
||||||
optimizer-extra-pruning-depth 8
|
optimizer-extra-pruning-depth 8
|
||||||
|
optimizer-index-block-copy-cost 0.2
|
||||||
|
optimizer-key-compare-cost 0.05
|
||||||
|
optimizer-key-copy-cost 0.025
|
||||||
|
optimizer-key-next-find-cost 0.0125
|
||||||
optimizer-max-sel-arg-weight 32000
|
optimizer-max-sel-arg-weight 32000
|
||||||
optimizer-prune-level 2
|
optimizer-prune-level 2
|
||||||
|
optimizer-row-copy-cost 0.05
|
||||||
optimizer-search-depth 62
|
optimizer-search-depth 62
|
||||||
optimizer-selectivity-sampling-limit 100
|
optimizer-selectivity-sampling-limit 100
|
||||||
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=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on
|
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=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on
|
||||||
optimizer-trace
|
optimizer-trace
|
||||||
optimizer-trace-max-mem-size 1048576
|
optimizer-trace-max-mem-size 1048576
|
||||||
optimizer-use-condition-selectivity 4
|
optimizer-use-condition-selectivity 4
|
||||||
|
optimizer-where-cost 0.2
|
||||||
performance-schema FALSE
|
performance-schema FALSE
|
||||||
performance-schema-accounts-size -1
|
performance-schema-accounts-size -1
|
||||||
performance-schema-consumer-events-stages-current FALSE
|
performance-schema-consumer-events-stages-current FALSE
|
||||||
|
@@ -29,6 +29,7 @@ perl;
|
|||||||
collation-server character-set-server log-tc-size table-cache
|
collation-server character-set-server log-tc-size table-cache
|
||||||
table-open-cache table-open-cache-instances max-connections
|
table-open-cache table-open-cache-instances max-connections
|
||||||
tls-version version.* password-reuse-check
|
tls-version version.* password-reuse-check
|
||||||
|
provider-bzip2 provider-lzma provider-lzo
|
||||||
password-reuse-check-interval/;
|
password-reuse-check-interval/;
|
||||||
|
|
||||||
# Plugins which may or may not be there:
|
# Plugins which may or may not be there:
|
||||||
|
@@ -158,7 +158,7 @@ explain select * from t1 where a=1 or b=1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_roworder_union_cost": 2.595171589,
|
"index_roworder_union_cost": 2.601171589,
|
||||||
"members": 2,
|
"members": 2,
|
||||||
"chosen": true
|
"chosen": true
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ explain select * from t1 where a=1 or b=1 {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"rows_for_plan": 2,
|
"rows_for_plan": 2,
|
||||||
"cost_for_plan": 2.595171589,
|
"cost_for_plan": 2.601171589,
|
||||||
"chosen": true
|
"chosen": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,14 +220,14 @@ explain select * from t1 where a=1 or b=1 {
|
|||||||
"rows": 2,
|
"rows": 2,
|
||||||
"rows_after_scan": 2,
|
"rows_after_scan": 2,
|
||||||
"rows_after_filter": 2,
|
"rows_after_filter": 2,
|
||||||
"cost": 2.595171589,
|
"cost": 2.601171589,
|
||||||
"chosen": true
|
"chosen": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"chosen_access_method": {
|
"chosen_access_method": {
|
||||||
"type": "index_merge",
|
"type": "index_merge",
|
||||||
"records": 2,
|
"records": 2,
|
||||||
"cost": 2.595171589,
|
"cost": 2.601171589,
|
||||||
"uses_join_buffering": false
|
"uses_join_buffering": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,14 +238,14 @@ explain select * from t1 where a=1 or b=1 {
|
|||||||
"plan_prefix": [],
|
"plan_prefix": [],
|
||||||
"table": "t1",
|
"table": "t1",
|
||||||
"rows_for_plan": 2,
|
"rows_for_plan": 2,
|
||||||
"cost_for_plan": 2.595171589
|
"cost_for_plan": 2.601171589
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"best_join_order": ["t1"],
|
"best_join_order": ["t1"],
|
||||||
"rows": 2,
|
"rows": 2,
|
||||||
"cost": 2.595171589
|
"cost": 2.601171589
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"substitute_best_equal": {
|
"substitute_best_equal": {
|
||||||
@@ -630,7 +630,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_roworder_union_cost": 332.5637481,
|
"index_roworder_union_cost": 333.0257481,
|
||||||
"members": 2,
|
"members": 2,
|
||||||
"chosen": true
|
"chosen": true
|
||||||
}
|
}
|
||||||
@@ -697,7 +697,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.chosen_range_access_summary'))
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"rows_for_plan": 154,
|
"rows_for_plan": 154,
|
||||||
"cost_for_plan": 332.5637481,
|
"cost_for_plan": 333.0257481,
|
||||||
"chosen": true
|
"chosen": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@@ -88,7 +88,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
|||||||
2 DEPENDENT SUBQUERY region eq_ref PRIMARY PRIMARY 4 dbt3_s001.nation.n_regionkey 1 20.00 Using where
|
2 DEPENDENT SUBQUERY region eq_ref PRIMARY PRIMARY 4 dbt3_s001.nation.n_regionkey 1 20.00 Using where
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1276 Field or reference 'dbt3_s001.part.p_partkey' of SELECT #2 was resolved in SELECT #1
|
Note 1276 Field or reference 'dbt3_s001.part.p_partkey' of SELECT #2 was resolved in SELECT #1
|
||||||
Note 1003 /* select#1 */ select `dbt3_s001`.`supplier`.`s_acctbal` AS `s_acctbal`,`dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`nation`.`n_name` AS `n_name`,`dbt3_s001`.`part`.`p_partkey` AS `p_partkey`,`dbt3_s001`.`part`.`p_mfgr` AS `p_mfgr`,`dbt3_s001`.`supplier`.`s_address` AS `s_address`,`dbt3_s001`.`supplier`.`s_phone` AS `s_phone`,`dbt3_s001`.`supplier`.`s_comment` AS `s_comment` from `dbt3_s001`.`part` join `dbt3_s001`.`supplier` join `dbt3_s001`.`partsupp` join `dbt3_s001`.`nation` join `dbt3_s001`.`region` where `dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey` and `dbt3_s001`.`supplier`.`s_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey` and `dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey` and `dbt3_s001`.`nation`.`n_regionkey` = `dbt3_s001`.`region`.`r_regionkey` and `dbt3_s001`.`region`.`r_name` = 'ASIA' and (`dbt3_s001`.`part`.`p_size` = 9 or `dbt3_s001`.`part`.`p_size` = 19999) and `dbt3_s001`.`part`.`p_type` like '%TIN' and `dbt3_s001`.`partsupp`.`ps_supplycost` = <expr_cache><`dbt3_s001`.`part`.`p_partkey`>((/* select#2 */ select min(`dbt3_s001`.`partsupp`.`ps_supplycost`) from `dbt3_s001`.`partsupp` join `dbt3_s001`.`supplier` join `dbt3_s001`.`nation` join `dbt3_s001`.`region` where `dbt3_s001`.`supplier`.`s_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey` and `dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey` and `dbt3_s001`.`nation`.`n_regionkey` = `dbt3_s001`.`region`.`r_regionkey` and `dbt3_s001`.`region`.`r_name` = 'ASIA' and `dbt3_s001`.`part`.`p_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`)) order by `dbt3_s001`.`supplier`.`s_acctbal` desc,`dbt3_s001`.`nation`.`n_name`,`dbt3_s001`.`supplier`.`s_name`,`dbt3_s001`.`part`.`p_partkey`
|
Note 1003 /* select#1 */ select `dbt3_s001`.`supplier`.`s_acctbal` AS `s_acctbal`,`dbt3_s001`.`supplier`.`s_name` AS `s_name`,`dbt3_s001`.`nation`.`n_name` AS `n_name`,`dbt3_s001`.`part`.`p_partkey` AS `p_partkey`,`dbt3_s001`.`part`.`p_mfgr` AS `p_mfgr`,`dbt3_s001`.`supplier`.`s_address` AS `s_address`,`dbt3_s001`.`supplier`.`s_phone` AS `s_phone`,`dbt3_s001`.`supplier`.`s_comment` AS `s_comment` from `dbt3_s001`.`part` join `dbt3_s001`.`supplier` join `dbt3_s001`.`partsupp` join `dbt3_s001`.`nation` join `dbt3_s001`.`region` where `dbt3_s001`.`partsupp`.`ps_partkey` = `dbt3_s001`.`part`.`p_partkey` and `dbt3_s001`.`supplier`.`s_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey` and `dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey` and `dbt3_s001`.`nation`.`n_regionkey` = `dbt3_s001`.`region`.`r_regionkey` and `dbt3_s001`.`region`.`r_name` = 'ASIA' and (`dbt3_s001`.`part`.`p_size` = 9 or `dbt3_s001`.`part`.`p_size` = 19999) and `dbt3_s001`.`part`.`p_type` like '%TIN' and `dbt3_s001`.`partsupp`.`ps_supplycost` = <expr_cache><`dbt3_s001`.`part`.`p_partkey`>((/* select#2 */ select min(`dbt3_s001`.`partsupp`.`ps_supplycost`) from `dbt3_s001`.`partsupp` join `dbt3_s001`.`supplier` join `dbt3_s001`.`nation` join `dbt3_s001`.`region` where `dbt3_s001`.`supplier`.`s_suppkey` = `dbt3_s001`.`partsupp`.`ps_suppkey` and `dbt3_s001`.`nation`.`n_nationkey` = `dbt3_s001`.`supplier`.`s_nationkey` and `dbt3_s001`.`region`.`r_regionkey` = `dbt3_s001`.`nation`.`n_regionkey` and `dbt3_s001`.`region`.`r_name` = 'ASIA' and `dbt3_s001`.`part`.`p_partkey` = `dbt3_s001`.`partsupp`.`ps_partkey`)) order by `dbt3_s001`.`supplier`.`s_acctbal` desc,`dbt3_s001`.`nation`.`n_name`,`dbt3_s001`.`supplier`.`s_name`,`dbt3_s001`.`part`.`p_partkey`
|
||||||
set optimizer_use_condition_selectivity=4;
|
set optimizer_use_condition_selectivity=4;
|
||||||
explain extended
|
explain extended
|
||||||
select
|
select
|
||||||
|
@@ -2292,6 +2292,16 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY YES
|
READ_ONLY YES
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_CACHE_HIT_RATIO
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE INT UNSIGNED
|
||||||
|
VARIABLE_COMMENT Expected hit rate of the row and index cache in storage engines. The value should be an integer between 0 and 99, where 0 means cache is empty and 99 means that value is almost always in the cache.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 99
|
||||||
|
NUMERIC_BLOCK_SIZE 1
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_EXTRA_PRUNING_DEPTH
|
VARIABLE_NAME OPTIMIZER_EXTRA_PRUNING_DEPTH
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE BIGINT UNSIGNED
|
VARIABLE_TYPE BIGINT UNSIGNED
|
||||||
@@ -2302,6 +2312,46 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_INDEX_BLOCK_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of copying a key block from the cache to intern storage as part of an index scan.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_COMPARE_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of checking a key against the end key condition.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of finding the next key in the engine and copying it to the SQL layer.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_NEXT_FIND_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of finding the next key and rowid when using filters.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_MAX_SEL_ARG_WEIGHT
|
VARIABLE_NAME OPTIMIZER_MAX_SEL_ARG_WEIGHT
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE BIGINT UNSIGNED
|
VARIABLE_TYPE BIGINT UNSIGNED
|
||||||
@@ -2322,6 +2372,16 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_ROW_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of copying a row from the engine or the join cache to the SQL layer.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_SEARCH_DEPTH
|
VARIABLE_NAME OPTIMIZER_SEARCH_DEPTH
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE BIGINT UNSIGNED
|
VARIABLE_TYPE BIGINT UNSIGNED
|
||||||
@@ -2382,6 +2442,16 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_WHERE_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of checking the row against the WHERE clause.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME PERFORMANCE_SCHEMA
|
VARIABLE_NAME PERFORMANCE_SCHEMA
|
||||||
VARIABLE_SCOPE GLOBAL
|
VARIABLE_SCOPE GLOBAL
|
||||||
VARIABLE_TYPE BOOLEAN
|
VARIABLE_TYPE BOOLEAN
|
||||||
|
@@ -2465,7 +2465,7 @@ COMMAND_LINE_ARGUMENT REQUIRED
|
|||||||
VARIABLE_NAME OPTIMIZER_CACHE_HIT_RATIO
|
VARIABLE_NAME OPTIMIZER_CACHE_HIT_RATIO
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE INT UNSIGNED
|
VARIABLE_TYPE INT UNSIGNED
|
||||||
VARIABLE_COMMENT Expected hit rate of the row and index cache in storage engines. The value should be an integer between 0 and 99, where 0 means cache is empty and 99 means that value is almost always in the cache
|
VARIABLE_COMMENT Expected hit rate of the row and index cache in storage engines. The value should be an integer between 0 and 99, where 0 means cache is empty and 99 means that value is almost always in the cache.
|
||||||
NUMERIC_MIN_VALUE 0
|
NUMERIC_MIN_VALUE 0
|
||||||
NUMERIC_MAX_VALUE 99
|
NUMERIC_MAX_VALUE 99
|
||||||
NUMERIC_BLOCK_SIZE 1
|
NUMERIC_BLOCK_SIZE 1
|
||||||
@@ -2482,6 +2482,46 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_INDEX_BLOCK_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of copying a key block from the cache to intern storage as part of an index scan.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_COMPARE_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of checking a key against the end key condition.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of finding the next key in the engine and copying it to the SQL layer.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_KEY_NEXT_FIND_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of finding the next key and rowid when using filters.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_MAX_SEL_ARG_WEIGHT
|
VARIABLE_NAME OPTIMIZER_MAX_SEL_ARG_WEIGHT
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE BIGINT UNSIGNED
|
VARIABLE_TYPE BIGINT UNSIGNED
|
||||||
@@ -2502,6 +2542,16 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_ROW_COPY_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of copying a row from the engine or the join cache to the SQL layer.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME OPTIMIZER_SEARCH_DEPTH
|
VARIABLE_NAME OPTIMIZER_SEARCH_DEPTH
|
||||||
VARIABLE_SCOPE SESSION
|
VARIABLE_SCOPE SESSION
|
||||||
VARIABLE_TYPE BIGINT UNSIGNED
|
VARIABLE_TYPE BIGINT UNSIGNED
|
||||||
@@ -2562,6 +2612,16 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME OPTIMIZER_WHERE_COST
|
||||||
|
VARIABLE_SCOPE SESSION
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT Cost of checking the row against the WHERE clause.
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 1
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME PERFORMANCE_SCHEMA
|
VARIABLE_NAME PERFORMANCE_SCHEMA
|
||||||
VARIABLE_SCOPE GLOBAL
|
VARIABLE_SCOPE GLOBAL
|
||||||
VARIABLE_TYPE BOOLEAN
|
VARIABLE_TYPE BOOLEAN
|
||||||
|
@@ -1594,17 +1594,18 @@ static bool check_if_pq_applicable(Sort_param *param,
|
|||||||
scanning the table and comparing the rows with the where clause!
|
scanning the table and comparing the rows with the where clause!
|
||||||
*/
|
*/
|
||||||
const double sort_merge_cost=
|
const double sort_merge_cost=
|
||||||
get_merge_many_buffs_cost_fast(num_rows,
|
get_merge_many_buffs_cost_fast(table->in_use, num_rows,
|
||||||
num_available_keys,
|
num_available_keys,
|
||||||
(uint)row_length);
|
(uint)row_length);
|
||||||
/*
|
/*
|
||||||
PQ has cost:
|
PQ has cost:
|
||||||
(insert + qsort) * log(queue size) / TIME_FOR_COMPARE_ROWID +
|
(insert + qsort) * log(queue size) * ROWID_COMPARE_COST
|
||||||
cost of rowid lookup of the original row to find the addon fields.
|
cost of rowid lookup of the original row to find the addon fields.
|
||||||
*/
|
*/
|
||||||
const double pq_cpu_cost=
|
const double pq_cpu_cost=
|
||||||
(PQ_slowness * num_rows + param->max_keys_per_buffer) *
|
(PQ_slowness * num_rows + param->max_keys_per_buffer) *
|
||||||
log((double) param->max_keys_per_buffer) / TIME_FOR_COMPARE_ROWID;
|
log((double) param->max_keys_per_buffer) *
|
||||||
|
ROWID_COMPARE_COST_THD(table->in_use);
|
||||||
const double pq_io_cost= table->file->ha_rnd_pos_time(param->max_rows);
|
const double pq_io_cost= table->file->ha_rnd_pos_time(param->max_rows);
|
||||||
const double pq_cost= pq_cpu_cost + pq_io_cost;
|
const double pq_cost= pq_cpu_cost + pq_io_cost;
|
||||||
|
|
||||||
|
@@ -23,17 +23,16 @@
|
|||||||
|
|
||||||
PSI_memory_key key_memory_Filesort_buffer_sort_keys;
|
PSI_memory_key key_memory_Filesort_buffer_sort_keys;
|
||||||
|
|
||||||
namespace {
|
|
||||||
/**
|
/**
|
||||||
A local helper function. See comments for get_merge_buffers_cost().
|
A local helper function. See comments for get_merge_buffers_cost().
|
||||||
*/
|
*/
|
||||||
double get_merge_cost(ha_rows num_elements, ha_rows num_buffers, uint elem_size)
|
|
||||||
|
static double get_merge_cost(double rowid_compare_cost, ha_rows num_elements,
|
||||||
|
ha_rows num_buffers, uint elem_size)
|
||||||
{
|
{
|
||||||
return
|
return (2.0 * ((double) num_elements * elem_size) / IO_SIZE
|
||||||
2.0 * ((double) num_elements * elem_size) / IO_SIZE
|
+ (double) num_elements * log((double) num_buffers) *
|
||||||
+ (double) num_elements * log((double) num_buffers) /
|
rowid_compare_cost / M_LN2);
|
||||||
(TIME_FOR_COMPARE_ROWID * M_LN2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,19 +42,20 @@ double get_merge_cost(ha_rows num_elements, ha_rows num_buffers, uint elem_size)
|
|||||||
see comments for get_merge_buffers_cost().
|
see comments for get_merge_buffers_cost().
|
||||||
TODO: Use this function for Unique::get_use_cost().
|
TODO: Use this function for Unique::get_use_cost().
|
||||||
*/
|
*/
|
||||||
double get_merge_many_buffs_cost_fast(ha_rows num_rows,
|
|
||||||
|
double get_merge_many_buffs_cost_fast(THD *thd,
|
||||||
|
ha_rows num_rows,
|
||||||
ha_rows num_keys_per_buffer,
|
ha_rows num_keys_per_buffer,
|
||||||
uint elem_size)
|
uint elem_size)
|
||||||
{
|
{
|
||||||
ha_rows num_buffers= num_rows / num_keys_per_buffer;
|
ha_rows num_buffers= num_rows / num_keys_per_buffer;
|
||||||
ha_rows last_n_elems= num_rows % num_keys_per_buffer;
|
ha_rows last_n_elems= num_rows % num_keys_per_buffer;
|
||||||
double total_cost;
|
double total_cost, rowid_compare_cost= ROWID_COMPARE_COST_THD(thd);
|
||||||
|
|
||||||
// Calculate CPU cost of sorting buffers.
|
// Calculate CPU cost of sorting buffers.
|
||||||
total_cost=
|
total_cost=
|
||||||
((num_buffers * num_keys_per_buffer * log(1.0 + num_keys_per_buffer) +
|
((num_buffers * num_keys_per_buffer * log(1.0 + num_keys_per_buffer) +
|
||||||
last_n_elems * log(1.0 + last_n_elems)) /
|
last_n_elems * log(1.0 + last_n_elems)) * rowid_compare_cost);
|
||||||
TIME_FOR_COMPARE_ROWID);
|
|
||||||
|
|
||||||
// Simulate behavior of merge_many_buff().
|
// Simulate behavior of merge_many_buff().
|
||||||
while (num_buffers >= MERGEBUFF2)
|
while (num_buffers >= MERGEBUFF2)
|
||||||
@@ -69,14 +69,16 @@ double get_merge_many_buffs_cost_fast(ha_rows num_rows,
|
|||||||
// Cost of merge sort 'num_merge_calls'.
|
// Cost of merge sort 'num_merge_calls'.
|
||||||
total_cost+=
|
total_cost+=
|
||||||
num_merge_calls *
|
num_merge_calls *
|
||||||
get_merge_cost(num_keys_per_buffer * MERGEBUFF, MERGEBUFF, elem_size);
|
get_merge_cost(rowid_compare_cost, num_keys_per_buffer * MERGEBUFF,
|
||||||
|
MERGEBUFF, elem_size);
|
||||||
|
|
||||||
// # of records in remaining buffers.
|
// # of records in remaining buffers.
|
||||||
last_n_elems+= num_remaining_buffs * num_keys_per_buffer;
|
last_n_elems+= num_remaining_buffs * num_keys_per_buffer;
|
||||||
|
|
||||||
// Cost of merge sort of remaining buffers.
|
// Cost of merge sort of remaining buffers.
|
||||||
total_cost+=
|
total_cost+=
|
||||||
get_merge_cost(last_n_elems, 1 + num_remaining_buffs, elem_size);
|
get_merge_cost(rowid_compare_cost, last_n_elems, 1 + num_remaining_buffs,
|
||||||
|
elem_size);
|
||||||
|
|
||||||
num_buffers= num_merge_calls;
|
num_buffers= num_merge_calls;
|
||||||
num_keys_per_buffer*= MERGEBUFF;
|
num_keys_per_buffer*= MERGEBUFF;
|
||||||
@@ -84,7 +86,8 @@ double get_merge_many_buffs_cost_fast(ha_rows num_rows,
|
|||||||
|
|
||||||
// Simulate final merge_buff call.
|
// Simulate final merge_buff call.
|
||||||
last_n_elems+= num_keys_per_buffer * num_buffers;
|
last_n_elems+= num_keys_per_buffer * num_buffers;
|
||||||
total_cost+= get_merge_cost(last_n_elems, 1 + num_buffers, elem_size);
|
total_cost+= get_merge_cost(rowid_compare_cost, last_n_elems, 1 + num_buffers,
|
||||||
|
elem_size);
|
||||||
return total_cost;
|
return total_cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ class Sort_param;
|
|||||||
See also comments get_merge_many_buffs_cost().
|
See also comments get_merge_many_buffs_cost().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double get_merge_many_buffs_cost_fast(ha_rows num_rows,
|
double get_merge_many_buffs_cost_fast(THD *thd, ha_rows num_rows,
|
||||||
ha_rows num_keys_per_buffer,
|
ha_rows num_keys_per_buffer,
|
||||||
uint elem_size);
|
uint elem_size);
|
||||||
|
|
||||||
|
@@ -12145,6 +12145,15 @@ ha_partition::can_convert_nocopy(const Field &field,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ha_partition::set_optimizer_costs(THD *thd)
|
||||||
|
{
|
||||||
|
handler::set_optimizer_costs(thd);
|
||||||
|
for (uint i= bitmap_get_first_set(&m_part_info->read_partitions);
|
||||||
|
i < m_tot_parts;
|
||||||
|
i= bitmap_get_next_set(&m_part_info->read_partitions, i))
|
||||||
|
m_file[i]->set_optimizer_costs(thd);
|
||||||
|
}
|
||||||
|
|
||||||
struct st_mysql_storage_engine partition_storage_engine=
|
struct st_mysql_storage_engine partition_storage_engine=
|
||||||
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
|
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
|
||||||
|
|
||||||
|
@@ -1637,5 +1637,6 @@ public:
|
|||||||
|
|
||||||
bool can_convert_nocopy(const Field &field,
|
bool can_convert_nocopy(const Field &field,
|
||||||
const Column_definition &new_field) const override;
|
const Column_definition &new_field) const override;
|
||||||
|
void set_optimizer_costs(THD *thd) override;
|
||||||
};
|
};
|
||||||
#endif /* HA_PARTITION_INCLUDED */
|
#endif /* HA_PARTITION_INCLUDED */
|
||||||
|
@@ -3249,7 +3249,7 @@ LEX_CSTRING *handler::engine_name()
|
|||||||
those key entries into the engine buffers.
|
those key entries into the engine buffers.
|
||||||
|
|
||||||
This function doesn't take in account into copying the key to record
|
This function doesn't take in account into copying the key to record
|
||||||
(KEY_COPY_COST) or comparing the key to the where clause (TIME_FOR_COMPARE)
|
(KEY_COPY_COST) or comparing the key to the where clause (WHERE_COST)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double handler::keyread_time(uint index, uint ranges, ha_rows rows)
|
double handler::keyread_time(uint index, uint ranges, ha_rows rows)
|
||||||
@@ -3261,7 +3261,8 @@ double handler::keyread_time(uint index, uint ranges, ha_rows rows)
|
|||||||
if (table->file->is_clustering_key(index))
|
if (table->file->is_clustering_key(index))
|
||||||
len= table->s->stored_rec_length;
|
len= table->s->stored_rec_length;
|
||||||
|
|
||||||
cost= ((double)rows*len/(stats.block_size+1)*INDEX_BLOCK_COPY_COST);
|
cost= ((double)rows*len/(stats.block_size+1) *
|
||||||
|
INDEX_BLOCK_COPY_COST(table->in_use));
|
||||||
/*
|
/*
|
||||||
We divide the cost with optimizer_cache_cost as ha_keyread_time()
|
We divide the cost with optimizer_cache_cost as ha_keyread_time()
|
||||||
and ha_key_scan_time() will multiply the result value with
|
and ha_key_scan_time() will multiply the result value with
|
||||||
@@ -3413,9 +3414,18 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
|
|||||||
else
|
else
|
||||||
dup_ref=ref+ALIGN_SIZE(ref_length);
|
dup_ref=ref+ALIGN_SIZE(ref_length);
|
||||||
cached_table_flags= table_flags();
|
cached_table_flags= table_flags();
|
||||||
}
|
|
||||||
|
/* Copy current optimizer costs. Needed in case clone() is used */
|
||||||
|
set_optimizer_costs(table->in_use);
|
||||||
|
DBUG_ASSERT(optimizer_key_copy_cost >= 0.0);
|
||||||
|
DBUG_ASSERT(optimizer_key_next_find_cost >= 0.0);
|
||||||
|
DBUG_ASSERT(optimizer_row_copy_cost >= 0.0);
|
||||||
|
DBUG_ASSERT(optimizer_where_cost >= 0.0);
|
||||||
|
DBUG_ASSERT(optimizer_key_cmp_cost >= 0.0);
|
||||||
reset_statistics();
|
reset_statistics();
|
||||||
|
}
|
||||||
internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE);
|
internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE);
|
||||||
|
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8755,3 +8765,30 @@ Table_scope_and_contents_source_st::fix_period_fields(THD *thd,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy common optimizer cost variables to the engine
|
||||||
|
|
||||||
|
This is needed to provide fast acccess to these variables during
|
||||||
|
optimization (as we refer to them multiple times).
|
||||||
|
|
||||||
|
The other option would be to access them from thd, but that
|
||||||
|
would require a function call (as we cannot access THD from
|
||||||
|
an inline handler function) and two extra memory accesses
|
||||||
|
for each variable.
|
||||||
|
|
||||||
|
index_block_copy_cost is not copied as it is used so seldom.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void handler::set_optimizer_costs(THD *thd)
|
||||||
|
{
|
||||||
|
optimizer_key_copy_cost= thd->variables.optimizer_key_copy_cost;
|
||||||
|
optimizer_key_next_find_cost=
|
||||||
|
thd->variables.optimizer_key_next_find_cost;
|
||||||
|
optimizer_row_copy_cost= thd->variables.optimizer_row_copy_cost;
|
||||||
|
optimizer_where_cost= thd->variables.optimizer_where_cost;
|
||||||
|
optimizer_key_cmp_cost= thd->variables.optimizer_key_cmp_cost;
|
||||||
|
set_optimizer_cache_cost(cache_hit_cost(thd->variables.
|
||||||
|
optimizer_cache_hit_ratio));
|
||||||
|
}
|
||||||
|
@@ -3225,6 +3225,10 @@ public:
|
|||||||
Updated from THD in open_tables()
|
Updated from THD in open_tables()
|
||||||
*/
|
*/
|
||||||
double optimizer_cache_cost;
|
double optimizer_cache_cost;
|
||||||
|
double optimizer_key_next_find_cost;
|
||||||
|
double optimizer_row_copy_cost, optimizer_key_copy_cost;
|
||||||
|
double optimizer_where_cost, optimizer_key_cmp_cost;
|
||||||
|
|
||||||
ha_copy_info copy_info;
|
ha_copy_info copy_info;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -3360,7 +3364,7 @@ public:
|
|||||||
ref_length(sizeof(my_off_t)),
|
ref_length(sizeof(my_off_t)),
|
||||||
ft_handler(0), inited(NONE), pre_inited(NONE),
|
ft_handler(0), inited(NONE), pre_inited(NONE),
|
||||||
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
|
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
|
||||||
optimizer_cache_cost((100-CACHE_HIT_RATIO)/100.0),
|
optimizer_cache_cost((100-DEFAULT_CACHE_HIT_RATIO)/100.0),
|
||||||
tracker(NULL),
|
tracker(NULL),
|
||||||
pushed_idx_cond(NULL),
|
pushed_idx_cond(NULL),
|
||||||
pushed_idx_cond_keyno(MAX_KEY),
|
pushed_idx_cond_keyno(MAX_KEY),
|
||||||
@@ -3624,7 +3628,7 @@ public:
|
|||||||
inline double ha_scan_and_compare_time(ha_rows records)
|
inline double ha_scan_and_compare_time(ha_rows records)
|
||||||
{
|
{
|
||||||
return (ha_scan_time() +
|
return (ha_scan_time() +
|
||||||
(double) records * (ROW_COPY_COST + 1/TIME_FOR_COMPARE));
|
(double) records * (ROW_COPY_COST + WHERE_COST));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual double avg_io_cost()
|
virtual double avg_io_cost()
|
||||||
@@ -3632,6 +3636,13 @@ public:
|
|||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void set_optimizer_costs(THD *thd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set cost for finding a row in the engine cache
|
||||||
|
This allows the handler to override the cost if there is no
|
||||||
|
caching of rows, like in heap or federatedx.
|
||||||
|
*/
|
||||||
virtual void set_optimizer_cache_cost(double cost)
|
virtual void set_optimizer_cache_cost(double cost)
|
||||||
{
|
{
|
||||||
optimizer_cache_cost= cost;
|
optimizer_cache_cost= cost;
|
||||||
@@ -3678,7 +3689,7 @@ public:
|
|||||||
inline double ha_read_and_compare_time(uint index, uint ranges, ha_rows rows)
|
inline double ha_read_and_compare_time(uint index, uint ranges, ha_rows rows)
|
||||||
{
|
{
|
||||||
return (ha_read_time(index, ranges, rows) +
|
return (ha_read_time(index, ranges, rows) +
|
||||||
rows2double(rows) * (ROW_COPY_COST + 1/TIME_FOR_COMPARE));
|
rows2double(rows) * (ROW_COPY_COST + WHERE_COST));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cost of reading a row with rowid */
|
/* Cost of reading a row with rowid */
|
||||||
@@ -3754,7 +3765,7 @@ public:
|
|||||||
inline double ha_key_scan_and_compare_time(uint index, ha_rows rows)
|
inline double ha_key_scan_and_compare_time(uint index, ha_rows rows)
|
||||||
{
|
{
|
||||||
return (ha_key_scan_time(index) +
|
return (ha_key_scan_time(index) +
|
||||||
(double) rows * (KEY_COPY_COST + 1/TIME_FOR_COMPARE));
|
(double) rows * (KEY_COPY_COST + WHERE_COST));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
|
virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
|
||||||
|
@@ -343,7 +343,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
|
|||||||
cost->cpu_cost= ha_read_time(keyno, 0, total_rows);
|
cost->cpu_cost= ha_read_time(keyno, 0, total_rows);
|
||||||
cost->copy_cost= rows2double(total_rows) * ROW_COPY_COST;
|
cost->copy_cost= rows2double(total_rows) * ROW_COPY_COST;
|
||||||
}
|
}
|
||||||
cost->comp_cost= (rows2double(total_rows) / TIME_FOR_COMPARE +
|
cost->comp_cost= (rows2double(total_rows) * WHERE_COST +
|
||||||
MULTI_RANGE_READ_SETUP_COST);
|
MULTI_RANGE_READ_SETUP_COST);
|
||||||
}
|
}
|
||||||
DBUG_PRINT("statistics",
|
DBUG_PRINT("statistics",
|
||||||
@@ -427,7 +427,8 @@ ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Same as above, but take into account copying the key to the upper level.
|
Same as above, but take into account copying the key to the upper
|
||||||
|
level.
|
||||||
*/
|
*/
|
||||||
cost->idx_cpu_cost= (keyread_time(keyno, 1, n_rows) +
|
cost->idx_cpu_cost= (keyread_time(keyno, 1, n_rows) +
|
||||||
(n_ranges-1) * range_lookup_cost);
|
(n_ranges-1) * range_lookup_cost);
|
||||||
@@ -440,7 +441,7 @@ ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
|
|||||||
cost->cpu_cost= read_time(keyno, n_ranges, n_rows);
|
cost->cpu_cost= read_time(keyno, n_ranges, n_rows);
|
||||||
cost->copy_cost= rows2double(n_rows) * ROW_COPY_COST;
|
cost->copy_cost= rows2double(n_rows) * ROW_COPY_COST;
|
||||||
}
|
}
|
||||||
cost->comp_cost= rows2double(n_rows) / TIME_FOR_COMPARE;
|
cost->comp_cost= rows2double(n_rows) * WHERE_COST;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2067,7 +2068,7 @@ void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost)
|
|||||||
{
|
{
|
||||||
get_sweep_read_cost(table, nrows, FALSE, cost);
|
get_sweep_read_cost(table, nrows, FALSE, cost);
|
||||||
/* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
|
/* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
|
||||||
double cmp_op= rows2double(nrows) * (1.0 / TIME_FOR_COMPARE_ROWID);
|
double cmp_op= rows2double(nrows) * ROWID_COMPARE_COST_THD(table->in_use);
|
||||||
if (cmp_op < 3)
|
if (cmp_op < 3)
|
||||||
cmp_op= 3;
|
cmp_op= 3;
|
||||||
cost->cpu_cost += cmp_op * log2(cmp_op);
|
cost->cpu_cost += cmp_op * log2(cmp_op);
|
||||||
|
@@ -5069,7 +5069,7 @@ static void dbug_print_singlepoint_range(SEL_ARG **start, uint num)
|
|||||||
get_sweep_read_cost()
|
get_sweep_read_cost()
|
||||||
param Parameter from test_quick_select
|
param Parameter from test_quick_select
|
||||||
records # of records to be retrieved
|
records # of records to be retrieved
|
||||||
add_time_for_compare If set, add cost of WHERE clause (TIME_FOR_COMPARE)
|
add_time_for_compare If set, add cost of WHERE clause (WHERE_COST)
|
||||||
RETURN
|
RETURN
|
||||||
cost of sweep
|
cost of sweep
|
||||||
*/
|
*/
|
||||||
@@ -5080,7 +5080,8 @@ static double get_sweep_read_cost(const PARAM *param, ha_rows records,
|
|||||||
DBUG_ENTER("get_sweep_read_cost");
|
DBUG_ENTER("get_sweep_read_cost");
|
||||||
#ifndef OLD_SWEEP_COST
|
#ifndef OLD_SWEEP_COST
|
||||||
double cost= (param->table->file->ha_rnd_pos_time(records) +
|
double cost= (param->table->file->ha_rnd_pos_time(records) +
|
||||||
(add_time_for_compare ? records / TIME_FOR_COMPARE : 0));
|
(add_time_for_compare ?
|
||||||
|
records * param->thd->variables.optimizer_where_cost : 0));
|
||||||
DBUG_PRINT("return", ("cost: %g", cost));
|
DBUG_PRINT("return", ("cost: %g", cost));
|
||||||
DBUG_RETURN(cost);
|
DBUG_RETURN(cost);
|
||||||
#else
|
#else
|
||||||
@@ -5132,7 +5133,7 @@ static double get_sweep_read_cost(const PARAM *param, ha_rows records,
|
|||||||
*/
|
*/
|
||||||
result= busy_blocks;
|
result= busy_blocks;
|
||||||
}
|
}
|
||||||
result+= rows2double(n_rows) * ROW_COPY_COST;
|
result+= rows2double(n_rows) * ROW_COPY_COST_THD(param->table->thd);
|
||||||
}
|
}
|
||||||
DBUG_PRINT("return",("cost: %g", result));
|
DBUG_PRINT("return",("cost: %g", result));
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
@@ -5345,8 +5346,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
|||||||
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
|
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
|
||||||
is done in QUICK_RANGE_SELECT::row_in_ranges)
|
is done in QUICK_RANGE_SELECT::row_in_ranges)
|
||||||
*/
|
*/
|
||||||
double rid_comp_cost= (rows2double(non_cpk_scan_records) /
|
double rid_comp_cost= (rows2double(non_cpk_scan_records) *
|
||||||
TIME_FOR_COMPARE_ROWID);
|
ROWID_COMPARE_COST_THD(param->thd));
|
||||||
imerge_cost+= rid_comp_cost;
|
imerge_cost+= rid_comp_cost;
|
||||||
trace_best_disjunct.add("cost_of_mapping_rowid_in_non_clustered_pk_scan",
|
trace_best_disjunct.add("cost_of_mapping_rowid_in_non_clustered_pk_scan",
|
||||||
rid_comp_cost);
|
rid_comp_cost);
|
||||||
@@ -5354,7 +5355,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
|||||||
|
|
||||||
/* Calculate cost(rowid_to_row_scan) */
|
/* Calculate cost(rowid_to_row_scan) */
|
||||||
{
|
{
|
||||||
/* imerge_cost already includes TIME_FOR_COMPARE */
|
/* imerge_cost already includes WHERE_COST */
|
||||||
double sweep_cost= get_sweep_read_cost(param, non_cpk_scan_records, 0);
|
double sweep_cost= get_sweep_read_cost(param, non_cpk_scan_records, 0);
|
||||||
imerge_cost+= sweep_cost;
|
imerge_cost+= sweep_cost;
|
||||||
trace_best_disjunct.
|
trace_best_disjunct.
|
||||||
@@ -5392,7 +5393,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
|||||||
param->imerge_cost_buff, (uint)non_cpk_scan_records,
|
param->imerge_cost_buff, (uint)non_cpk_scan_records,
|
||||||
param->table->file->ref_length,
|
param->table->file->ref_length,
|
||||||
(size_t)param->thd->variables.sortbuff_size,
|
(size_t)param->thd->variables.sortbuff_size,
|
||||||
TIME_FOR_COMPARE_ROWID,
|
ROWID_COMPARE_COST_THD(param->thd),
|
||||||
FALSE, NULL);
|
FALSE, NULL);
|
||||||
imerge_cost+= dup_removal_cost;
|
imerge_cost+= dup_removal_cost;
|
||||||
if (unlikely(trace_best_disjunct.trace_started()))
|
if (unlikely(trace_best_disjunct.trace_started()))
|
||||||
@@ -5506,8 +5507,8 @@ skip_to_ror_scan:
|
|||||||
|
|
||||||
double roru_total_cost;
|
double roru_total_cost;
|
||||||
roru_total_cost= (roru_index_costs +
|
roru_total_cost= (roru_index_costs +
|
||||||
rows2double(roru_total_records)*log((double)n_child_scans) /
|
rows2double(roru_total_records)*log((double)n_child_scans) *
|
||||||
(TIME_FOR_COMPARE_ROWID * M_LN2) +
|
ROWID_COMPARE_COST_THD(param->thd) / M_LN2 +
|
||||||
get_sweep_read_cost(param, roru_total_records, 0));
|
get_sweep_read_cost(param, roru_total_records, 0));
|
||||||
|
|
||||||
DBUG_PRINT("info", ("ROR-union: cost %g, %zu members",
|
DBUG_PRINT("info", ("ROR-union: cost %g, %zu members",
|
||||||
@@ -5663,7 +5664,7 @@ typedef struct st_common_index_intersect_info
|
|||||||
{
|
{
|
||||||
PARAM *param; /* context info for range optimizations */
|
PARAM *param; /* context info for range optimizations */
|
||||||
uint key_size; /* size of a ROWID element stored in Unique object */
|
uint key_size; /* size of a ROWID element stored in Unique object */
|
||||||
double compare_factor; /* 1/compare - cost to compare two ROWIDs */
|
double compare_factor; /* cost to compare two ROWIDs */
|
||||||
size_t max_memory_size; /* maximum space allowed for Unique objects */
|
size_t max_memory_size; /* maximum space allowed for Unique objects */
|
||||||
ha_rows table_cardinality; /* estimate of the number of records in table */
|
ha_rows table_cardinality; /* estimate of the number of records in table */
|
||||||
double cutoff_cost; /* discard index intersects with greater costs */
|
double cutoff_cost; /* discard index intersects with greater costs */
|
||||||
@@ -5877,7 +5878,7 @@ bool prepare_search_best_index_intersect(PARAM *param,
|
|||||||
|
|
||||||
common->param= param;
|
common->param= param;
|
||||||
common->key_size= table->file->ref_length;
|
common->key_size= table->file->ref_length;
|
||||||
common->compare_factor= TIME_FOR_COMPARE_ROWID;
|
common->compare_factor= ROWID_COMPARE_COST_THD(param->thd);
|
||||||
common->max_memory_size= (size_t)param->thd->variables.sortbuff_size;
|
common->max_memory_size= (size_t)param->thd->variables.sortbuff_size;
|
||||||
common->cutoff_cost= cutoff_cost;
|
common->cutoff_cost= cutoff_cost;
|
||||||
common->cpk_scan= NULL;
|
common->cpk_scan= NULL;
|
||||||
@@ -5934,7 +5935,7 @@ bool prepare_search_best_index_intersect(PARAM *param,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cost= table->opt_range[(*index_scan)->keynr].index_only_fetch_cost();
|
cost= table->opt_range[(*index_scan)->keynr].index_only_fetch_cost(thd);
|
||||||
|
|
||||||
idx_scan.add("cost", cost);
|
idx_scan.add("cost", cost);
|
||||||
|
|
||||||
@@ -6298,8 +6299,8 @@ double get_cpk_filter_cost(ha_rows filtered_records,
|
|||||||
INDEX_SCAN_INFO *cpk_scan,
|
INDEX_SCAN_INFO *cpk_scan,
|
||||||
double compare_factor)
|
double compare_factor)
|
||||||
{
|
{
|
||||||
return log((double) (cpk_scan->range_count+1)) / (compare_factor * M_LN2) *
|
return (log((double) (cpk_scan->range_count+1)) * compare_factor / M_LN2 *
|
||||||
filtered_records;
|
filtered_records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7054,11 +7055,11 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
CPK scan is used to filter out rows. We apply filtering for
|
CPK scan is used to filter out rows. We apply filtering for
|
||||||
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
|
each record of every scan. Assuming ROWID_COMPARE_COST
|
||||||
per check this gives us:
|
per check this gives us:
|
||||||
*/
|
*/
|
||||||
const double idx_cost= (rows2double(info->index_records) /
|
const double idx_cost= (rows2double(info->index_records) *
|
||||||
TIME_FOR_COMPARE_ROWID);
|
ROWID_COMPARE_COST_THD(info->param->thd));
|
||||||
info->index_scan_costs+= idx_cost;
|
info->index_scan_costs+= idx_cost;
|
||||||
trace_costs->add("index_scan_cost", idx_cost);
|
trace_costs->add("index_scan_cost", idx_cost);
|
||||||
}
|
}
|
||||||
@@ -7367,7 +7368,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
|
|||||||
Adjust row count and add the cost of comparing the final rows to the
|
Adjust row count and add the cost of comparing the final rows to the
|
||||||
WHERE clause
|
WHERE clause
|
||||||
*/
|
*/
|
||||||
cmp_cost= intersect_best->out_rows/TIME_FOR_COMPARE;
|
cmp_cost= intersect_best->out_rows * thd->variables.optimizer_where_cost;
|
||||||
|
|
||||||
/* Ok, return ROR-intersect plan if we have found one */
|
/* Ok, return ROR-intersect plan if we have found one */
|
||||||
TRP_ROR_INTERSECT *trp= NULL;
|
TRP_ROR_INTERSECT *trp= NULL;
|
||||||
@@ -7536,9 +7537,9 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
|
|||||||
tree->ror_scans, ror_scan_mark););
|
tree->ror_scans, ror_scan_mark););
|
||||||
|
|
||||||
/* Add priority queue use cost. */
|
/* Add priority queue use cost. */
|
||||||
total_cost += rows2double(records)*
|
total_cost += (rows2double(records) *
|
||||||
log((double)(ror_scan_mark - tree->ror_scans)) /
|
log((double)(ror_scan_mark - tree->ror_scans)) *
|
||||||
(TIME_FOR_COMPARE_ROWID * M_LN2);
|
ROWID_COMPARE_COST_THD(param->thd) / M_LN2);
|
||||||
DBUG_PRINT("info", ("Covering ROR-intersect full cost: %g", total_cost));
|
DBUG_PRINT("info", ("Covering ROR-intersect full cost: %g", total_cost));
|
||||||
|
|
||||||
/* TODO: Add TIME_FOR_COMPARE cost to total_cost */
|
/* TODO: Add TIME_FOR_COMPARE cost to total_cost */
|
||||||
@@ -15093,7 +15094,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
|
|||||||
group. To make the CPU cost reflect this, we estimate the CPU cost
|
group. To make the CPU cost reflect this, we estimate the CPU cost
|
||||||
as the sum of:
|
as the sum of:
|
||||||
1. Cost for evaluating the condition for each num_group
|
1. Cost for evaluating the condition for each num_group
|
||||||
(1/TIME_FOR_COMPARE_IDX) (similarly as for index scan).
|
KEY_COMPARE_COST (similarly as for index scan).
|
||||||
2. Cost for navigating the index structure (assuming a b-tree).
|
2. Cost for navigating the index structure (assuming a b-tree).
|
||||||
Note: We only add the cost for one index comparision per block. For a
|
Note: We only add the cost for one index comparision per block. For a
|
||||||
b-tree the number of comparisons will be larger. However the cost
|
b-tree the number of comparisons will be larger. However the cost
|
||||||
@@ -15102,13 +15103,15 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
|
|||||||
TODO: This cost should be provided by the storage engine.
|
TODO: This cost should be provided by the storage engine.
|
||||||
3. Cost for comparing the row with the where clause
|
3. Cost for comparing the row with the where clause
|
||||||
*/
|
*/
|
||||||
|
const THD *thd= table->in_use;
|
||||||
const double tree_traversal_cost=
|
const double tree_traversal_cost=
|
||||||
ceil(log(static_cast<double>(table_records))/
|
ceil(log(static_cast<double>(table_records))/
|
||||||
log(static_cast<double>(keys_per_block))) *
|
log(static_cast<double>(keys_per_block))) *
|
||||||
1/(TIME_FOR_COMPARE_IDX);
|
thd->variables.optimizer_key_cmp_cost;
|
||||||
|
|
||||||
const double cpu_cost= (num_groups *
|
const double cpu_cost= (num_groups *
|
||||||
(tree_traversal_cost + 1/TIME_FOR_COMPARE));
|
(tree_traversal_cost +
|
||||||
|
thd->variables.optimizer_where_cost));
|
||||||
|
|
||||||
*read_cost= io_cost + cpu_cost;
|
*read_cost= io_cost + cpu_cost;
|
||||||
*records= num_groups;
|
*records= num_groups;
|
||||||
|
@@ -1449,6 +1449,7 @@ void get_delayed_table_estimates(TABLE *table,
|
|||||||
Item_in_subselect *item= table->pos_in_table_list->jtbm_subselect;
|
Item_in_subselect *item= table->pos_in_table_list->jtbm_subselect;
|
||||||
Table_function_json_table *table_function=
|
Table_function_json_table *table_function=
|
||||||
table->pos_in_table_list->table_function;
|
table->pos_in_table_list->table_function;
|
||||||
|
handler *file= table->file;
|
||||||
|
|
||||||
if (table_function)
|
if (table_function)
|
||||||
{
|
{
|
||||||
@@ -1468,9 +1469,10 @@ void get_delayed_table_estimates(TABLE *table,
|
|||||||
/* Calculate cost of scanning the temptable */
|
/* Calculate cost of scanning the temptable */
|
||||||
double data_size= COST_MULT(item->jtbm_record_count,
|
double data_size= COST_MULT(item->jtbm_record_count,
|
||||||
hash_sj_engine->tmp_table->s->reclength);
|
hash_sj_engine->tmp_table->s->reclength);
|
||||||
|
|
||||||
/* Do like in handler::ha_scan_and_compare_time, but ignore the where cost */
|
/* Do like in handler::ha_scan_and_compare_time, but ignore the where cost */
|
||||||
*scan_time= ((data_size/table->file->stats.block_size+2) *
|
*scan_time= ((data_size/table->file->stats.block_size+2) *
|
||||||
table->file->avg_io_cost()) + *out_rows * ROW_COPY_COST;
|
table->file->avg_io_cost()) + *out_rows * file->ROW_COPY_COST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -20,14 +20,6 @@
|
|||||||
|
|
||||||
/* This file includes costs variables used by the optimizer */
|
/* This file includes costs variables used by the optimizer */
|
||||||
|
|
||||||
/**
|
|
||||||
The following is used to decide if MariaDB should use table scanning
|
|
||||||
instead of reading with keys. The number says how many evaluation of the
|
|
||||||
WHERE clause is comparable to reading one extra row from a table.
|
|
||||||
*/
|
|
||||||
#define TIME_FOR_COMPARE 5.0 // 5 WHERE compares == one read
|
|
||||||
#define TIME_FOR_COMPARE_IDX 20.0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The table/index cache hit ratio in %. 0 means that a searched for key or row
|
The table/index cache hit ratio in %. 0 means that a searched for key or row
|
||||||
will never be in the cache while 100 means it always in the cache.
|
will never be in the cache while 100 means it always in the cache.
|
||||||
@@ -43,7 +35,7 @@
|
|||||||
|
|
||||||
Note that avg_io_cost() is multipled with this constant!
|
Note that avg_io_cost() is multipled with this constant!
|
||||||
*/
|
*/
|
||||||
#define CACHE_HIT_RATIO 50
|
#define DEFAULT_CACHE_HIT_RATIO 50
|
||||||
|
|
||||||
/* Convert ratio to cost */
|
/* Convert ratio to cost */
|
||||||
|
|
||||||
@@ -53,14 +45,23 @@ static inline double cache_hit_cost(uint ratio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cost of finding and copying keys of a total length of 'blocksize'
|
Base cost for finding keys and rows from the engine is 1.0
|
||||||
used in handler::keyread_time()
|
All other costs should be proportional to these
|
||||||
*/
|
*/
|
||||||
#define INDEX_BLOCK_COPY_COST ((double) 1 / 5.0)
|
|
||||||
/* Cost for finding the first key in a key scan */
|
/* Cost for finding the first key in a key scan */
|
||||||
#define KEY_LOOKUP_COST ((double) 1.0)
|
#define KEY_LOOKUP_COST ((double) 1.0)
|
||||||
/* Cost of finding a key from a row_ID (not used for clustered keys) */
|
/* Cost of finding a key from a row_ID (not used for clustered keys) */
|
||||||
#define ROW_LOOKUP_COST ((double) 1.0)
|
#define ROW_LOOKUP_COST ((double) 1.0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cost of finding and copying keys from the storage engine index cache to
|
||||||
|
an internal cache as part of an index scan.
|
||||||
|
Used in handler::keyread_time()
|
||||||
|
*/
|
||||||
|
#define DEFAULT_INDEX_BLOCK_COPY_COST ((double) 1 / 5.0)
|
||||||
|
#define INDEX_BLOCK_COPY_COST(THD) ((THD)->variables.optimizer_index_block_copy_cost)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cost of finding the next row during table scan and copying it to
|
Cost of finding the next row during table scan and copying it to
|
||||||
'table->record'.
|
'table->record'.
|
||||||
@@ -70,7 +71,10 @@ static inline double cache_hit_cost(uint ratio)
|
|||||||
too big then MariaDB will used key lookup even when table scan is
|
too big then MariaDB will used key lookup even when table scan is
|
||||||
better.
|
better.
|
||||||
*/
|
*/
|
||||||
#define ROW_COPY_COST ((double) 1.0 / 20.0)
|
#define DEFAULT_ROW_COPY_COST ((double) 1.0 / 20.0)
|
||||||
|
#define ROW_COPY_COST optimizer_row_copy_cost
|
||||||
|
#define ROW_COPY_COST_THD(THD) ((THD)->variables.optimizer_row_copy_cost)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cost of finding the next key during index scan and copying it to
|
Cost of finding the next key during index scan and copying it to
|
||||||
'table->record'
|
'table->record'
|
||||||
@@ -79,13 +83,40 @@ static inline double cache_hit_cost(uint ratio)
|
|||||||
as with table scans there are no key read (KEY_LOOKUP_COST) and
|
as with table scans there are no key read (KEY_LOOKUP_COST) and
|
||||||
fewer disk reads.
|
fewer disk reads.
|
||||||
*/
|
*/
|
||||||
#define KEY_COPY_COST ((double) 1.0 / 40.0)
|
#define DEFAULT_KEY_COPY_COST ((double) 1.0 / 40.0)
|
||||||
|
#define KEY_COPY_COST optimizer_key_copy_cost
|
||||||
|
#define KEY_COPY_COST_THD(THD) ((THD)->variables.optimizer_key_copy_cost)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cost of finding the next index entry and checking it against filter
|
Cost of finding the next index entry and checking it against filter
|
||||||
This cost is very low as it's done inside the storage engine.
|
This cost is very low as it's done inside the storage engine.
|
||||||
Should be smaller than KEY_COPY_COST.
|
Should be smaller than KEY_COPY_COST.
|
||||||
*/
|
*/
|
||||||
#define KEY_NEXT_FIND_COST ((double) 1.0 / 80.0)
|
#define DEFAULT_KEY_NEXT_FIND_COST ((double) 1.0 / 80.0)
|
||||||
|
#define KEY_NEXT_FIND_COST optimizer_next_find_cost
|
||||||
|
|
||||||
|
/**
|
||||||
|
The following is used to decide if MariaDB should use table scanning
|
||||||
|
instead of reading with keys. The number says how many evaluation of the
|
||||||
|
WHERE clause is comparable to reading one extra row from a table.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_WHERE_COST (1 / 5.0)
|
||||||
|
#define WHERE_COST optimizer_where_cost
|
||||||
|
#define WHERE_COST_THD(THD) ((THD)->variables.optimizer_where_cost)
|
||||||
|
|
||||||
|
#define DEFAULT_KEY_COMPARE_COST (1 / 20.0)
|
||||||
|
#define KEY_COMPARE_COST optimizer_key_cmp_cost
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cost of comparing two rowids. This is set relative to KEY_COMPARE_COST
|
||||||
|
This is usally just a memcmp!
|
||||||
|
*/
|
||||||
|
#define ROWID_COMPARE_COST KEY_COMPARE_COST/10.0
|
||||||
|
#define ROWID_COMPARE_COST_THD(THD) ((THD)->variables.KEY_COMPARE_COST / 10.0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup cost for different operations
|
||||||
|
*/
|
||||||
|
|
||||||
/* Extra cost for doing a range scan. Used to prefer 'ref' over range */
|
/* Extra cost for doing a range scan. Used to prefer 'ref' over range */
|
||||||
#define MULTI_RANGE_READ_SETUP_COST (double) (1.0 / 50.0)
|
#define MULTI_RANGE_READ_SETUP_COST (double) (1.0 / 50.0)
|
||||||
@@ -105,12 +136,6 @@ static inline double cache_hit_cost(uint ratio)
|
|||||||
*/
|
*/
|
||||||
#define MIN_ROWS_AFTER_FILTERING 1.0
|
#define MIN_ROWS_AFTER_FILTERING 1.0
|
||||||
|
|
||||||
/**
|
|
||||||
Number of comparisons of table rowids equivalent to reading one row from a
|
|
||||||
table.
|
|
||||||
*/
|
|
||||||
#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*100)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
cost1 is better that cost2 only if cost1 + COST_EPS < cost2
|
cost1 is better that cost2 only if cost1 + COST_EPS < cost2
|
||||||
The main purpose of this is to ensure we use the first index or plan
|
The main purpose of this is to ensure we use the first index or plan
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
#include "opt_trace.h"
|
#include "opt_trace.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
KEY_NEXT_FIND_COST below is the cost of finding the next possible key
|
key_next_find_cost below is the cost of finding the next possible key
|
||||||
and calling handler_rowid_filter_check() to check it against the filter
|
and calling handler_rowid_filter_check() to check it against the filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ lookup_cost(Rowid_filter_container_type cont_type)
|
|||||||
{
|
{
|
||||||
switch (cont_type) {
|
switch (cont_type) {
|
||||||
case SORTED_ARRAY_CONTAINER:
|
case SORTED_ARRAY_CONTAINER:
|
||||||
return log(est_elements)*0.01+KEY_NEXT_FIND_COST;
|
return log(est_elements)*0.01+key_next_find_cost;
|
||||||
default:
|
default:
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -51,7 +51,7 @@ double Range_rowid_filter_cost_info::
|
|||||||
avg_access_and_eval_gain_per_row(Rowid_filter_container_type cont_type,
|
avg_access_and_eval_gain_per_row(Rowid_filter_container_type cont_type,
|
||||||
double cost_of_row_fetch)
|
double cost_of_row_fetch)
|
||||||
{
|
{
|
||||||
return (cost_of_row_fetch+1.0/TIME_FOR_COMPARE) * (1 - selectivity) -
|
return (cost_of_row_fetch + where_cost) * (1 - selectivity) -
|
||||||
lookup_cost(cont_type);
|
lookup_cost(cont_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +125,8 @@ void Range_rowid_filter_cost_info::init(Rowid_filter_container_type cont_type,
|
|||||||
key_no= idx;
|
key_no= idx;
|
||||||
est_elements= (ulonglong) table->opt_range[key_no].rows;
|
est_elements= (ulonglong) table->opt_range[key_no].rows;
|
||||||
cost_of_building_range_filter= build_cost(container_type);
|
cost_of_building_range_filter= build_cost(container_type);
|
||||||
|
where_cost= tab->in_use->variables.optimizer_where_cost;
|
||||||
|
key_next_find_cost= tab->in_use->variables.optimizer_key_next_find_cost;
|
||||||
selectivity= est_elements/((double) table->stat_records());
|
selectivity= est_elements/((double) table->stat_records());
|
||||||
gain= avg_access_and_eval_gain_per_row(container_type,
|
gain= avg_access_and_eval_gain_per_row(container_type,
|
||||||
tab->file->optimizer_cache_cost);
|
tab->file->optimizer_cache_cost);
|
||||||
@@ -147,7 +149,7 @@ Range_rowid_filter_cost_info::build_cost(Rowid_filter_container_type cont_type)
|
|||||||
double cost;
|
double cost;
|
||||||
DBUG_ASSERT(table->opt_range_keys.is_set(key_no));
|
DBUG_ASSERT(table->opt_range_keys.is_set(key_no));
|
||||||
|
|
||||||
cost= table->opt_range[key_no].index_only_fetch_cost();
|
cost= table->opt_range[key_no].index_only_fetch_cost(table->in_use);
|
||||||
|
|
||||||
switch (cont_type) {
|
switch (cont_type) {
|
||||||
|
|
||||||
@@ -523,7 +525,8 @@ TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no,
|
|||||||
cost_of_rejected_rows= index_only_cost * (1 - filter->selectivity);
|
cost_of_rejected_rows= index_only_cost * (1 - filter->selectivity);
|
||||||
new_cost= (cost_of_accepted_rows + cost_of_rejected_rows +
|
new_cost= (cost_of_accepted_rows + cost_of_rejected_rows +
|
||||||
records * filter->lookup_cost());
|
records * filter->lookup_cost());
|
||||||
new_total_cost= ((new_cost + new_records/TIME_FOR_COMPARE) * prev_records +
|
new_total_cost= ((new_cost + new_records *
|
||||||
|
in_use->variables.optimizer_where_cost) * prev_records +
|
||||||
filter->get_setup_cost());
|
filter->get_setup_cost());
|
||||||
|
|
||||||
if (best_filter_gain > new_total_cost)
|
if (best_filter_gain > new_total_cost)
|
||||||
|
@@ -406,6 +406,7 @@ class Range_rowid_filter_cost_info final: public Sql_alloc
|
|||||||
/* The index whose range scan would be used to build the range filter */
|
/* The index whose range scan would be used to build the range filter */
|
||||||
uint key_no;
|
uint key_no;
|
||||||
double cost_of_building_range_filter;
|
double cost_of_building_range_filter;
|
||||||
|
double where_cost, key_next_find_cost;
|
||||||
/*
|
/*
|
||||||
(gain*row_combinations)-cost_of_building_range_filter yields the gain of
|
(gain*row_combinations)-cost_of_building_range_filter yields the gain of
|
||||||
the filter for 'row_combinations' key tuples of the index key_no
|
the filter for 'row_combinations' key tuples of the index key_no
|
||||||
@@ -466,7 +467,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline double get_cmp_gain(double row_combinations)
|
inline double get_cmp_gain(double row_combinations)
|
||||||
{
|
{
|
||||||
return row_combinations * (1 - selectivity) / TIME_FOR_COMPARE;
|
return (row_combinations * (1 - selectivity) * where_cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rowid_filter_container *create_container();
|
Rowid_filter_container *create_container();
|
||||||
|
@@ -692,6 +692,10 @@ typedef struct system_variables
|
|||||||
ulonglong slave_skip_counter;
|
ulonglong slave_skip_counter;
|
||||||
ulonglong max_relay_log_size;
|
ulonglong max_relay_log_size;
|
||||||
|
|
||||||
|
double optimizer_index_block_copy_cost, optimizer_key_next_find_cost;
|
||||||
|
double optimizer_row_copy_cost, optimizer_key_copy_cost;
|
||||||
|
double optimizer_where_cost, optimizer_key_cmp_cost;
|
||||||
|
|
||||||
ha_rows select_limit;
|
ha_rows select_limit;
|
||||||
ha_rows max_join_size;
|
ha_rows max_join_size;
|
||||||
ha_rows expensive_subquery_limit;
|
ha_rows expensive_subquery_limit;
|
||||||
@@ -776,7 +780,7 @@ typedef struct system_variables
|
|||||||
|
|
||||||
uint group_concat_max_len;
|
uint group_concat_max_len;
|
||||||
uint eq_range_index_dive_limit;
|
uint eq_range_index_dive_limit;
|
||||||
uint optimizer_cache_hit_ratio;
|
uint optimizer_cache_hit_ratio; // Stored in handler::optimizer_cache_cost
|
||||||
int max_user_connections;
|
int max_user_connections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -7825,7 +7825,7 @@ static double matching_candidates_in_table(JOIN_TAB *s,
|
|||||||
KEY_COPY_COST as for filtering there is no copying of not accepted
|
KEY_COPY_COST as for filtering there is no copying of not accepted
|
||||||
keys.
|
keys.
|
||||||
|
|
||||||
TIME_FOR_COMPARE cost is not added to any result.
|
WHERE_COST cost is not added to any result.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
INDEX_READ_COST cost_for_index_read(const THD *thd, const TABLE *table,
|
INDEX_READ_COST cost_for_index_read(const THD *thd, const TABLE *table,
|
||||||
@@ -7850,14 +7850,14 @@ INDEX_READ_COST cost_for_index_read(const THD *thd, const TABLE *table,
|
|||||||
records to compute the record copy cost.
|
records to compute the record copy cost.
|
||||||
*/
|
*/
|
||||||
cost.read_cost= (cost.index_only_cost +
|
cost.read_cost= (cost.index_only_cost +
|
||||||
rows2double(records) * ROW_COPY_COST);
|
rows2double(records) * ROW_COPY_COST_THD(thd));
|
||||||
}
|
}
|
||||||
else if (table->covering_keys.is_set(key) && !table->no_keyread)
|
else if (table->covering_keys.is_set(key) && !table->no_keyread)
|
||||||
{
|
{
|
||||||
cost.index_only_cost= file->ha_keyread_time(key, 1, rows_adjusted);
|
cost.index_only_cost= file->ha_keyread_time(key, 1, rows_adjusted);
|
||||||
/* Same computation as in ha_keyread_and_copy_time() */
|
/* Same computation as in ha_keyread_and_copy_time() */
|
||||||
cost.read_cost= (cost.index_only_cost +
|
cost.read_cost= (cost.index_only_cost +
|
||||||
rows2double(records) * KEY_COPY_COST);
|
rows2double(records) * KEY_COPY_COST_THD(thd));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -7868,7 +7868,7 @@ INDEX_READ_COST cost_for_index_read(const THD *thd, const TABLE *table,
|
|||||||
*/
|
*/
|
||||||
cost.read_cost= (cost.index_only_cost +
|
cost.read_cost= (cost.index_only_cost +
|
||||||
file->ha_read_time(key, 0, rows_adjusted) +
|
file->ha_read_time(key, 0, rows_adjusted) +
|
||||||
rows2double(records) * ROW_COPY_COST);
|
rows2double(records) * ROW_COPY_COST_THD(thd));
|
||||||
}
|
}
|
||||||
DBUG_PRINT("statistics", ("index_cost: %.3f full_cost: %.3f",
|
DBUG_PRINT("statistics", ("index_cost: %.3f full_cost: %.3f",
|
||||||
cost.index_only_cost, cost.read_cost));
|
cost.index_only_cost, cost.read_cost));
|
||||||
@@ -7882,7 +7882,7 @@ INDEX_READ_COST cost_for_index_read(const THD *thd, const TABLE *table,
|
|||||||
@param thd Thread handler
|
@param thd Thread handler
|
||||||
@param table Table
|
@param table Table
|
||||||
@param cost Pointer to cost for *records_arg rows, not including
|
@param cost Pointer to cost for *records_arg rows, not including
|
||||||
TIME_FOR_COMPARE cost.
|
WHERE_COST cost.
|
||||||
Will be updated to new cost if filter is used.
|
Will be updated to new cost if filter is used.
|
||||||
@param records_arg Pointer to number of records for the current key.
|
@param records_arg Pointer to number of records for the current key.
|
||||||
Will be updated to records after filter, if filter is
|
Will be updated to records after filter, if filter is
|
||||||
@@ -7940,11 +7940,11 @@ apply_filter(THD *thd, TABLE *table, double *cost, double *records_arg,
|
|||||||
ranges * KEY_LOOKUP_COST * io_cost *
|
ranges * KEY_LOOKUP_COST * io_cost *
|
||||||
table->file->optimizer_cache_cost) +
|
table->file->optimizer_cache_cost) +
|
||||||
cost_of_rejected_rows + filter_lookup_cost);
|
cost_of_rejected_rows + filter_lookup_cost);
|
||||||
new_total_cost= ((new_cost + new_records/TIME_FOR_COMPARE) * prev_records +
|
new_total_cost= ((new_cost + new_records * WHERE_COST_THD(thd)) *
|
||||||
filter_startup_cost);
|
prev_records + filter_startup_cost);
|
||||||
|
|
||||||
DBUG_ASSERT(new_cost >= 0 && new_records >= 0);
|
DBUG_ASSERT(new_cost >= 0 && new_records >= 0);
|
||||||
use_filter= ((*cost + records/TIME_FOR_COMPARE) * prev_records >
|
use_filter= ((*cost + records * WHERE_COST_THD(thd)) * prev_records >
|
||||||
new_total_cost);
|
new_total_cost);
|
||||||
|
|
||||||
if (unlikely(thd->trace_started()))
|
if (unlikely(thd->trace_started()))
|
||||||
@@ -8638,7 +8638,7 @@ best_access_path(JOIN *join,
|
|||||||
tmp, index_only_cost,
|
tmp, index_only_cost,
|
||||||
1, record_count);
|
1, record_count);
|
||||||
}
|
}
|
||||||
tmp= COST_ADD(tmp, records_after_filter/TIME_FOR_COMPARE);
|
tmp= COST_ADD(tmp, records_after_filter * WHERE_COST_THD(thd));
|
||||||
tmp= COST_MULT(tmp, record_count);
|
tmp= COST_MULT(tmp, record_count);
|
||||||
tmp= COST_ADD(tmp, startup_cost);
|
tmp= COST_ADD(tmp, startup_cost);
|
||||||
if (unlikely(trace_access_idx.trace_started()))
|
if (unlikely(trace_access_idx.trace_started()))
|
||||||
@@ -8753,7 +8753,8 @@ best_access_path(JOIN *join,
|
|||||||
We assume here that, thanks to the hash, we don't have to compare all
|
We assume here that, thanks to the hash, we don't have to compare all
|
||||||
row combinations, only a HASH_FANOUT (10%) rows in the cache.
|
row combinations, only a HASH_FANOUT (10%) rows in the cache.
|
||||||
*/
|
*/
|
||||||
cmp_time= (rnd_records * record_count * HASH_FANOUT / TIME_FOR_COMPARE);
|
cmp_time= (rnd_records * record_count * HASH_FANOUT *
|
||||||
|
WHERE_COST_THD(thd));
|
||||||
tmp= COST_ADD(tmp, cmp_time);
|
tmp= COST_ADD(tmp, cmp_time);
|
||||||
|
|
||||||
best_cost= tmp;
|
best_cost= tmp;
|
||||||
@@ -8840,7 +8841,7 @@ best_access_path(JOIN *join,
|
|||||||
- skip rows which does not satisfy WHERE constraints
|
- skip rows which does not satisfy WHERE constraints
|
||||||
|
|
||||||
Note that s->quick->read_time includes the cost of comparing
|
Note that s->quick->read_time includes the cost of comparing
|
||||||
the row with the where clause (TIME_FOR_COMPARE)
|
the row with the where clause (WHERE_COST)
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
We take into account possible use of join cache for ALL/index
|
We take into account possible use of join cache for ALL/index
|
||||||
@@ -8889,8 +8890,9 @@ best_access_path(JOIN *join,
|
|||||||
if (filter)
|
if (filter)
|
||||||
{
|
{
|
||||||
tmp= filter_cost;
|
tmp= filter_cost;
|
||||||
/* Filter returns cost without TIME_FOR_COMPARE */
|
/* Filter returns cost without WHERE_COST */
|
||||||
tmp= COST_ADD(tmp, records_after_filter / TIME_FOR_COMPARE);
|
tmp= COST_ADD(tmp, records_after_filter *
|
||||||
|
WHERE_COST_THD(thd));
|
||||||
tmp= COST_MULT(tmp, record_count);
|
tmp= COST_MULT(tmp, record_count);
|
||||||
tmp= COST_ADD(tmp, startup_cost);
|
tmp= COST_ADD(tmp, startup_cost);
|
||||||
startup_cost= 0; // Avoid adding it later
|
startup_cost= 0; // Avoid adding it later
|
||||||
@@ -8927,7 +8929,7 @@ best_access_path(JOIN *join,
|
|||||||
type= JT_NEXT;
|
type= JT_NEXT;
|
||||||
tmp= cost.read_cost;
|
tmp= cost.read_cost;
|
||||||
/* Calculate cost of checking the attached WHERE */
|
/* Calculate cost of checking the attached WHERE */
|
||||||
tmp= COST_ADD(cost.read_cost, s->records / TIME_FOR_COMPARE);
|
tmp= COST_ADD(cost.read_cost, s->records * WHERE_COST_THD(thd));
|
||||||
}
|
}
|
||||||
else // table scan
|
else // table scan
|
||||||
{
|
{
|
||||||
@@ -8979,8 +8981,8 @@ best_access_path(JOIN *join,
|
|||||||
row.
|
row.
|
||||||
*/
|
*/
|
||||||
cmp_time= (rnd_records * record_count *
|
cmp_time= (rnd_records * record_count *
|
||||||
(ROW_COPY_COST * (idx - join->const_tables) +
|
(ROW_COPY_COST_THD(thd) * (idx - join->const_tables) +
|
||||||
1 / TIME_FOR_COMPARE));
|
WHERE_COST_THD(thd)));
|
||||||
tmp= COST_ADD(tmp, cmp_time);
|
tmp= COST_ADD(tmp, cmp_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14848,7 +14850,8 @@ void JOIN_TAB::cleanup()
|
|||||||
|
|
||||||
void JOIN_TAB::estimate_scan_time()
|
void JOIN_TAB::estimate_scan_time()
|
||||||
{
|
{
|
||||||
double copy_cost= ROW_COPY_COST;
|
THD *thd= join->thd;
|
||||||
|
double copy_cost= ROW_COPY_COST_THD(thd);
|
||||||
|
|
||||||
cached_covering_key= MAX_KEY;
|
cached_covering_key= MAX_KEY;
|
||||||
if (table->is_created())
|
if (table->is_created())
|
||||||
@@ -14873,7 +14876,7 @@ void JOIN_TAB::estimate_scan_time()
|
|||||||
{
|
{
|
||||||
cached_covering_key= find_shortest_key(table, &table->covering_keys);
|
cached_covering_key= find_shortest_key(table, &table->covering_keys);
|
||||||
read_time= table->file->ha_key_scan_time(cached_covering_key);
|
read_time= table->file->ha_key_scan_time(cached_covering_key);
|
||||||
copy_cost= KEY_COPY_COST;
|
copy_cost= KEY_COPY_COST_THD(thd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
read_time= table->file->ha_scan_time();
|
read_time= table->file->ha_scan_time();
|
||||||
@@ -14888,7 +14891,7 @@ void JOIN_TAB::estimate_scan_time()
|
|||||||
found_records= records;
|
found_records= records;
|
||||||
cached_scan_time= read_time;
|
cached_scan_time= read_time;
|
||||||
cached_scan_and_compare_time= (read_time + records *
|
cached_scan_and_compare_time= (read_time + records *
|
||||||
(copy_cost + 1/TIME_FOR_COMPARE));
|
(copy_cost + WHERE_COST_THD(thd)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -29967,7 +29970,7 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab,
|
|||||||
best_cost *= rows_limit_for_quick / best_rows;
|
best_cost *= rows_limit_for_quick / best_rows;
|
||||||
best_rows = rows_limit_for_quick;
|
best_rows = rows_limit_for_quick;
|
||||||
}
|
}
|
||||||
*read_time= best_cost + best_rows/TIME_FOR_COMPARE;
|
*read_time= best_cost + best_rows * WHERE_COST_THD(table->in_use);
|
||||||
*read_rows= best_rows;
|
*read_rows= best_rows;
|
||||||
res= true;
|
res= true;
|
||||||
}
|
}
|
||||||
@@ -30280,7 +30283,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
|
|||||||
(ha_rows) tab->worst_seeks :
|
(ha_rows) tab->worst_seeks :
|
||||||
HA_ROWS_MAX);
|
HA_ROWS_MAX);
|
||||||
index_scan_time= (cost.read_cost +
|
index_scan_time= (cost.read_cost +
|
||||||
select_limit / TIME_FOR_COMPARE);
|
select_limit * WHERE_COST_THD(thd));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
|
@@ -6968,7 +6968,8 @@ static Sys_var_uint Sys_in_subquery_conversion_threshold(
|
|||||||
"IN predicate that triggers its conversion to IN subquery. Set to "
|
"IN predicate that triggers its conversion to IN subquery. Set to "
|
||||||
"0 to disable the conversion.",
|
"0 to disable the conversion.",
|
||||||
SESSION_VAR(in_subquery_conversion_threshold), CMD_LINE(REQUIRED_ARG),
|
SESSION_VAR(in_subquery_conversion_threshold), CMD_LINE(REQUIRED_ARG),
|
||||||
VALID_RANGE(0, UINT_MAX), DEFAULT(IN_SUBQUERY_CONVERSION_THRESHOLD), BLOCK_SIZE(1));
|
VALID_RANGE(0, UINT_MAX), DEFAULT(IN_SUBQUERY_CONVERSION_THRESHOLD),
|
||||||
|
BLOCK_SIZE(1));
|
||||||
|
|
||||||
static Sys_var_ulong Sys_optimizer_max_sel_arg_weight(
|
static Sys_var_ulong Sys_optimizer_max_sel_arg_weight(
|
||||||
"optimizer_max_sel_arg_weight",
|
"optimizer_max_sel_arg_weight",
|
||||||
@@ -6985,7 +6986,50 @@ static Sys_var_uint Sys_optimizer_cache_hit_ratio(
|
|||||||
"optimizer_cache_hit_ratio",
|
"optimizer_cache_hit_ratio",
|
||||||
"Expected hit rate of the row and index cache in storage engines. "
|
"Expected hit rate of the row and index cache in storage engines. "
|
||||||
"The value should be an integer between 0 and 99, where 0 means cache is "
|
"The value should be an integer between 0 and 99, where 0 means cache is "
|
||||||
"empty and 99 means that value is almost always in the cache",
|
"empty and 99 means that value is almost always in the cache.",
|
||||||
SESSION_VAR(optimizer_cache_hit_ratio), CMD_LINE(REQUIRED_ARG),
|
SESSION_VAR(optimizer_cache_hit_ratio), CMD_LINE(REQUIRED_ARG),
|
||||||
VALID_RANGE(0, 99), DEFAULT(CACHE_HIT_RATIO), 1, NO_MUTEX_GUARD,
|
VALID_RANGE(0, 99), DEFAULT(DEFAULT_CACHE_HIT_RATIO), 1, NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_key_copy_cost(
|
||||||
|
"optimizer_key_copy_cost",
|
||||||
|
"Cost of finding the next key in the engine and copying it to the SQL layer.",
|
||||||
|
SESSION_VAR(optimizer_key_copy_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_KEY_COPY_COST), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_index_block_copy_cost(
|
||||||
|
"optimizer_index_block_copy_cost",
|
||||||
|
"Cost of copying a key block from the cache to intern storage as part of an "
|
||||||
|
"index scan.",
|
||||||
|
SESSION_VAR(optimizer_index_block_copy_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_INDEX_BLOCK_COPY_COST), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_key_next_find_cost(
|
||||||
|
"optimizer_key_next_find_cost",
|
||||||
|
"Cost of finding the next key and rowid when using filters.",
|
||||||
|
SESSION_VAR(optimizer_key_next_find_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_KEY_NEXT_FIND_COST), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_row_copy_cost(
|
||||||
|
"optimizer_row_copy_cost",
|
||||||
|
"Cost of copying a row from the engine or the join cache to the SQL layer.",
|
||||||
|
SESSION_VAR(optimizer_row_copy_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_ROW_COPY_COST), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_where_cost(
|
||||||
|
"optimizer_where_cost",
|
||||||
|
"Cost of checking the row against the WHERE clause.",
|
||||||
|
SESSION_VAR(optimizer_where_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_WHERE_COST), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG);
|
||||||
|
|
||||||
|
static Sys_var_double Sys_optimizer_key_cmp_cost(
|
||||||
|
"optimizer_key_compare_cost",
|
||||||
|
"Cost of checking a key against the end key condition.",
|
||||||
|
SESSION_VAR(optimizer_key_cmp_cost), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, 1), DEFAULT(DEFAULT_KEY_COMPARE_COST), NO_MUTEX_GUARD,
|
||||||
NOT_IN_BINLOG);
|
NOT_IN_BINLOG);
|
||||||
|
18
sql/table.cc
18
sql/table.cc
@@ -5672,12 +5672,14 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
|
|||||||
opt_range_condition_rows=0;
|
opt_range_condition_rows=0;
|
||||||
no_cache= false;
|
no_cache= false;
|
||||||
initialize_opt_range_structures();
|
initialize_opt_range_structures();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update optimizer_cache_cost to ensure that a SET STATEMENT of
|
Update optimizer_costs to ensure that a SET STATEMENT of the
|
||||||
the variable it will work.
|
variables it will work.
|
||||||
*/
|
*/
|
||||||
file->set_optimizer_cache_cost(cache_hit_cost(thd->variables.
|
file->set_optimizer_costs(thd);
|
||||||
optimizer_cache_hit_ratio));
|
|
||||||
#ifdef HAVE_REPLICATION
|
#ifdef HAVE_REPLICATION
|
||||||
/* used in RBR Triggers */
|
/* used in RBR Triggers */
|
||||||
master_had_triggers= 0;
|
master_had_triggers= 0;
|
||||||
@@ -10434,6 +10436,14 @@ inline void TABLE::initialize_opt_range_structures()
|
|||||||
TRASH_ALLOC(const_key_parts, s->keys * sizeof(*const_key_parts));
|
TRASH_ALLOC(const_key_parts, s->keys * sizeof(*const_key_parts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double TABLE::OPT_RANGE::index_only_fetch_cost(THD *thd)
|
||||||
|
{
|
||||||
|
return (index_only_cost + (double) rows *
|
||||||
|
thd->variables.optimizer_key_copy_cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Mark table to be reopened after query
|
Mark table to be reopened after query
|
||||||
*/
|
*/
|
||||||
|
@@ -1420,10 +1420,7 @@ public:
|
|||||||
Cost of fetching keys with index only read and returning them to the
|
Cost of fetching keys with index only read and returning them to the
|
||||||
sql level.
|
sql level.
|
||||||
*/
|
*/
|
||||||
double index_only_fetch_cost()
|
double index_only_fetch_cost(THD *thd);
|
||||||
{
|
|
||||||
return index_only_cost + (double) rows * KEY_COPY_COST;
|
|
||||||
}
|
|
||||||
} *opt_range;
|
} *opt_range;
|
||||||
/*
|
/*
|
||||||
Bitmaps of key parts that =const for the duration of join execution. If
|
Bitmaps of key parts that =const for the duration of join execution. If
|
||||||
|
@@ -156,7 +156,7 @@ inline double log2_n_fact(double x)
|
|||||||
the same length, so each of total_buf_size elements will be added to a sort
|
the same length, so each of total_buf_size elements will be added to a sort
|
||||||
heap with (n_buffers-1) elements. This gives the comparison cost:
|
heap with (n_buffers-1) elements. This gives the comparison cost:
|
||||||
|
|
||||||
total_buf_elems* log2(n_buffers) / TIME_FOR_COMPARE_ROWID;
|
total_buf_elems* log2(n_buffers) * ROWID_COMPARE_COST;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
|
static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
|
||||||
@@ -171,8 +171,8 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
|
|||||||
size_t n_buffers= last - first + 1;
|
size_t n_buffers= last - first + 1;
|
||||||
|
|
||||||
/* Using log2(n)=log(n)/log(2) formula */
|
/* Using log2(n)=log(n)/log(2) formula */
|
||||||
return 2*((double)total_buf_elems*elem_size) / IO_SIZE +
|
return (2*((double)total_buf_elems*elem_size) / IO_SIZE +
|
||||||
total_buf_elems*log((double) n_buffers) / (compare_factor * M_LN2);
|
total_buf_elems*log((double) n_buffers) * compare_factor / M_LN2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ double Unique::get_use_cost(uint *buffer, size_t nkeys, uint key_size,
|
|||||||
result= 2*log2_n_fact(last_tree_elems + 1.0);
|
result= 2*log2_n_fact(last_tree_elems + 1.0);
|
||||||
if (n_full_trees)
|
if (n_full_trees)
|
||||||
result+= n_full_trees * log2_n_fact(max_elements_in_tree + 1.0);
|
result+= n_full_trees * log2_n_fact(max_elements_in_tree + 1.0);
|
||||||
result /= compare_factor;
|
result *= compare_factor;
|
||||||
|
|
||||||
DBUG_PRINT("info",("unique trees sizes: %u=%u*%u + %u", (uint)nkeys,
|
DBUG_PRINT("info",("unique trees sizes: %u=%u*%u + %u", (uint)nkeys,
|
||||||
(uint)n_full_trees,
|
(uint)n_full_trees,
|
||||||
|
@@ -75,7 +75,7 @@ public:
|
|||||||
inline static double get_search_cost(ulonglong tree_elems,
|
inline static double get_search_cost(ulonglong tree_elems,
|
||||||
double compare_factor)
|
double compare_factor)
|
||||||
{
|
{
|
||||||
return log((double) tree_elems) / (compare_factor * M_LN2);
|
return log((double) tree_elems) * compare_factor / M_LN2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double get_use_cost(uint *buffer, size_t nkeys, uint key_size,
|
static double get_use_cost(uint *buffer, size_t nkeys, uint key_size,
|
||||||
|
Reference in New Issue
Block a user