Commit 013ba37a authored by Monty's avatar Monty Committed by Sergei Petrunia

Fix cost calculation in test_if_cheaper_ordering() to be cost based

The original code was mostly rule based and preferred clustered or
covering indexed independent of cost.

There where a few test changes:
- Some test changed from using filesort to index or table scan. This
  happened when most of the rows had to be sorted and the ORDER BY could
  use covering or a clustered index (innodb_mysql, create_spatial_index).
- Some test changed range to filesort. This where mainly because the range
  was scanning most of the rows or using index scan + row lookup and
  filesort with table scan is cheaper. (order_by).
- Change in join_cache was because sorting 2 rows is faster than retrieving
  10 rows.
- In selectivity_innodb.test one test changed to use a cheaper index.
parent 59193ef6
......@@ -5153,7 +5153,7 @@ SET SESSION optimizer_switch = 'index_condition_pushdown=off';
EXPLAIN SELECT * FROM t1,t2
WHERE t2.f3 = t1.f2 AND t1.f1 IN (9, 0, 100) ORDER BY t1.f2 LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range f1,f2 f2 13 NULL 10 Using where
1 SIMPLE t1 range f1,f2 f1 5 NULL 3 Using where; Rowid-ordered scan; Using filesort
1 SIMPLE t2 ref f3 f3 67 test.t1.f2 2 Using where; Using index
SELECT * FROM t1,t2
WHERE t2.f3 = t1.f2 AND t1.f1 IN (9, 0 ,100) ORDER BY t1.f2 LIMIT 1;
......@@ -5163,7 +5163,7 @@ SET SESSION optimizer_switch = 'index_condition_pushdown=on';
EXPLAIN SELECT * FROM t1,t2
WHERE t2.f3 = t1.f2 AND t1.f1 IN (9, 0 ,100) ORDER BY t1.f2 LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range f1,f2 f2 13 NULL 10 Using where
1 SIMPLE t1 range f1,f2 f1 5 NULL 3 Using index condition; Using where; Rowid-ordered scan; Using filesort
1 SIMPLE t2 ref f3 f3 67 test.t1.f2 2 Using where; Using index
SELECT * FROM t1,t2
WHERE t2.f3 = t1.f2 AND t1.f1 IN (9, 0 ,100) ORDER BY t1.f2 LIMIT 1;
......
......@@ -1709,18 +1709,20 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
{
"reconsidering_access_paths_for_index_ordering": {
"clause": "GROUP BY",
"fanout": 1,
"read_time": 2.084226263,
"table": "t1",
"rows_estimation": 7,
"rows_estimation": 1,
"read_cost": 2.147624763,
"filesort_cost": 0.0633985,
"filesort_type": "priority_queue with addon fields",
"fanout": 1,
"possible_keys": [
{
"index": "a",
"can_resolve_order": true,
"direction": 1,
"updated_limit": 7,
"index_scan_cost": 2.084226263,
"rows": 7,
"rows_to_examine": 7,
"range_scan": false,
"scan_cost": 2.084226263,
"chosen": true
}
]
......@@ -2168,7 +2170,7 @@ a int,
b int,
c int,
filler char(100),
KEY a_a(c),
KEY c(c),
KEY a_c(a,c),
KEY a_b(a,b)
);
......@@ -2183,6 +2185,10 @@ test.t1 analyze status OK
set optimizer_trace='enabled=on';
explain select * from t1 where a=1 and b=2 order by c limit 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a_c,a_b a_b 10 const,const 21 Using where; Using filesort
update t1 set b=2 where pk between 20 and 40;
explain select * from t1 where a=1 and b=2 order by c limit 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a_c,a_b a_c 5 NULL 180 Using where
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
......@@ -2268,7 +2274,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
},
"potential_range_indexes": [
{
"index": "a_a",
"index": "c",
"usable": false,
"cause": "not applicable"
},
......@@ -2302,8 +2308,8 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 21,
"cost": 16.28742739,
"rows": 41,
"cost": 31.3040249,
"chosen": true
}
],
......@@ -2320,11 +2326,11 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"range_access_plan": {
"type": "range_scan",
"index": "a_b",
"rows": 21,
"rows": 41,
"ranges": ["(1,2) <= (a,b) <= (1,2)"]
},
"rows_for_plan": 21,
"cost_for_plan": 16.28742739,
"rows_for_plan": 41,
"cost_for_plan": 31.3040249,
"chosen": true
}
}
......@@ -2334,8 +2340,8 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"rowid_filters": [
{
"key": "a_b",
"build_cost": 1.127362357,
"rows": 21
"build_cost": 1.752281351,
"rows": 41
},
{
"key": "a_c",
......@@ -2348,7 +2354,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"selectivity_for_indexes": [
{
"index_name": "a_b",
"selectivity_from_index": 0.021
"selectivity_from_index": 0.041
}
],
"selectivity_for_columns": [
......@@ -2363,7 +2369,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"selectivity_from_histogram": 0.021
}
],
"cond_selectivity": 0.021
"cond_selectivity": 0.041
}
]
},
......@@ -2391,8 +2397,8 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"access_type": "ref",
"index": "a_b",
"used_range_estimates": true,
"rows": 21,
"cost": 16.26742739,
"rows": 41,
"cost": 31.2840249,
"chosen": true
},
{
......@@ -2403,9 +2409,9 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
],
"chosen_access_method": {
"type": "ref",
"records_read": 21,
"records_out": 21,
"cost": 16.26742739,
"records_read": 41,
"records_out": 41,
"cost": 31.2840249,
"uses_join_buffering": false
}
}
......@@ -2415,15 +2421,15 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
{
"plan_prefix": [],
"table": "t1",
"rows_for_plan": 21,
"cost_for_plan": 16.26742739
"rows_for_plan": 41,
"cost_for_plan": 31.2840249
}
]
},
{
"best_join_order": ["t1"],
"rows": 21,
"cost": 16.26742739
"rows": 41,
"cost": 31.2840249
},
{
"substitute_best_equal": {
......@@ -2445,28 +2451,29 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
{
"reconsidering_access_paths_for_index_ordering": {
"clause": "ORDER BY",
"fanout": 1,
"read_time": 16.26742739,
"table": "t1",
"rows_estimation": 21,
"rows_estimation": 41,
"read_cost": 32.58369415,
"filesort_cost": 1.299669251,
"filesort_type": "priority_queue with addon fields",
"fanout": 1,
"possible_keys": [
{
"index": "a_a",
"index": "c",
"can_resolve_order": true,
"direction": 1,
"updated_limit": 47,
"index_scan_cost": 35.77753234,
"usable": false,
"cause": "cost"
"rows_to_examine": 24,
"range_scan": false,
"scan_cost": 18.51405907,
"chosen": true
},
{
"index": "a_c",
"can_resolve_order": true,
"direction": 1,
"updated_limit": 47,
"index_scan_cost": 35.78900415,
"range_scan_cost": 6.375520747,
"rows": 180,
"rows_to_examine": 4,
"range_scan": true,
"scan_cost": 10.5218905,
"chosen": true
},
{
......@@ -2486,7 +2493,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
},
"potential_range_indexes": [
{
"index": "a_a",
"index": "c",
"usable": false,
"cause": "not applicable"
},
......
......@@ -148,7 +148,7 @@ create table t1 (
b int,
c int,
filler char(100),
KEY a_a(c),
KEY c(c),
KEY a_c(a,c),
KEY a_b(a,b)
);
......@@ -160,6 +160,9 @@ update t1 set b=2 where pk between 0 and 20;
analyze table t1;
set optimizer_trace='enabled=on';
explain select * from t1 where a=1 and b=2 order by c limit 1;
update t1 set b=2 where pk between 20 and 40;
explain select * from t1 where a=1 and b=2 order by c limit 1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1,ten,one_k;
......
......@@ -1552,16 +1552,71 @@ UNIQUE KEY a_c (a,c),
KEY (a));
INSERT INTO t1 VALUES (1, 10), (2, NULL);
# Must use ref-or-null on the a_c index
ANALYZE FORMAT=JSON
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"read_sorted_file": {
"r_rows": 1,
"filesort": {
"sort_key": "t1.c",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_used_priority_queue": false,
"r_output_rows": 1,
"r_buffer_size": "REPLACED",
"r_sort_mode": "sort_key,addon_fields",
"table": {
"table_name": "t1",
"access_type": "index",
"possible_keys": ["a_c", "a"],
"key": "a_c",
"key_length": "10",
"used_key_parts": ["a", "c"],
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 50,
"r_filtered": 50,
"attached_condition": "t1.a = 2 and (t1.c = 10 or t1.c is null)",
"using_index": true
}
}
}
}
]
}
}
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a_c,a a_c 10 NULL 2 Using where; Using index
1 SIMPLE t1 index a_c,a a_c 10 NULL 2 Using where; Using index; Using filesort
# Must return 1 row
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
col
1
# With more rows "filesort" is removed
INSERT INTO t1 select seq,seq from seq_1_to_2;
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a_c,a a_c 10 NULL 2 Using where; Using index
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
col
1
# With more rows "range" changes to "ref_or_null"
INSERT INTO t1 select seq,seq from seq_1_to_10;
INSERT INTO t1 select seq,seq from seq_3_to_10;
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
id select_type table type possible_keys key key_len ref rows Extra
......
......@@ -912,13 +912,23 @@ CREATE TABLE t1 (
INSERT INTO t1 VALUES (1, 10), (2, NULL);
--echo # Must use ref-or-null on the a_c index
--source include/analyze-format.inc
ANALYZE FORMAT=JSON
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
--echo # Must return 1 row
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
--echo # With more rows "filesort" is removed
INSERT INTO t1 select seq,seq from seq_1_to_2;
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
--echo # With more rows "range" changes to "ref_or_null"
INSERT INTO t1 select seq,seq from seq_1_to_10;
INSERT INTO t1 select seq,seq from seq_3_to_10;
EXPLAIN
SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c;
......
......@@ -3601,7 +3601,7 @@ SELECT * FROM t1
WHERE (a BETWEEN 9 AND 10 OR a IS NULL) AND (b BETWEEN 9 AND 10 OR b = 9)
ORDER BY pk LIMIT 1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index a,b PRIMARY 4 NULL 75 100.00 Using where
1 SIMPLE t1 index a,b PRIMARY 4 NULL 73 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (`test`.`t1`.`a` between 9 and 10 or `test`.`t1`.`a` is null) and (`test`.`t1`.`b` between 9 and 10 or `test`.`t1`.`b` = 9) order by `test`.`t1`.`pk` limit 1
ANALYZE
......
......@@ -334,7 +334,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.orders.o_orderkey 1 100.00
1 PRIMARY lineitem ref PRIMARY,i_l_orderkey,i_l_orderkey_quantity i_l_orderkey_quantity 4 dbt3_s001.orders.o_orderkey 4 100.00 Using index
2 MATERIALIZED lineitem index NULL PRIMARY 8 NULL 6005 100.00
2 MATERIALIZED lineitem index NULL i_l_orderkey_quantity 13 NULL 6005 100.00 Using index
Warnings:
Note 1003 /* select#1 */ select `dbt3_s001`.`customer`.`c_name` AS `c_name`,`dbt3_s001`.`customer`.`c_custkey` AS `c_custkey`,`dbt3_s001`.`orders`.`o_orderkey` AS `o_orderkey`,`dbt3_s001`.`orders`.`o_orderDATE` AS `o_orderdate`,`dbt3_s001`.`orders`.`o_totalprice` AS `o_totalprice`,sum(`dbt3_s001`.`lineitem`.`l_quantity`) AS `sum(l_quantity)` from <materialize> (/* select#2 */ select `dbt3_s001`.`lineitem`.`l_orderkey` from `dbt3_s001`.`lineitem` group by `dbt3_s001`.`lineitem`.`l_orderkey` having sum(`dbt3_s001`.`lineitem`.`l_quantity`) > 250) join `dbt3_s001`.`customer` join `dbt3_s001`.`orders` join `dbt3_s001`.`lineitem` where `dbt3_s001`.`customer`.`c_custkey` = `dbt3_s001`.`orders`.`o_custkey` and `<subquery2>`.`l_orderkey` = `dbt3_s001`.`orders`.`o_orderkey` and `dbt3_s001`.`lineitem`.`l_orderkey` = `dbt3_s001`.`orders`.`o_orderkey` group by `dbt3_s001`.`customer`.`c_name`,`dbt3_s001`.`customer`.`c_custkey`,`dbt3_s001`.`orders`.`o_orderkey`,`dbt3_s001`.`orders`.`o_orderDATE`,`dbt3_s001`.`orders`.`o_totalprice` order by `dbt3_s001`.`orders`.`o_totalprice` desc,`dbt3_s001`.`orders`.`o_orderDATE`
select
......@@ -368,7 +368,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.orders.o_orderkey 1 100.00
1 PRIMARY lineitem ref PRIMARY,i_l_orderkey,i_l_orderkey_quantity i_l_orderkey_quantity 4 dbt3_s001.orders.o_orderkey 4 100.00 Using index
2 MATERIALIZED lineitem index NULL PRIMARY 8 NULL 6005 100.00
2 MATERIALIZED lineitem index NULL i_l_orderkey_quantity 13 NULL 6005 100.00 Using index
Warnings:
Note 1003 /* select#1 */ select `dbt3_s001`.`customer`.`c_name` AS `c_name`,`dbt3_s001`.`customer`.`c_custkey` AS `c_custkey`,`dbt3_s001`.`orders`.`o_orderkey` AS `o_orderkey`,`dbt3_s001`.`orders`.`o_orderDATE` AS `o_orderdate`,`dbt3_s001`.`orders`.`o_totalprice` AS `o_totalprice`,sum(`dbt3_s001`.`lineitem`.`l_quantity`) AS `sum(l_quantity)` from <materialize> (/* select#2 */ select `dbt3_s001`.`lineitem`.`l_orderkey` from `dbt3_s001`.`lineitem` group by `dbt3_s001`.`lineitem`.`l_orderkey` having sum(`dbt3_s001`.`lineitem`.`l_quantity`) > 250) join `dbt3_s001`.`customer` join `dbt3_s001`.`orders` join `dbt3_s001`.`lineitem` where `dbt3_s001`.`customer`.`c_custkey` = `dbt3_s001`.`orders`.`o_custkey` and `<subquery2>`.`l_orderkey` = `dbt3_s001`.`orders`.`o_orderkey` and `dbt3_s001`.`lineitem`.`l_orderkey` = `dbt3_s001`.`orders`.`o_orderkey` group by `dbt3_s001`.`customer`.`c_name`,`dbt3_s001`.`customer`.`c_custkey`,`dbt3_s001`.`orders`.`o_orderkey`,`dbt3_s001`.`orders`.`o_orderDATE`,`dbt3_s001`.`orders`.`o_totalprice` order by `dbt3_s001`.`orders`.`o_totalprice` desc,`dbt3_s001`.`orders`.`o_orderDATE`
select
......
......@@ -1407,13 +1407,13 @@ EXPLAIN SELECT * FROM t2 WHERE b=1 ORDER BY a;
id 1
select_type SIMPLE
table t2
type ref
type index
possible_keys bkey
key bkey
key_len 5
ref const
key PRIMARY
key_len 4
ref NULL
rows 16
Extra Using where; Using index; Using filesort
Extra Using where
SELECT * FROM t2 WHERE b=1 ORDER BY a;
a b c
1 1 1
......
......@@ -148,7 +148,7 @@ a b c d e
03 03 343 7 03_03_343
03 06 343 8 03_06_343
03 07 343 9 03_07_343
SELECT a,count(b) FROM t1 GROUP BY a ORDER BY a LOCK IN SHARE MODE SKIP LOCKED;
SELECT a,count(b) FROM t1 force index (a) GROUP BY a ORDER BY a LOCK IN SHARE MODE SKIP LOCKED;
a count(b)
01 5
03 3
......
......@@ -104,7 +104,7 @@ SELECT * FROM t1 LOCK IN SHARE MODE;
--error ER_LOCK_WAIT_TIMEOUT
SELECT * FROM t1 LOCK IN SHARE MODE NOWAIT;
SELECT * FROM t1 ORDER BY d LOCK IN SHARE MODE SKIP LOCKED;
SELECT a,count(b) FROM t1 GROUP BY a ORDER BY a LOCK IN SHARE MODE SKIP LOCKED;
SELECT a,count(b) FROM t1 force index (a) GROUP BY a ORDER BY a LOCK IN SHARE MODE SKIP LOCKED;
SELECT d,a,b,c FROM t1 partition (p1,p9,p11,p17) ORDER BY d
LOCK IN SHARE MODE SKIP LOCKED;
SELECT d,a,b,c FROM t1 ORDER BY d LOCK IN SHARE MODE SKIP LOCKED;
......
......@@ -28,7 +28,8 @@ const LEX_CSTRING filesort_names[]=
{ STRING_WITH_LEN("priority_queue with addon fields")},
{ STRING_WITH_LEN("priority_queue with row lookup")},
{ STRING_WITH_LEN("merge_sort with addon fields")},
{ STRING_WITH_LEN("merge_sort with row lookup)")}
{ STRING_WITH_LEN("merge_sort with row lookup)")},
{ STRING_WITH_LEN("Error while computing filesort cost")}
};
/*
......@@ -447,7 +448,7 @@ double cost_of_filesort(TABLE *table, ORDER *order_by, ha_rows rows_to_read,
for (ORDER *ptr= order_by; ptr ; ptr= ptr->next)
{
Item_field *field= (Item_field*) (*ptr->item)->real_item();
size_t length= get_sort_length(table->in_use, field);
size_t length= get_sort_length(thd, field);
set_if_smaller(length, thd->variables.max_sort_length);
sort_len+= (uint) length;
}
......
......@@ -77,9 +77,8 @@ enum sort_type
MERGE_SORT_ALL_FIELDS,
MERGE_SORT_ORDER_BY_FIELDS,
FINAL_SORT_TYPE,
NO_SORT_POSSIBLE_OUT_OF_MEM,
NO_SORT_POSSIBLE_OUT_OF_MEM, /* In case of errors */
FINAL_SORT_TYPE= NO_SORT_POSSIBLE_OUT_OF_MEM
};
struct Sort_costs
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment