#At file:///export/home/jl208045/mysql/wl4800/mysql-next-mr-opt-backporting-wl4800-patchcleanup/ based on revid:guilhem@stripped
3229 Jorgen Loland 2010-10-22
WL#5594 - Add optimizer traces to the range optimizer
Add optimizer trace points to the range optimizer.
@ mysql-test/include/optimizer_trace.inc
Increase optimizer_trace_max_mem_size to 1MB
@ mysql-test/r/optimizer_trace_charset.result
Traces now include range optimizer tracepoints. Added test for range with special characters.
@ mysql-test/r/optimizer_trace_no_prot.result
Adds range information to trace of existing queries
@ mysql-test/r/optimizer_trace_range.result
Tests for tracing of range optimizer
@ mysql-test/t/optimizer_trace_charset.test
Added test for range with special characters.
@ mysql-test/t/optimizer_trace_range.test
Tests for tracing of range optimizer
@ sql/handler.cc
Enable ifndef'ed tracepoint belonging to range optimizer
@ sql/opt_range.cc
Add tracepoints to range optimizer
@ sql/opt_range.h
Add tracepoints to range optimizer
@ sql/opt_trace.cc
Add RANGE_OPTIMIZER trace flag
@ sql/opt_trace.h
Add RANGE_OPTIMIZER trace flag
@ sql/sql_select.cc
Add tracepoints to range optimizer
added:
mysql-test/r/optimizer_trace_range.result
mysql-test/t/optimizer_trace_range.test
modified:
mysql-test/include/optimizer_trace.inc
mysql-test/r/optimizer_trace_charset.result
mysql-test/r/optimizer_trace_no_prot.result
mysql-test/t/optimizer_trace_charset.test
sql/handler.cc
sql/opt_range.cc
sql/opt_range.h
sql/opt_trace.cc
sql/opt_trace.h
sql/sql_select.cc
=== modified file 'mysql-test/include/optimizer_trace.inc'
--- a/mysql-test/include/optimizer_trace.inc 2010-10-21 15:22:32 +0000
+++ b/mysql-test/include/optimizer_trace.inc 2010-10-22 08:31:43 +0000
@@ -24,6 +24,8 @@
# should be empty
select * from information_schema.OPTIMIZER_TRACE;
+let $DEFAULT_TRACE_MEM_SIZE=1048576; # 1MB
+eval set optimizer_trace_max_mem_size=$DEFAULT_TRACE_MEM_SIZE;
set @@session.optimizer_trace="enabled=on";
select * from information_schema.OPTIMIZER_TRACE;
@@ -108,7 +110,7 @@ select * from information_schema.OPTIMIZ
set optimizer_trace_max_mem_size=0;
select 1;
select * from information_schema.OPTIMIZER_TRACE;
-set optimizer_trace_max_mem_size=default;
+eval set optimizer_trace_max_mem_size=$DEFAULT_TRACE_MEM_SIZE;
# semijoin
=== modified file 'mysql-test/r/optimizer_trace_charset.result'
--- a/mysql-test/r/optimizer_trace_charset.result 2010-10-09 15:04:30 +0000
+++ b/mysql-test/r/optimizer_trace_charset.result 2010-10-22 08:31:43 +0000
@@ -33,6 +33,13 @@ explain extended select '��� from t1
"t1"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -71,6 +78,13 @@ explain extended select 'ÁÂÃÄÅ' fro
"t1"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -124,6 +138,13 @@ select * from v1 where v1.col = '���
"t1"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -165,6 +186,13 @@ select * from v1 where v1.col = '���
"v1"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "",
+ "table": "v1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -181,4 +209,135 @@ select * from v1 where v1.col = '���
}
drop table t1;
drop view v1;
+create table t1(c char(4) primary key);
+insert into t1 values ('aaa'), ('��');
+select * from t1 where c < '���;
+c
+aaa
+��
+select query, trace from information_schema.OPTIMIZER_TRACE;
+query trace
+select * from t1 where c < '��� {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where (`c` < '?????')"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t1`.`c` < '?????')",
+ "after_equality_propagation": "(`test`.`t1`.`c` < '?????')",
+ "after_constant_propagation": "(`test`.`t1`.`c` < '?????')",
+ "after_trivial_conditions_removal": "(`test`.`t1`.`c` < '?????')"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": true,
+ "key_parts": [
+ "c"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "PRIMARY",
+ "cost": 1.4213,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "PRIMARY",
+ "ranges": [
+ "c <= ��"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 2,
+ "cost": 3.41,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 2,
+ "cost": 2.0034,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.0034,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t1`.`c` < '?????')",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "(`test`.`t1`.`c` < '?????')"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+}
+drop table t1;
set optimizer_trace=default;
=== modified file 'mysql-test/r/optimizer_trace_no_prot.result'
--- a/mysql-test/r/optimizer_trace_no_prot.result 2010-10-21 15:22:32 +0000
+++ b/mysql-test/r/optimizer_trace_no_prot.result 2010-10-22 08:31:43 +0000
@@ -1,5 +1,6 @@
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+set optimizer_trace_max_mem_size=1048576;
set @@session.optimizer_trace="enabled=on";
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
@@ -40,6 +41,13 @@ SELECT (SELECT 1 FROM D WHERE d = c) AS
"C"
],
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
]
},
{
@@ -78,10 +86,36 @@ SELECT (SELECT 1 FROM D WHERE d = c) AS
],
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- }
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ },
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ },
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ },
+ "impossible_range": true
+ },
+ "records": 0,
+ "cause": "impossible_where_condition"
}
]
}
@@ -96,18 +130,18 @@ SELECT (SELECT 1 FROM D WHERE d = c) AS
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-45.3699
+50.1160
set optimizer_trace="one_line=on";
SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C ;
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
-SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C {"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`D` where (`d` = `c`)) AS `RESULT` from `test`.`C`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["C"],"records_estimation": []},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`D`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`D`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "D.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"table": "D","more_range_optimizer_trace": {"TODO?": "yes!"}}]}],"empty_result": {"cause": "no matching row in const table"}}}]} 0 0
+SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C {"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`D` where (`d` = `c`)) AS `RESULT` from `test`.`C`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["C"],"records_estimation": [{"database": "test","table": "C","records": 1,"cost": 1,"cause": "system_table"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`D`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`D`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "D.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"database": "test","table": "D","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","usable": true,"key_parts": ["d"]}],"best_covering_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_condition": {"table": "D","field": "d","cause": "comparison_with_null_always_false"},"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]} 0 0
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-6.4238
+6.0729
set optimizer_trace="one_line=off,end_marker=on";
EXPLAIN SELECT (SELECT 1 FROM D WHERE d = ifnull(c,null)) AS RESULT FROM C ;
id select_type table type possible_keys key key_len ref rows Extra
@@ -143,6 +177,13 @@ EXPLAIN SELECT (SELECT 1 FROM D WHERE d
"C"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -181,10 +222,36 @@ EXPLAIN SELECT (SELECT 1 FROM D WHERE d
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -229,6 +296,13 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
"C"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -267,10 +341,36 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -333,6 +433,13 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
"C"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -371,10 +478,36 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -410,10 +543,36 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -439,6 +598,7 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
] /* constant_tables */,
"records_estimation": [
{
+ "database": "",
"table": "",
"table_scan": {
"records": 0,
@@ -450,13 +610,15 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
{
"considered_execution_plans": [
{
+ "database": "",
"table": "",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 0,
+ "cost": 10,
"chosen": true
}
] /* considered_access_paths */
@@ -472,6 +634,7 @@ SELECT (SELECT 1 FROM D WHERE d = ifnull
"original_condition": null,
"attached_conditions": [
{
+ "database": "",
"table": "",
"attached": null
}
@@ -583,6 +746,13 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
"C"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -655,6 +825,7 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
] /* constant_tables */,
"records_estimation": [
{
+ "database": "",
"table": "",
"table_scan": {
"records": 0,
@@ -666,13 +837,15 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
{
"considered_execution_plans": [
{
+ "database": "",
"table": "",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 0,
+ "cost": 10,
"chosen": true
}
] /* considered_access_paths */
@@ -688,6 +861,7 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
"original_condition": null,
"attached_conditions": [
{
+ "database": "",
"table": "",
"attached": null
}
@@ -710,7 +884,7 @@ select (@query:=QUERY)+NULL, (@trace:=TR
NULL NULL
select length(@trace);
length(@trace)
-8594
+8953
set optimizer_trace_max_mem_size=8400;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
@@ -719,7 +893,7 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
c
select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
(@missing_bytes:=missing_bytes_beyond_max_mem_size)
-306
+671
select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
(@query2:=QUERY)+NULL (@trace2:=TRACE)+NULL
NULL NULL
@@ -727,7 +901,7 @@ select length(@trace2),
(length(@trace2) + @missing_bytes) = length(@trace),
@query2 = @query;
length(@trace2) (length(@trace2) + @missing_bytes) = length(@trace) @query2 = @query
-8288 1 1
+8282 1 1
select length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100);
length(@query2) + length(@trace2)
@@ -750,7 +924,7 @@ select 1;
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
381 0
-set optimizer_trace_max_mem_size=default;
+set optimizer_trace_max_mem_size=1048576;
explain SELECT c FROM C where c+1 in (select d+1 from D where d is null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY C system NULL NULL NULL NULL 1
@@ -819,10 +993,59 @@ explain SELECT c FROM C where c+1 in (se
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_single_table"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "NULL <= d <= NULL"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
}
] /* records_estimation */
},
@@ -836,21 +1059,23 @@ explain SELECT c FROM C where c+1 in (se
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 2,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -886,21 +1111,23 @@ explain SELECT c FROM C where c+1 in (se
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 2,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -942,6 +1169,7 @@ explain SELECT c FROM C where c+1 in (se
"original_condition": "(isnull(`test`.`D`.`d`) and ((NULL + 1) = (`test`.`D`.`d` + 1)))",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(isnull(`test`.`D`.`d`) and ((NULL + 1) = (`test`.`D`.`d` + 1)))"
}
@@ -1017,6 +1245,13 @@ explain SELECT c FROM C where c+1 in (se
"C"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -1063,31 +1298,75 @@ explain SELECT c FROM C where c+1 in (se
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.4233,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "NULL <= d <= NULL"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
}
] /* records_estimation */
},
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 2,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -1102,6 +1381,7 @@ explain SELECT c FROM C where c+1 in (se
"original_condition": "isnull(`test`.`D`.`d`)",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "isnull(`test`.`D`.`d`)"
}
@@ -1174,6 +1454,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1185,13 +1466,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1207,6 +1490,7 @@ explain extended select * from t1 where
"original_condition": "<nop>((`test`.`t1`.`s1` > (/* select#2 */ select min(`test`.`t1`.`s2`) from `test`.`t1`)))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "<nop>((`test`.`t1`.`s1` > (/* select#2 */ select min(`test`.`t1`.`s2`) from `test`.`t1`)))"
}
@@ -1225,6 +1509,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1236,13 +1521,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1258,6 +1545,7 @@ explain extended select * from t1 where
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -1326,6 +1614,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1337,13 +1626,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1359,6 +1650,7 @@ explain extended select * from t1 where
"original_condition": "<nop>((`test`.`t1`.`s1` > <min>(/* select#2 */ select max(`test`.`t1`.`s2`) from `test`.`t1`)))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "<nop>((`test`.`t1`.`s1` > <min>(/* select#2 */ select max(`test`.`t1`.`s2`) from `test`.`t1`)))"
}
@@ -1377,6 +1669,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1388,13 +1681,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1410,6 +1705,7 @@ explain extended select * from t1 where
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -1495,6 +1791,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1506,13 +1803,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1528,6 +1827,7 @@ explain extended select * from t1 where
"original_condition": "<in_optimizer>(`test`.`t1`.`s1`,<exists>(/* select#2 */ select 1 from `test`.`t1` where (<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "<in_optimizer>(`test`.`t1`.`s1`,<exists>(/* select#2 */ select 1 from `test`.`t1` where (<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)))"
}
@@ -1559,6 +1859,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1570,13 +1871,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1592,6 +1895,7 @@ explain extended select * from t1 where
"original_condition": "(<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)"
}
@@ -1676,6 +1980,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1687,13 +1992,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1709,6 +2016,7 @@ explain extended select * from t1 where
"original_condition": "<in_optimizer>((`test`.`t1`.`s1`,`test`.`t1`.`s2`),<exists>(/* select#2 */ select `test`.`t1`.`s2`,`test`.`t1`.`s1` from `test`.`t1` where ((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "<in_optimizer>((`test`.`t1`.`s1`,`test`.`t1`.`s2`),<exists>(/* select#2 */ select `test`.`t1`.`s2`,`test`.`t1`.`s1` from `test`.`t1` where ((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))))"
}
@@ -1740,6 +2048,7 @@ explain extended select * from t1 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -1751,13 +2060,15 @@ explain extended select * from t1 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -1773,6 +2084,7 @@ explain extended select * from t1 where
"original_condition": "((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))"
}
@@ -1818,6 +2130,7 @@ explain select * from t1,t2 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -1825,6 +2138,7 @@ explain select * from t1,t2 {
} /* table_scan */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 2,
@@ -1836,13 +2150,15 @@ explain select * from t1,t2 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0034,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0034,
"chosen": true
}
] /* considered_access_paths */
@@ -1851,13 +2167,15 @@ explain select * from t1,t2 {
"records_for_plan": 2,
"rest_of_plan": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0053,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0053,
"chosen": true
}
] /* considered_access_paths */
@@ -1869,13 +2187,15 @@ explain select * from t1,t2 {
] /* rest_of_plan */
},
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -1884,13 +2204,15 @@ explain select * from t1,t2 {
"records_for_plan": 3,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0036,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0036,
"chosen": true
}
] /* considered_access_paths */
@@ -1908,10 +2230,12 @@ explain select * from t1,t2 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": null
},
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -1925,7 +2249,7 @@ explain select * from t1,t2 {
} 0 0
select @@optimizer_trace_features;
@@optimizer_trace_features
-misc=on,greedy_search=on
+misc=on,greedy_search=on,range_optimizer=on
set @@optimizer_trace_features="greedy_search=off";
explain select * from t1,t2;
id select_type table type possible_keys key key_len ref rows Extra
@@ -1954,6 +2278,7 @@ explain select * from t1,t2 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -1961,6 +2286,7 @@ explain select * from t1,t2 {
} /* table_scan */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 2,
@@ -1977,10 +2303,12 @@ explain select * from t1,t2 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": null
},
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -2108,6 +2436,7 @@ where a1 in (select b1 from t2_16 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1_16",
"table_scan": {
"records": 3,
@@ -2119,13 +2448,15 @@ where a1 in (select b1 from t2_16 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1_16",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0293,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0293,
"chosen": true
}
] /* considered_access_paths */
@@ -2141,6 +2472,7 @@ where a1 in (select b1 from t2_16 where
"original_condition": "<in_optimizer>(`test`.`t1_16`.`a1`,<exists>(/* select#2 */ select 1 from `test`.`t2_16` where ((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1_16",
"attached": "<in_optimizer>(`test`.`t1_16`.`a1`,<exists>(/* select#2 */ select 1 from `test`.`t2_16` where ((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))))"
}
@@ -2172,6 +2504,7 @@ where a1 in (select b1 from t2_16 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2_16",
"table_scan": {
"records": 3,
@@ -2183,13 +2516,15 @@ where a1 in (select b1 from t2_16 where
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2_16",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0293,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0293,
"chosen": true
}
] /* considered_access_paths */
@@ -2205,6 +2540,7 @@ where a1 in (select b1 from t2_16 where
"original_condition": "((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))",
"attached_conditions": [
{
+ "database": "test",
"table": "t2_16",
"attached": "((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))"
}
@@ -2299,6 +2635,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -2306,6 +2643,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
} /* table_scan */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -2317,13 +2655,15 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2332,13 +2672,15 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
"records_for_plan": 3,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0054,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0054,
"chosen": true
}
] /* considered_access_paths */
@@ -2350,13 +2692,15 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
] /* rest_of_plan */
},
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2372,10 +2716,12 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
"original_condition": "((`test`.`t2`.`c2` = `test`.`t1`.`c1`) and <in_optimizer>(`test`.`t1`.`c1`,<exists>(/* select#2 */ select 1 from `test`.`t2` where ((`test`.`t2`.`c2` = 1) and (<cache>(`test`.`t2`.`c2`) = `test`.`t2`.`c2`)))))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "<in_optimizer>(`test`.`t1`.`c1`,<exists>(/* select#2 */ select 1 from `test`.`t2` where ((`test`.`t2`.`c2` = 1) and (<cache>(`test`.`t2`.`c2`) = `test`.`t2`.`c2`))))"
},
{
+ "database": "test",
"table": "t2",
"attached": "(`test`.`t2`.`c2` = `test`.`t1`.`c1`)"
}
@@ -2407,6 +2753,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -2418,13 +2765,15 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2440,6 +2789,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
"original_condition": "((`test`.`t2`.`c2` = 1) and (<cache>(`test`.`t1`.`c1`) = 1))",
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": "((`test`.`t2`.`c2` = 1) and (<cache>(`test`.`t1`.`c1`) = 1))"
}
@@ -2497,6 +2847,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -2508,13 +2859,15 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2530,6 +2883,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
"original_condition": "(`test`.`t1`.`c1` = 5)",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(`test`.`t1`.`c1` = 5)"
}
@@ -2561,6 +2915,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -2572,13 +2927,15 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2594,6 +2951,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
"original_condition": "(`test`.`t2`.`c2` = 5)",
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": "(`test`.`t2`.`c2` = 5)"
}
@@ -2619,6 +2977,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
] /* constant_tables */,
"records_estimation": [
{
+ "database": "",
"table": "",
"table_scan": {
"records": 1,
@@ -2630,13 +2989,15 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
{
"considered_execution_plans": [
{
+ "database": "",
"table": "",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10.05,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 1,
+ "cost": 10.05,
"chosen": true
}
] /* considered_access_paths */
@@ -2652,6 +3013,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
"original_condition": null,
"attached_conditions": [
{
+ "database": "",
"table": "",
"attached": null
}
@@ -2763,6 +3125,7 @@ concat(c1,'y') IN
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -2774,13 +3137,15 @@ concat(c1,'y') IN
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2796,6 +3161,7 @@ concat(c1,'y') IN
"original_condition": "(<in_optimizer>(concat(`test`.`t1`.`c1`,'x'),concat(`test`.`t1`.`c1`,'x') in (/* select#2 */ select left(`test`.`t2`.`c2`,8) from `test`.`t2`)) and <in_optimizer>(concat(`test`.`t1`.`c1`,'y'),concat(`test`.`t1`.`c1`,'y') in (/* select#3 */ select left(`test`.`t2`.`c2`,9) from `test`.`t2`)))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(<in_optimizer>(concat(`test`.`t1`.`c1`,'x'),concat(`test`.`t1`.`c1`,'x') in (/* select#2 */ select left(`test`.`t2`.`c2`,8) from `test`.`t2`)) and <in_optimizer>(concat(`test`.`t1`.`c1`,'y'),concat(`test`.`t1`.`c1`,'y') in (/* select#3 */ select left(`test`.`t2`.`c2`,9) from `test`.`t2`)))"
}
@@ -2830,6 +3196,7 @@ concat(c1,'y') IN
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -2841,13 +3208,15 @@ concat(c1,'y') IN
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2863,6 +3232,7 @@ concat(c1,'y') IN
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": null
}
@@ -2881,6 +3251,7 @@ concat(c1,'y') IN
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -2892,13 +3263,15 @@ concat(c1,'y') IN
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0051,
"chosen": true
}
] /* considered_access_paths */
@@ -2914,6 +3287,7 @@ concat(c1,'y') IN
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": null
}
@@ -2958,6 +3332,20 @@ select * from t1,t2 {
"t2"
] /* constant_tables */,
"records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ }
] /* records_estimation */
},
{
@@ -3075,6 +3463,28 @@ trace
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
+ "table": "t3",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
"table": "t4",
"table_scan": {
"records": 2,
@@ -3086,14 +3496,17 @@ trace
{
"pulled_out_semijoin_tables": [
{
+ "database": "test",
"table": "t2",
"constant": true
},
{
+ "database": "test",
"table": "t1",
"constant": true
},
{
+ "database": "test",
"table": "t4",
"functionally_dependent": true
}
@@ -3102,21 +3515,23 @@ trace
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t4",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "PRIMARY",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 2,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -3179,6 +3594,28 @@ trace
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
+ "table": "t3",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
+ "table": "t1",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
"table": "t4",
"table_scan": {
"records": 2,
@@ -3190,21 +3627,23 @@ trace
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t4",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "PRIMARY",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 2,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -3267,6 +3706,7 @@ select * from t1 left join t2 on t2.a=50
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -3274,6 +3714,7 @@ select * from t1 left join t2 on t2.a=50
} /* table_scan */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 2,
@@ -3285,13 +3726,15 @@ select * from t1 left join t2 on t2.a=50
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0034,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0034,
"chosen": true
}
] /* considered_access_paths */
@@ -3300,13 +3743,14 @@ select * from t1 left join t2 on t2.a=50
"records_for_plan": 2,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 4.0068,
+ "access_type": "scan",
"records": 2,
+ "cost": 4.0068,
"chosen": true
}
] /* considered_access_paths */
@@ -3324,10 +3768,12 @@ select * from t1 left join t2 on t2.a=50
"original_condition": "isnull(`test`.`t2`.`a`)",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
},
{
+ "database": "test",
"table": "t2",
"attached": "(trigcond_if(found_match(t2), isnull(`test`.`t2`.`a`), true) and trigcond_if(is_not_null_compl(t2), (`test`.`t2`.`a` = 500), true))"
}
@@ -3413,6 +3859,7 @@ select * from t1 where (t1.a,t1.b) not i
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -3424,13 +3871,15 @@ select * from t1 where (t1.a,t1.b) not i
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0044,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0044,
"chosen": true
}
] /* considered_access_paths */
@@ -3446,6 +3895,7 @@ select * from t1 where (t1.a,t1.b) not i
"original_condition": "(not(<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`b`),<exists>(/* select#2 */ select `test`.`t2`.`c`,`test`.`t2`.`d` from `test`.`t2` where ((`test`.`t2`.`c` > 0) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`c`) or isnull(`test`.`t2`.`c`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`b`) = `test`.`t2`.`d`) or isnull(`test`.`t2`.`d`)), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`c`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`d`), true))))))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(not(<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`b`),<exists>(/* select#2 */ select `test`.`t2`.`c`,`test`.`t2`.`d` from `test`.`t2` where ((`test`.`t2`.`c` > 0) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`c`) or isnull(`test`.`t2`.`c`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`b`) = `test`.`t2`.`d`) or isnull(`test`.`t2`.`d`)), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`c`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`d`), true))))))"
}
@@ -3485,6 +3935,7 @@ select * from t1 where (t1.a,t1.b) not i
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 2,
@@ -3496,13 +3947,15 @@ select * from t1 where (t1.a,t1.b) not i
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0044,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0044,
"chosen": true
}
] /* considered_access_paths */
@@ -3518,6 +3971,7 @@ select * from t1 where (t1.a,t1.b) not i
"original_condition": "((`test`.`t2`.`c` > 0) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`c`) or isnull(`test`.`t2`.`c`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`b`) = `test`.`t2`.`d`) or isnull(`test`.`t2`.`d`)), true))",
"attached_conditions": [
{
+ "database": "test",
"table": "t2",
"attached": "((`test`.`t2`.`c` > 0) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`c`) or isnull(`test`.`t2`.`c`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`b`) = `test`.`t2`.`d`) or isnull(`test`.`t2`.`d`)), true))"
}
@@ -3578,6 +4032,7 @@ trace
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -3585,6 +4040,7 @@ trace
} /* table_scan */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 2,
@@ -3596,14 +4052,17 @@ trace
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0044,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
- "chosen": true
+ "cost": 2.0044,
+ "chosen": true,
+ "use_temp_table": true
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -3611,13 +4070,15 @@ trace
"records_for_plan": 2,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0045,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0045,
"chosen": true
}
] /* considered_access_paths */
@@ -3629,13 +4090,15 @@ trace
] /* rest_of_plan */
},
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0044,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0044,
"chosen": true
}
] /* considered_access_paths */
@@ -3651,10 +4114,12 @@ trace
"original_condition": "(`test`.`t2`.`c` > -(1))",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
},
{
+ "database": "test",
"table": "t2",
"attached": "(`test`.`t2`.`c` > -(1))"
}
@@ -3720,6 +4185,59 @@ update D set d=5 where D is NULL {
"steps": [
{
"expanded_query": "/* select#1 */ select `d` AS `d` from `test`.`D` where isnull(`D`)"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no_join"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "NULL <= d <= NULL"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "d",
+ "records": 1,
+ "ranges": [
+ "NULL <= d <= NULL"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 1,
+ "cost_of_plan": 2.21,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -3730,6 +4248,55 @@ delete from D where d=5 {
"steps": [
{
"expanded_query": "/* select#1 */ select from dual where (`d` = 5)"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 2,
+ "cost": 4.5034
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no_join"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "5 <= d <= 5"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "d",
+ "records": 1,
+ "ranges": [
+ "5 <= d <= 5"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 1,
+ "cost_of_plan": 2.21,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -3780,23 +4347,67 @@ insert into D select * from D where D>7
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7051
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.6465,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "7 < d"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 2,
+ "cost": 3.41,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
}
] /* records_estimation */
},
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.2051,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.2051,
"chosen": true
}
] /* considered_access_paths */
@@ -3812,6 +4423,7 @@ insert into D select * from D where D>7
"original_condition": "(`test`.`D`.`d` > 7)",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(`test`.`D`.`d` > 7)"
}
@@ -3861,23 +4473,80 @@ update C,D set D.d=D.d+C.c+4-C.c-4 where
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_single_table"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "7000 < d"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": false,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "d",
+ "records": 1,
+ "ranges": [
+ "7000 < d"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 1,
+ "cost_of_plan": 2.21,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
}
] /* records_estimation */
},
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.21,
+ "access_type": "range",
"records": 1,
+ "cost": 2.21,
"chosen": true
}
] /* considered_access_paths */
@@ -3893,6 +4562,7 @@ update C,D set D.d=D.d+C.c+4-C.c-4 where
"original_condition": "(`test`.`D`.`d` > 7000)",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(`test`.`D`.`d` > 7000)"
}
@@ -3942,23 +4612,74 @@ delete D from C,D where D>7000 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
+ "table": "C",
+ "records": 1,
+ "cost": 1,
+ "cause": "system_table"
+ },
+ {
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.8698,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_single_table"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "7000 < d"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
}
] /* records_estimation */
},
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.6068,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 1,
+ "cost": 2.6068,
"chosen": true
}
] /* considered_access_paths */
@@ -3974,6 +4695,7 @@ delete D from C,D where D>7000 {
"original_condition": "(`test`.`D`.`d` > 7000)",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(`test`.`D`.`d` > 7000)"
}
@@ -4157,6 +4879,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -4168,13 +4891,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -4190,6 +4915,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -4229,6 +4955,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -4240,13 +4967,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -4262,6 +4991,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -4298,6 +5028,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -4309,13 +5040,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -4331,6 +5064,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -4411,12 +5145,55 @@ select * from D where d in (select f1()
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.8698,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_single_table"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "3 <= d <= 3"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 3,
@@ -4435,13 +5212,15 @@ select * from D where d in (select f1()
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0212,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0212,
"chosen": true
}
] /* considered_access_paths */
@@ -4460,13 +5239,15 @@ select * from D where d in (select f1()
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0212,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0212,
"chosen": true
}
] /* considered_access_paths */
@@ -4477,20 +5258,22 @@ select * from D where d in (select f1()
] /* semijoin_strategy_choice */,
"rest_of_plan": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 3,
"records": 1,
+ "cost": 3,
"chosen": true
},
{
- "access_type": "table scan",
- "cost": 2.6076,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 1,
+ "cost": 2.6076,
"chosen": true
}
] /* considered_access_paths */
@@ -4511,21 +5294,23 @@ select * from D where d in (select f1()
] /* rest_of_plan */
},
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 4,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -4535,13 +5320,15 @@ select * from D where d in (select f1()
] /* semijoin_strategy_choice */,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0213,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0213,
"chosen": true
}
] /* considered_access_paths */
@@ -4555,13 +5342,15 @@ select * from D where d in (select f1()
"cause": "join_buffering_not_possible",
"tables": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0213,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0213,
"chosen": true
}
] /* considered_access_paths */
@@ -4597,13 +5386,14 @@ select * from D where d in (select f1()
{
"reconsidering_access_paths_for_semijoin": {
"strategy": "FirstMatch",
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0212,
+ "access_type": "scan",
"records": 3,
+ "cost": 2.0212,
"chosen": true
}
] /* considered_access_paths */
@@ -4615,10 +5405,12 @@ select * from D where d in (select f1()
"original_condition": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(`test`.`D`.`d` = `f1`())"
},
{
+ "database": "test",
"table": "t2",
"attached": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))"
}
@@ -4641,6 +5433,14 @@ delete from t1 where id="z" {
"steps": [
{
"expanded_query": "/* select#1 */ select from dual where (`id` = 'z')"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -4665,6 +5465,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -4676,13 +5477,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -4698,6 +5501,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -4718,6 +5522,14 @@ delete from t1 where id="z" {
"steps": [
{
"expanded_query": "/* select#1 */ select from dual where (`id` = 'z')"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -4771,10 +5583,36 @@ select d+1 into res from D where d= NAME
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.8698,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -4814,6 +5652,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -4825,13 +5664,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -4847,6 +5688,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -4919,10 +5761,36 @@ select @trace;
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.8698,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "impossible_condition": {
+ "table": "D",
+ "field": "d",
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
}
] /* records_estimation */
}
@@ -5022,12 +5890,55 @@ select d into res from D where d in (sel
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "D",
- "more_range_optimizer_trace": {
- "TODO?": "yes!"
- } /* more_range_optimizer_trace */
+ "range_analysis": {
+ "table_scan": {
+ "records": 4,
+ "cost": 4.9068
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "d",
+ "usable": true,
+ "key_parts": [
+ "d"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "d",
+ "cost": 1.8698,
+ "chosen": true
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_single_table"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "3 <= d <= 3"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */
+ } /* range_analysis */
},
{
+ "database": "test",
"table": "t2",
"table_scan": {
"records": 7,
@@ -5046,13 +5957,15 @@ select d into res from D where d in (sel
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0496,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 7,
+ "cost": 2.0496,
"chosen": true
}
] /* considered_access_paths */
@@ -5071,21 +5984,23 @@ select d into res from D where d in (sel
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "D",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "index",
"index": "d",
- "cost": 1,
"records": 1,
+ "cost": 1,
"chosen": true
},
{
- "access_type": "table scan",
+ "access_type": "scan",
"cost": 2,
"records": 4,
- "chosen": false
+ "chosen": false,
+ "cause": "index_cheaper"
}
] /* considered_access_paths */
} /* best_access_path */,
@@ -5095,13 +6010,15 @@ select d into res from D where d in (sel
] /* semijoin_strategy_choice */,
"rest_of_plan": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0496,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 7,
+ "cost": 2.0496,
"chosen": true
}
] /* considered_access_paths */
@@ -5115,13 +6032,15 @@ select d into res from D where d in (sel
"cause": "join_buffering_not_possible",
"tables": [
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0496,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 7,
+ "cost": 2.0496,
"chosen": true
}
] /* considered_access_paths */
@@ -5153,13 +6072,15 @@ select d into res from D where d in (sel
] /* rest_of_plan */
},
{
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0496,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 7,
+ "cost": 2.0496,
"chosen": true
}
] /* considered_access_paths */
@@ -5175,13 +6096,14 @@ select d into res from D where d in (sel
{
"reconsidering_access_paths_for_semijoin": {
"strategy": "FirstMatch",
+ "database": "test",
"table": "t2",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0496,
+ "access_type": "scan",
"records": 7,
+ "cost": 2.0496,
"chosen": true
}
] /* considered_access_paths */
@@ -5193,10 +6115,12 @@ select d into res from D where d in (sel
"original_condition": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))",
"attached_conditions": [
{
+ "database": "test",
"table": "D",
"attached": "(`test`.`D`.`d` = `f1`())"
},
{
+ "database": "test",
"table": "t2",
"attached": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))"
}
@@ -5219,6 +6143,14 @@ delete from t1 where id="z" {
"steps": [
{
"expanded_query": "/* select#1 */ select from dual where (`id` = 'z')"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -5243,6 +6175,7 @@ select sum(data) into ret from t1 {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -5254,13 +6187,15 @@ select sum(data) into ret from t1 {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -5276,6 +6211,7 @@ select sum(data) into ret from t1 {
"original_condition": null,
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": null
}
@@ -5347,6 +6283,7 @@ explain select * from v1 where id="b" {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 2,
@@ -5358,13 +6295,15 @@ explain select * from v1 where id="b" {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -5380,6 +6319,7 @@ explain select * from v1 where id="b" {
"original_condition": "(`test`.`t1`.`id` = 'b')",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(`test`.`t1`.`id` = 'b')"
}
@@ -5424,6 +6364,14 @@ delete from v1 where data=100 {
},
{
"expanded_query": "/* select#1 */ select from dual where (`data` = 100)"
+ },
+ {
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
}
] /* steps */
} 0 0
@@ -5477,6 +6425,7 @@ explain select * from v1 where id="b" {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "test",
"table": "t1",
"table_scan": {
"records": 3,
@@ -5488,13 +6437,15 @@ explain select * from v1 where id="b" {
{
"considered_execution_plans": [
{
+ "database": "test",
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 2.0154,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 3,
+ "cost": 2.0154,
"chosen": true
}
] /* considered_access_paths */
@@ -5510,6 +6461,7 @@ explain select * from v1 where id="b" {
"original_condition": "(`test`.`t1`.`id` < 'c')",
"attached_conditions": [
{
+ "database": "test",
"table": "t1",
"attached": "(`test`.`t1`.`id` < 'c')"
}
@@ -5548,6 +6500,7 @@ explain select * from v1 where id="b" {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "",
"table": "v1",
"table_scan": {
"records": 2,
@@ -5559,13 +6512,15 @@ explain select * from v1 where id="b" {
{
"considered_execution_plans": [
{
+ "database": "",
"table": "v1",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10.1,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 10.1,
"chosen": true
}
] /* considered_access_paths */
@@ -5581,6 +6536,7 @@ explain select * from v1 where id="b" {
"original_condition": "(`v1`.`id` = 'b')",
"attached_conditions": [
{
+ "database": "",
"table": "v1",
"attached": "(`v1`.`id` = 'b')"
}
@@ -5634,6 +6590,7 @@ VARIABLE_NAME="optimizer_trace" {
] /* constant_tables */,
"records_estimation": [
{
+ "database": "information_schema",
"table": "SESSION_VARIABLES",
"table_scan": {
"records": 2,
@@ -5645,13 +6602,15 @@ VARIABLE_NAME="optimizer_trace" {
{
"considered_execution_plans": [
{
+ "database": "information_schema",
"table": "SESSION_VARIABLES",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10.1,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 10.1,
"chosen": true
}
] /* considered_access_paths */
@@ -5667,6 +6626,7 @@ VARIABLE_NAME="optimizer_trace" {
"original_condition": "(`information_schema`.`SESSION_VARIABLES`.`VARIABLE_NAME` = 'optimizer_trace')",
"attached_conditions": [
{
+ "database": "information_schema",
"table": "SESSION_VARIABLES",
"attached": "(`information_schema`.`SESSION_VARIABLES`.`VARIABLE_NAME` = 'optimizer_trace')"
}
@@ -5733,6 +6693,7 @@ select TRACE into dumpfile 'MYSQLTEST_VA
],
"records_estimation": [
{
+ "database": "",
"table": "",
"table_scan": {
"records": 2,
@@ -5744,13 +6705,15 @@ select TRACE into dumpfile 'MYSQLTEST_VA
{
"considered_execution_plans": [
{
+ "database": "",
"table": "",
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "table scan",
- "cost": 10.1,
+ "access_type": "scan",
+ "using_join_cache": true,
"records": 2,
+ "cost": 10.1,
"chosen": true
}
]
@@ -5766,6 +6729,7 @@ select TRACE into dumpfile 'MYSQLTEST_VA
"original_condition": null,
"attached_conditions": [
{
+ "database": "",
"table": "",
"attached": null
}
=== added file 'mysql-test/r/optimizer_trace_range.result'
--- a/mysql-test/r/optimizer_trace_range.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_trace_range.result 2010-10-22 08:31:43 +0000
@@ -0,0 +1,2112 @@
+SET optimizer_trace_max_mem_size=1048576;
+SET optimizer_trace="enabled=on,end_marker=on,one_line=off";
+CREATE TABLE t1
+(
+key1 INT NOT NULL,
+INDEX i1(key1)
+);
+Inserting 1024 records into t1
+ALTER TABLE t1 ADD key2 INT NOT NULL, ADD INDEX i2(key2);
+ALTER TABLE t1 ADD key3 INT NOT NULL, ADD INDEX i3(key3);
+ALTER TABLE t1 ADD key4 INT NOT NULL, ADD INDEX i4(key4);
+ALTER TABLE t1 ADD key5 INT NOT NULL, ADD INDEX i5(key5);
+ALTER TABLE t1 ADD key6 INT NOT NULL, ADD INDEX i6(key6);
+ALTER TABLE t1 ADD key7 INT NOT NULL, ADD INDEX i7(key7);
+ALTER TABLE t1 ADD key8 INT NOT NULL, ADD INDEX i8(key8);
+UPDATE t1 SET
+key2=key1,
+key3=key1,
+key4=key1,
+key5=key1,
+key6=key1,
+key7=key1,
+key8=1024-key1;
+CREATE TABLE t2 (
+key1a INT NOT NULL,
+key1b INT NOT NULL,
+key2 INT NOT NULL,
+key2_1 INT NOT NULL,
+key2_2 INT NOT NULL,
+key3 INT NOT NULL,
+primary key i1a (key1a, key1b),
+INDEX i1b (key1b, key1a),
+INDEX i2_1(key2, key2_1),
+INDEX i2_2(key2, key2_1)
+);
+INSERT INTO t2 SELECT key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 FROM t1;
+
+EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range i2 i2 4 NULL 47 Using index condition; Using MRR
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key2` < 5) or (`key2` > 1020))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))",
+ "after_equality_propagation": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))",
+ "after_constant_propagation": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))",
+ "after_trivial_conditions_removal": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 217.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "i1",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2",
+ "usable": true,
+ "key_parts": [
+ "key2"
+ ] /* key_parts */
+ },
+ {
+ "index": "i3",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i4",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i5",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i6",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i7",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i8",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "i2",
+ "ranges": [
+ "key2 < 5",
+ "1020 < key2"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 47,
+ "cost": 58.41,
+ "rowid_ordered": false,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "i2",
+ "records": 47,
+ "ranges": [
+ "key2 < 5",
+ "1020 < key2"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 47,
+ "cost_of_plan": 58.41,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "records": 47,
+ "cost": 58.41,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 58.41,
+ "records_for_plan": 47,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "((`test`.`t1`.`key2` < 5) or (`test`.`t1`.`key2` > 1020))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 45 Using sort_union(i1,i2); Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key1` < 3) or (`key2` > 1020))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+ "after_equality_propagation": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+ "after_constant_propagation": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+ "after_trivial_conditions_removal": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 217.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "i1",
+ "usable": true,
+ "key_parts": [
+ "key1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2",
+ "usable": true,
+ "key_parts": [
+ "key2"
+ ] /* key_parts */
+ },
+ {
+ "index": "i3",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i4",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i5",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i6",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i7",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i8",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_index_merge": [
+ {
+ "indices_to_merge": [
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i1",
+ "ranges": [
+ "key1 < 3"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 3,
+ "cost": 1.6526,
+ "rowid_ordered": false,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "index_to_merge": "i1",
+ "cumulated_cost": 1.6526
+ },
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i2",
+ "ranges": [
+ "1020 < key2"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 42,
+ "cost": 10.282,
+ "rowid_ordered": false,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "index_to_merge": "i2",
+ "cumulated_cost": 11.935
+ }
+ ] /* indices_to_merge */,
+ "cost_of_reading_ranges": 11.935,
+ "cost_sort_rowid_and_read_disk": 8.0666,
+ "cost_duplicate_removal": 38.361,
+ "total_cost": 58.363
+ }
+ ] /* analyzing_index_merge */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "index_merge",
+ "index_merge_of": [
+ {
+ "type": "range_scan",
+ "index": "i1",
+ "records": 3,
+ "ranges": [
+ "key1 < 3"
+ ] /* ranges */
+ },
+ {
+ "type": "range_scan",
+ "index": "i2",
+ "records": 42,
+ "ranges": [
+ "1020 < key2"
+ ] /* ranges */
+ }
+ ] /* index_merge_of */
+ } /* range_access_plan */,
+ "records_in_plan": 45,
+ "cost_of_plan": 58.363,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "records": 45,
+ "cost": 58.363,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 58.363,
+ "records_for_plan": 45,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL i2_1 4 NULL 103 Using index for group-by
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `key2` AS `key2`,min(`key2_1`) AS `MIN(key2_1)` from `test`.`t2` group by `key2`"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t2",
+ "const_keys_added": {
+ "keys": [
+ "i2_1",
+ "i2_2"
+ ] /* keys */,
+ "cause": "group_by"
+ } /* const_keys_added */,
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 215.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2_1",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2_2",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "i2_1",
+ "cost": 235.03,
+ "chosen": false,
+ "cause": "cost"
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "potential_group_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "covering": false
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "covering": false
+ },
+ {
+ "index": "i2_1",
+ "covering": true,
+ "records": 103,
+ "cost": 50.6
+ },
+ {
+ "index": "i2_2",
+ "covering": true,
+ "records": 103,
+ "cost": 50.6
+ }
+ ] /* potential_group_range_indices */
+ } /* group_index_range */,
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "i2_1",
+ "group_attribute": "key2_1",
+ "min_aggregate": true,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "key_parts_used_for_access": 1,
+ "records": 103,
+ "cost": 50.6,
+ "ranges": [
+ ] /* ranges */,
+ "chosen": true
+ } /* best_group_range_summary */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "index_group",
+ "index": "i2_1",
+ "group_attribute": "key2_1",
+ "min_aggregate": true,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "key_parts_used_for_access": 1,
+ "records": 103,
+ "cost": 50.6,
+ "ranges": [
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 103,
+ "cost_of_plan": 50.6,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "records": 103,
+ "cost": 50.6,
+ "chosen": true,
+ "use_temp_table": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 50.6,
+ "records_for_plan": 103,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": null
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 where key2 < 5 GROUP BY key2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range i2_1,i2_2 i2_1 4 NULL 47 Using where; Using index
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 where key2 < 5 GROUP BY key2 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `key2` AS `key2`,min(`key2_1`) AS `MIN(key2_1)` from `test`.`t2` where (`key2` < 5) group by `key2`"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t2`.`key2` < 5)",
+ "after_equality_propagation": "(`test`.`t2`.`key2` < 5)",
+ "after_constant_propagation": "(`test`.`t2`.`key2` < 5)",
+ "after_trivial_conditions_removal": "(`test`.`t2`.`key2` < 5)"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t2",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 215.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2_1",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2_2",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "best_covering_index_scan": {
+ "index": "i2_1",
+ "cost": 235.03,
+ "chosen": false,
+ "cause": "cost"
+ } /* best_covering_index_scan */,
+ "group_index_range": {
+ "potential_group_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "covering": false
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "covering": false
+ },
+ {
+ "index": "i2_1",
+ "covering": true,
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */,
+ "records": 5,
+ "cost": 31
+ },
+ {
+ "index": "i2_2",
+ "covering": true,
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */,
+ "records": 5,
+ "cost": 31
+ }
+ ] /* potential_group_range_indices */
+ } /* group_index_range */,
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "i2_1",
+ "group_attribute": "key2_1",
+ "min_aggregate": true,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "key_parts_used_for_access": 1,
+ "records": 5,
+ "cost": 31,
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */,
+ "chosen": true
+ } /* best_group_range_summary */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "i2_1",
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 47,
+ "cost": 11.724,
+ "rowid_ordered": false,
+ "chosen": true
+ },
+ {
+ "index": "i2_2",
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 47,
+ "cost": 11.724,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "i2_1",
+ "records": 47,
+ "ranges": [
+ "key2 < 5"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 47,
+ "cost_of_plan": 11.724,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "records": 5,
+ "cost": 20.124,
+ "chosen": true,
+ "use_temp_table": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 20.124,
+ "records_for_plan": 5,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t2`.`key2` < 5)",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "(`test`.`t2`.`key2` < 5)"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref i2_1,i2_2 i2_1 4 const 10 Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5) {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t2` where ((`key2` = 1) and ((`key2_1` = 1) or (`key3` = 5)))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t2`.`key2` = 1) and ((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5)))",
+ "after_equality_propagation": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))",
+ "after_constant_propagation": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))",
+ "after_trivial_conditions_removal": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ {
+ "condition": "t2.key2= 1",
+ "null_rejecting": false
+ },
+ {
+ "condition": "t2.key2= 1",
+ "null_rejecting": false
+ }
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t2",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 215.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2_1",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2_2",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "i2_1",
+ "ranges": [
+ "1 <= key2 <= 1"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 10,
+ "cost": 13.01,
+ "rowid_ordered": false,
+ "chosen": true
+ },
+ {
+ "index": "i2_2",
+ "ranges": [
+ "1 <= key2 <= 1"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 10,
+ "cost": 13.01,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "i2_1",
+ "records": 10,
+ "ranges": [
+ "1 <= key2 <= 1"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 10,
+ "cost_of_plan": 13.01,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "index",
+ "index": "i2_1",
+ "records": 10,
+ "cost": 10,
+ "chosen": true
+ },
+ {
+ "access_type": "index",
+ "index": "i2_2",
+ "records": 10,
+ "cost": 10,
+ "chosen": false
+ },
+ {
+ "access_type": "range",
+ "chosen": false,
+ "cause": "heuristic_index_must_be_cheaper"
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 10,
+ "records_for_plan": 10,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t2`.`key2` = 1) and ((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5)))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key2` = 10) or (`key3` = 3) or (`key4` <=> NULL))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))",
+ "after_equality_propagation": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))",
+ "after_constant_propagation": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))",
+ "after_trivial_conditions_removal": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 217.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "i1",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2",
+ "usable": true,
+ "key_parts": [
+ "key2"
+ ] /* key_parts */
+ },
+ {
+ "index": "i3",
+ "usable": true,
+ "key_parts": [
+ "key3"
+ ] /* key_parts */
+ },
+ {
+ "index": "i4",
+ "usable": true,
+ "key_parts": [
+ "key4"
+ ] /* key_parts */
+ },
+ {
+ "index": "i5",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i6",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i7",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i8",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "impossible_condition": {
+ "table": "t1",
+ "field": "key4",
+ "cause": "null_field_in_non_null_column"
+ } /* impossible_condition */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_index_merge": [
+ {
+ "indices_to_merge": [
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i2",
+ "ranges": [
+ "10 <= key2 <= 10"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "index_to_merge": "i2",
+ "cumulated_cost": 2.21
+ },
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i3",
+ "ranges": [
+ "3 <= key3 <= 3"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "index_to_merge": "i3",
+ "cumulated_cost": 4.42
+ }
+ ] /* indices_to_merge */,
+ "cost_of_reading_ranges": 4.42,
+ "use_roworder_union": true,
+ "cause": "always_cheaper_than_not_roworder_retrieval",
+ "analyzing_roworder_scans": [
+ {
+ "type": "range_scan",
+ "index": "i2",
+ "records": 1,
+ "ranges": [
+ "10 <= key2 <= 10"
+ ] /* ranges */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ },
+ {
+ "type": "range_scan",
+ "index": "i3",
+ "records": 1,
+ "ranges": [
+ "3 <= key3 <= 3"
+ ] /* ranges */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ }
+ ] /* analyzing_roworder_scans */,
+ "index_roworder_union_cost": 6.327,
+ "members": 2,
+ "chosen": true
+ }
+ ] /* analyzing_index_merge */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "index_roworder_union",
+ "union_of": [
+ {
+ "type": "range_scan",
+ "index": "i2",
+ "records": 1,
+ "ranges": [
+ "10 <= key2 <= 10"
+ ] /* ranges */
+ },
+ {
+ "type": "range_scan",
+ "index": "i3",
+ "records": 1,
+ "ranges": [
+ "3 <= key3 <= 3"
+ ] /* ranges */
+ }
+ ] /* union_of */
+ } /* range_access_plan */,
+ "records_in_plan": 2,
+ "cost_of_plan": 6.327,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "records": 2,
+ "cost": 6.327,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 6.327,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL i2_1,i2_2 NULL NULL NULL 1024 Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t2` where ((`key2_1` < 79) or (`key2` = 2))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))",
+ "after_equality_propagation": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))",
+ "after_constant_propagation": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))",
+ "after_trivial_conditions_removal": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t2",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 215.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i1b",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2_1",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2_2",
+ "usable": true,
+ "key_parts": [
+ "key2",
+ "key2_1"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "range_scan_possible": false,
+ "cause": "condition_always_true",
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 1024,
+ "cost": 8.25,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 8.25,
+ "records_for_plan": 1024,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range PRIMARY,i1b PRIMARY 8 NULL 1 Using index condition; Using MRR
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10 {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t2` where ((`key1a` = 5) and (`key1b` < 10))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t2`.`key1a` = 5) and (`test`.`t2`.`key1b` < 10))",
+ "after_equality_propagation": "((`test`.`t2`.`key1b` < 10) and multiple equal(5, `test`.`t2`.`key1a`))",
+ "after_constant_propagation": "((`test`.`t2`.`key1b` < 10) and multiple equal(5, `test`.`t2`.`key1a`))",
+ "after_trivial_conditions_removal": "((`test`.`t2`.`key1b` < 10) and multiple equal(5, `test`.`t2`.`key1a`))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ {
+ "condition": "t2.key1a= 5",
+ "null_rejecting": false
+ }
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t2",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 215.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "PRIMARY",
+ "usable": true,
+ "key_parts": [
+ "key1a",
+ "key1b"
+ ] /* key_parts */
+ },
+ {
+ "index": "i1b",
+ "usable": true,
+ "key_parts": [
+ "key1b",
+ "key1a"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2_1",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i2_2",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "PRIMARY",
+ "ranges": [
+ "5 <= key1a <= 5 : key1b < 10"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": false,
+ "chosen": true
+ },
+ {
+ "index": "i1b",
+ "ranges": [
+ "key1b < 10"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 9,
+ "cost": 11.81,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "PRIMARY",
+ "records": 1,
+ "ranges": [
+ "5 <= key1a <= 5 : key1b < 10"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 1,
+ "cost_of_plan": 2.21,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "index",
+ "index": "PRIMARY",
+ "records": 10,
+ "cost": 10.24,
+ "chosen": true
+ },
+ {
+ "access_type": "range",
+ "records": 1,
+ "cost": 2.21,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.21,
+ "records_for_plan": 1,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t2`.`key1a` = 5) and (`test`.`t2`.`key1b` < 10))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "((`test`.`t2`.`key1a` = 5) and (`test`.`t2`.`key1b` < 10))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL i1,i2 NULL NULL NULL 1024 Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2) {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key1` > 1) or (`key2` > 2))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+ "after_equality_propagation": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+ "after_constant_propagation": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+ "after_trivial_conditions_removal": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 1024,
+ "cost": 217.15
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "i1",
+ "usable": true,
+ "key_parts": [
+ "key1"
+ ] /* key_parts */
+ },
+ {
+ "index": "i2",
+ "usable": true,
+ "key_parts": [
+ "key2"
+ ] /* key_parts */
+ },
+ {
+ "index": "i3",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i4",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i5",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i6",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i7",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ },
+ {
+ "index": "i8",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_index_merge": [
+ {
+ "indices_to_merge": [
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i1",
+ "ranges": [
+ "1 < key1"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1023,
+ "cost": 227.35,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "chosen": false,
+ "cause": "cost"
+ },
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "i2",
+ "ranges": [
+ "2 < key2"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 1022,
+ "cost": 227.13,
+ "rowid_ordered": false,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* indices_to_merge */,
+ "cost_of_reading_ranges": 0,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* analyzing_index_merge */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 1024,
+ "cost": 10.25,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 10.25,
+ "records_for_plan": 1024,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+DROP TABLE t1,t2;
+CREATE TABLE t1 (
+cola char(3) not null,
+colb char(3) not null,
+filler char(200),
+key(cola),
+key(colb)
+);
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+Inserting records
+
+EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 32 Using intersect(cola,colb); Using where
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`cola` = 'foo') and (`colb` = 'bar'))"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "((`test`.`t1`.`cola` = 'foo') and (`test`.`t1`.`colb` = 'bar'))",
+ "after_equality_propagation": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))",
+ "after_constant_propagation": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))",
+ "after_trivial_conditions_removal": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ {
+ "condition": "t1.cola= 'foo'",
+ "null_rejecting": false
+ },
+ {
+ "condition": "t1.colb= 'bar'",
+ "null_rejecting": false
+ }
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 8704,
+ "cost": 2184.8
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "cola",
+ "usable": true,
+ "key_parts": [
+ "cola"
+ ] /* key_parts */
+ },
+ {
+ "index": "colb",
+ "usable": true,
+ "key_parts": [
+ "colb"
+ ] /* key_parts */
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "cola",
+ "ranges": [
+ "foo <= cola <= foo"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 533,
+ "cost": 640.61,
+ "rowid_ordered": true,
+ "chosen": true
+ },
+ {
+ "index": "colb",
+ "ranges": [
+ "bar <= colb <= bar"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 533,
+ "cost": 640.61,
+ "rowid_ordered": true,
+ "chosen": false,
+ "cause": "cost"
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "intersecting_indices": [
+ {
+ "index": "cola",
+ "used_in_intersect": true,
+ "matching_records_now": 533,
+ "cumulated_cost": 320.38,
+ "isect_covering_with_this_index": false
+ },
+ {
+ "index": "colb",
+ "used_in_intersect": true,
+ "matching_records_now": 32.639,
+ "cumulated_cost": 53.359,
+ "isect_covering_with_this_index": false
+ }
+ ] /* intersecting_indices */,
+ "clustered_pk": {
+ "cpk_added_to_intersect": false,
+ "cause": "no_clustered_pk_index"
+ } /* clustered_pk */,
+ "records": 32,
+ "cost": 53.359,
+ "covering": false,
+ "chosen": true
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "index_roworder_intersect",
+ "records": 32,
+ "cost": 53.359,
+ "covering": false,
+ "cpk_scan": false,
+ "intersect_of": [
+ {
+ "type": "range_scan",
+ "index": "cola",
+ "records": 533,
+ "ranges": [
+ "foo <= cola <= foo"
+ ] /* ranges */
+ },
+ {
+ "type": "range_scan",
+ "index": "colb",
+ "records": 533,
+ "ranges": [
+ "bar <= colb <= bar"
+ ] /* ranges */
+ }
+ ] /* intersect_of */
+ } /* range_access_plan */,
+ "records_in_plan": 32,
+ "cost_of_plan": 53.359,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "index",
+ "index": "cola",
+ "records": 533,
+ "cost": 533,
+ "chosen": true
+ },
+ {
+ "access_type": "index",
+ "index": "colb",
+ "records": 533,
+ "cost": 533,
+ "chosen": false
+ },
+ {
+ "access_type": "range",
+ "records": 24,
+ "cost": 54.959,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 54.959,
+ "records_for_plan": 24,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "((`test`.`t1`.`colb` = 'bar') and (`test`.`t1`.`cola` = 'foo'))",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "((`test`.`t1`.`colb` = 'bar') and (`test`.`t1`.`cola` = 'foo'))"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+
+EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref cola cola 3 const 1 Using index condition
+
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE OS_MALLOC_ERROR
+EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no' {
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where (`cola` = 'f\\no')"
+ },
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t1`.`cola` = 'f\\no')",
+ "after_equality_propagation": "multiple equal('f\\no', `test`.`t1`.`cola`)",
+ "after_constant_propagation": "multiple equal('f\\no', `test`.`t1`.`cola`)",
+ "after_trivial_conditions_removal": "multiple equal('f\\no', `test`.`t1`.`cola`)"
+ } /* condition_processing */
+ },
+ {
+ "ref-optimizer-key-uses": [
+ {
+ "condition": "t1.cola= 'f\\no'",
+ "null_rejecting": false
+ }
+ ] /* ref-optimizer-key-uses */
+ },
+ {
+ "constant_tables": [
+ ] /* constant_tables */,
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 8704,
+ "cost": 2184.8
+ } /* table_scan */,
+ "potential_range_indices": [
+ {
+ "index": "cola",
+ "usable": true,
+ "key_parts": [
+ "cola"
+ ] /* key_parts */
+ },
+ {
+ "index": "colb",
+ "usable": false,
+ "cause": "not_usable_by_conditions"
+ }
+ ] /* potential_range_indices */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "cola",
+ "ranges": [
+ "f
+o <= cola <= f
+o"
+ ] /* ranges */,
+ "index_only": false,
+ "records": 1,
+ "cost": 2.21,
+ "rowid_ordered": true,
+ "chosen": true
+ }
+ ] /* range_scan_alternatives */,
+ "analyzing_roworder_intersect": {
+ "usable": false,
+ "cause": "too_few_roworder_scans"
+ } /* analyzing_roworder_intersect */
+ } /* analyzing_range_alternatives */,
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "cola",
+ "records": 1,
+ "ranges": [
+ "f
+o <= cola <= f
+o"
+ ] /* ranges */
+ } /* range_access_plan */,
+ "records_in_plan": 1,
+ "cost_of_plan": 2.21,
+ "chosen": true
+ } /* chosen_range_access_summary */
+ } /* range_analysis */
+ }
+ ] /* records_estimation */
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "database": "test",
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "index",
+ "index": "cola",
+ "records": 1,
+ "cost": 1,
+ "chosen": true
+ },
+ {
+ "access_type": "range",
+ "chosen": false,
+ "cause": "heuristic_index_must_be_cheaper"
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 1,
+ "records_for_plan": 1,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t1`.`cola` = 'f\\no')",
+ "attached_conditions": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "(`test`.`t1`.`cola` = 'f\\no')"
+ }
+ ] /* attached_conditions */
+ } /* attaching_conditions_to_tables */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ }
+ ] /* steps */
+} 0 0
+DROP TABLE t1;
+set optimizer_trace=default;
=== modified file 'mysql-test/t/optimizer_trace_charset.test'
--- a/mysql-test/t/optimizer_trace_charset.test 2010-10-09 15:04:30 +0000
+++ b/mysql-test/t/optimizer_trace_charset.test 2010-10-22 08:31:43 +0000
@@ -32,4 +32,11 @@ select @query, @trace;
drop table t1;
drop view v1;
+
+create table t1(c char(4) primary key);
+insert into t1 values ('aaa'), ('��');
+select * from t1 where c < '���;
+select query, trace from information_schema.OPTIMIZER_TRACE;
+drop table t1;
+
set optimizer_trace=default;
=== added file 'mysql-test/t/optimizer_trace_range.test'
--- a/mysql-test/t/optimizer_trace_range.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_trace_range.test 2010-10-22 08:31:43 +0000
@@ -0,0 +1,158 @@
+# Basic test for optimizer trace
+
+--source include/have_optimizer_trace.inc
+
+SET optimizer_trace_max_mem_size=1048576; # 1MB
+SET optimizer_trace="enabled=on,end_marker=on,one_line=off";
+
+CREATE TABLE t1
+(
+ key1 INT NOT NULL,
+ INDEX i1(key1)
+);
+
+--echo Inserting 1024 records into t1
+
+--disable_query_log
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+
+let $1=7;
+set @d=8;
+while ($1)
+{
+ EVAL INSERT INTO t1 SELECT key1+@d FROM t1;
+ EVAL SET @d=@d*2;
+ DEC $1;
+}
+--enable_query_log
+
+ALTER TABLE t1 ADD key2 INT NOT NULL, ADD INDEX i2(key2);
+ALTER TABLE t1 ADD key3 INT NOT NULL, ADD INDEX i3(key3);
+ALTER TABLE t1 ADD key4 INT NOT NULL, ADD INDEX i4(key4);
+ALTER TABLE t1 ADD key5 INT NOT NULL, ADD INDEX i5(key5);
+ALTER TABLE t1 ADD key6 INT NOT NULL, ADD INDEX i6(key6);
+ALTER TABLE t1 ADD key7 INT NOT NULL, ADD INDEX i7(key7);
+ALTER TABLE t1 ADD key8 INT NOT NULL, ADD INDEX i8(key8);
+
+UPDATE t1 SET
+ key2=key1,
+ key3=key1,
+ key4=key1,
+ key5=key1,
+ key6=key1,
+ key7=key1,
+ key8=1024-key1;
+
+CREATE TABLE t2 (
+ key1a INT NOT NULL,
+ key1b INT NOT NULL,
+ key2 INT NOT NULL,
+ key2_1 INT NOT NULL,
+ key2_2 INT NOT NULL,
+ key3 INT NOT NULL,
+ primary key i1a (key1a, key1b),
+ INDEX i1b (key1b, key1a),
+ INDEX i2_1(key2, key2_1),
+ INDEX i2_2(key2, key2_1)
+);
+
+INSERT INTO t2 SELECT key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 FROM t1;
+
+# multiple ranges on one key
+--echo
+EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+
+# index merge
+--echo
+EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# group without range
+--echo
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# group with range
+--echo
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 where key2 < 5 GROUP BY key2;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+#intersect
+--echo
+EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# union
+--echo
+EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# range_scan_possible=false
+--echo
+EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# Multiple key parts in same index
+--echo
+EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10;
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+# more_expensive_than_table_scan
+--echo
+EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2);
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+DROP TABLE t1,t2;
+
+CREATE TABLE t1 (
+ cola char(3) not null,
+ colb char(3) not null,
+ filler char(200),
+ key(cola),
+ key(colb)
+);
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+
+--echo Inserting records
+--disable_query_log
+let $1=9;
+while ($1)
+{
+ eval INSERT INTO t1 SELECT * FROM t1 WHERE cola = 'foo';
+ dec $1;
+}
+LET $1=13;
+WHILE ($1)
+{
+ eval INSERT INTO t1 SELECT * FROM t1 WHERE cola <> 'foo';
+ dec $1;
+}
+
+--enable_query_log
+
+--echo
+# Index roworder intersect
+EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar';
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+--echo
+# Range with escaped character should be printed escaped
+EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no';
+--echo
+SELECT * FROM information_schema.OPTIMIZER_TRACE;
+
+DROP TABLE t1;
+
+set optimizer_trace=default;
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2010-09-27 09:26:39 +0000
+++ b/sql/handler.cc 2010-10-22 08:31:43 +0000
@@ -4381,14 +4381,7 @@ handler::multi_range_read_info_const(uin
*bufsz= 0;
seq_it= seq->init(seq_init_param, n_ranges, *flags);
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- /*
- Given that this method can be overridden by engines, it doesn't sound
- smart to do tracing here. seq->next() produces tracing when it's equal to
- sel_arg_range_seq_next() (prints the range).
- */
Opt_trace_array ota(thd->opt_trace, "ranges");
-#endif
while (!seq->next(seq_it, &range))
{
if (unlikely(thd->killed != 0))
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2010-09-27 09:26:39 +0000
+++ b/sql/opt_range.cc 2010-10-22 08:31:43 +0000
@@ -30,7 +30,8 @@
and builds lists of intervals (in index/partitioning space), such that
all possible records that match the condition are contained within the
intervals.
- The entry point for the range analysis module is get_mm_tree() function.
+ The entry point for the range analysis module is get_mm_tree()
+ (mm=min_max) function.
The lists are returned in form of complicated structure of interlinked
SEL_TREE/SEL_IMERGE/SEL_ARG objects.
@@ -756,7 +757,7 @@ class TABLE_READ_PLAN;
class TRP_RANGE;
class TRP_ROR_INTERSECT;
class TRP_ROR_UNION;
- class TRP_ROR_INDEX_MERGE;
+ class TRP_INDEX_MERGE;
class TRP_GROUP_MIN_MAX;
struct st_ror_scan_info;
@@ -803,13 +804,12 @@ static void print_ror_scans_arr(TABLE *t
struct st_ror_scan_info **end);
#endif
#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
-#endif
-static void print_range(Opt_trace_context *out, KEY_PART_INFO *key_parts,
- const uchar *min_key, uint16 min_length,
- const uchar *max_key, uint16 max_length,
- uint flag);
+static void append_range(String *out,
+ const KEY_PART_INFO *key_parts,
+ const uchar *min_key, const uint16 min_length,
+ const uchar *max_key, const uint16 max_length,
+ const uint flag);
#endif
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
@@ -1956,12 +1956,68 @@ public:
static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ }
virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */
+#ifdef OPTIMIZER_TRACE
+ /**
+ Add basic info for this TABLE_READ_PLAN to the optimizer trace.
+
+ @param param Parameters for range analysis of this table
+ @param trace_object The optimizer trace object the info is appended to
+ */
+ virtual void trace_basic_info(const PARAM *param,
+ Opt_trace_object *trace_object) const =0;
+#endif
};
-class TRP_ROR_INTERSECT;
-class TRP_ROR_UNION;
-class TRP_INDEX_MERGE;
+/**
+ Print a key into a stream
+ @param[out] out String the key is appended to
+ @param[in] key_part Index components description
+ @param[in] key Key tuple
+ @param[in] used_length Key tuple length
+*/
+static void
+print_key2(String *out, const KEY_PART_INFO *key_part, const uchar *key,
+ uint used_length)
+{
+ const uchar *key_end= key + used_length;
+ String tmp;
+ uint store_length;
+ TABLE *table= key_part->field->table;
+ my_bitmap_map *old_sets[2];
+
+ dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+
+ for (; key < key_end; key+= store_length, key_part++)
+ {
+ Field *field= key_part->field;
+ store_length= key_part->store_length;
+
+ if (field->real_maybe_null())
+ {
+ /* Byte 0 of key is the null-byte. If set, key is NULL.
+ Otherwise, print the key value starting immediately after the
+ null-byte
+ */
+ if (*key)
+ {
+ out->append(STRING_WITH_LEN("NULL"));
+ continue;
+ }
+ key++; // Skip null byte
+ store_length--;
+ }
+ field->set_key_image(key, key_part->length);
+ if (field->type() == MYSQL_TYPE_BIT)
+ (void) field->val_int_as_str(&tmp, 1);
+ else
+ field->val_str(&tmp);
+ out->append(tmp.ptr(), tmp.length(), tmp.charset());
+ if (key + store_length < key_end)
+ out->append('\'');
+ }
+ dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+}
/*
Plan for a QUICK_RANGE_SELECT scan.
@@ -1996,8 +2052,65 @@ public:
}
DBUG_RETURN(quick);
}
+
+#ifdef OPTIMIZER_TRACE
+ void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+ {
+ DBUG_ASSERT(param->using_real_indexes);
+ uint keynr_in_table= param->real_keynr[key_idx];
+
+ const KEY cur_key= param->table->key_info[keynr_in_table];
+ const KEY_PART_INFO *key_part= cur_key.key_part;
+
+ trace->add_str("type", "range_scan").
+ add_str("index", cur_key.name, strlen(cur_key.name)).
+ add("records", records);
+
+ Opt_trace_array trace_range(param->thd->opt_trace,"ranges");
+ for (const SEL_ARG *current= key;
+ current;
+ current= current->next)
+ {
+ String range_info;
+ range_info.set_charset(system_charset_info);
+ for (const SEL_ARG *part= current;
+ part;
+ part= part->next_key_part)
+ {
+ const KEY_PART_INFO *cur_key_part= key_part + part->part;
+ append_range(&range_info, cur_key_part,
+ part->min_value, cur_key_part->length,
+ part->max_value, cur_key_part->length,
+ part->min_flag | part->max_flag);
+ }
+ trace_range.add_str(range_info.ptr(), range_info.length());
+ }
+ }
+#endif
};
+typedef struct st_ror_scan_info
+{
+ uint idx; ///< # of used key in param->keys
+ uint keynr; ///< # of used key in table
+ ha_rows records; ///< estimate of # records this scan will return
+
+ /** Set of intervals over key fields that will be used for row retrieval. */
+ SEL_ARG *sel_arg;
+
+ /** Fields used in the query and covered by this ROR scan. */
+ MY_BITMAP covered_fields;
+ uint used_fields_covered; ///< # of set bits in covered_fields
+ int key_rec_length; ///< length of key record (including rowid)
+
+ /**
+ Cost of reading all index records with values in sel_arg intervals set
+ (assuming there is no need to access full table records)
+ */
+ double index_read_cost;
+ uint first_uncovered_field; ///< first unused bit in covered_fields
+ uint key_components; ///< # of parts in the key
+} ROR_SCAN_INFO;
/* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
@@ -2015,6 +2128,52 @@ public:
struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */
bool is_covering; /* TRUE if no row retrieval phase is necessary */
double index_scan_costs; /* SUM(cost(index_scan)) */
+
+#ifdef OPTIMIZER_TRACE
+ void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+ {
+ trace->add_str("type", "index_roworder_intersect").
+ add("records", records).
+ add("cost", read_cost).
+ add("covering", is_covering).
+ add("cpk_scan", cpk_scan != NULL);
+
+ Opt_trace_context *trace_ctx= param->thd->opt_trace;
+ Opt_trace_array ota(trace_ctx,"intersect_of");
+ for (st_ror_scan_info **cur_scan= first_scan;
+ cur_scan != last_scan;
+ cur_scan++)
+ {
+ const KEY cur_key= param->table->key_info[(*cur_scan)->keynr];
+ const KEY_PART_INFO *key_part= cur_key.key_part;
+
+ Opt_trace_object trace_isect_idx(trace_ctx);
+ trace_isect_idx.add_str("type", "range_scan").
+ add_str("index", cur_key.name, strlen(cur_key.name)).
+ add("records", (*cur_scan)->records);
+
+ Opt_trace_array trace_range(trace_ctx, "ranges");
+ for (const SEL_ARG *current= (*cur_scan)->sel_arg;
+ current;
+ current= current->next)
+ {
+ String range_info;
+ range_info.set_charset(system_charset_info);
+ for (const SEL_ARG *part= current;
+ part;
+ part= part->next_key_part)
+ {
+ const KEY_PART_INFO *cur_key_part= key_part + part->part;
+ append_range(&range_info, cur_key_part,
+ part->min_value, cur_key_part->length,
+ part->max_value, cur_key_part->length,
+ part->min_flag | part->max_flag);
+ }
+ trace_range.add_str(range_info.ptr(), range_info.length());
+ }
+ }
+ }
+#endif
};
@@ -2033,6 +2192,21 @@ public:
MEM_ROOT *parent_alloc);
TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */
TABLE_READ_PLAN **last_ror; /* end of the above array */
+
+#ifdef OPTIMIZER_TRACE
+ void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+ {
+ trace->add_str("type", "index_roworder_union");
+ Opt_trace_array ota(param->thd->opt_trace, "union_of");
+ for (TABLE_READ_PLAN **current= first_ror;
+ current != last_ror;
+ current++)
+ {
+ Opt_trace_object trp_info(param->thd->opt_trace);
+ (*current)->trace_basic_info(param, &trp_info);
+ }
+ }
+#endif
};
@@ -2051,6 +2225,21 @@ public:
MEM_ROOT *parent_alloc);
TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */
TRP_RANGE **range_scans_end; /* end of the array */
+
+#ifdef OPTIMIZER_TRACE
+ void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+ {
+ trace->add_str("type", "index_merge");
+ Opt_trace_array ota(param->thd->opt_trace, "index_merge_of");
+ for (TRP_RANGE **current= range_scans;
+ current != range_scans_end;
+ current++)
+ {
+ Opt_trace_object trp_info(param->thd->opt_trace);
+ (*current)->trace_basic_info(param, &trp_info);
+ }
+ }
+#endif
};
@@ -2061,23 +2250,71 @@ public:
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
{
private:
- bool have_min, have_max, have_agg_distinct;
- KEY_PART_INFO *min_max_arg_part;
- uint group_prefix_len;
- uint used_key_parts;
- uint group_key_parts;
- KEY *index_info;
- uint index;
- uint key_infix_len;
- uchar key_infix[MAX_KEY_LENGTH];
- SEL_TREE *range_tree; /* Represents all range predicates in the query. */
- SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
- uint param_idx; /* Index of used key in param->key. */
- bool is_index_scan; /* Use index_next() instead of random read */
+ bool have_min; ///< TRUE if there is a MIN function
+ bool have_max; ///< TRUE if there is a MAX function
+ /** TRUE if there is an aggregate distinct function, e.g.
+ "COUNT(DISTINCT x)"
+ */
+ bool have_agg_distinct;
+ /** The key_part of the only field used by all MIN/MAX functions.
+ Note that TRP_GROUP_MIN_MAX is not used if there are MIN/MAX
+ functions on more than one field.
+ */
+ KEY_PART_INFO *min_max_arg_part;
+ uint group_prefix_len; ///< Length of all key parts in the group prefix
+ uint used_key_parts; ///< Number of index key parts used for access
+ uint group_key_parts; ///< Number of index key parts in the group prefix
+ KEY *index_info; ///< The index chosen for data access
+ uint index; ///< The id of the chosen index
+ uchar key_infix[MAX_KEY_LENGTH]; ///< Constants from equality predicates
+ uint key_infix_len; ///< Length of key_infix
+ SEL_TREE *range_tree; ///< Represents all range predicates in the query
+ SEL_ARG *index_tree; ///< The SEL_ARG sub-tree corresponding to index_info
+ uint param_idx; ///< Index of used key in param->key
+ bool is_index_scan; ///< Use index_next() instead of random read
public:
- /* Number of records selected by the ranges in index_tree. */
+ /** Number of records selected by the ranges in index_tree. */
ha_rows quick_prefix_records;
public:
+
+#ifdef OPTIMIZER_TRACE
+ void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+ {
+ trace->add_str("type", "index_group").
+ add_str("index", index_info->name, strlen(index_info->name)).
+ add_str("group_attribute", min_max_arg_part->field->field_name,
+ strlen(min_max_arg_part->field->field_name)).
+ add("min_aggregate", have_min).
+ add("max_aggregate", have_max).
+ add("distinct_aggregate", have_agg_distinct).
+ add("key_parts_used_for_access", used_key_parts).
+ add("records", records).
+ add("cost", read_cost);
+
+ const KEY_PART_INFO *key_part= index_info->key_part;
+
+ Opt_trace_array trace_range(param->thd->opt_trace,"ranges");
+ for (const SEL_ARG *current= index_tree;
+ current;
+ current= current->next)
+ {
+ String range_info;
+ range_info.set_charset(system_charset_info);
+ for (const SEL_ARG *part= current;
+ part;
+ part= part->next_key_part)
+ {
+ const KEY_PART_INFO *cur_key_part= key_part + part->part;
+ append_range(&range_info, cur_key_part,
+ part->min_value, cur_key_part->length,
+ part->max_value, cur_key_part->length,
+ part->min_flag | part->max_flag);
+ }
+ trace_range.add_str(range_info.ptr(), range_info.length());
+ }
+ }
+#endif
+
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
bool have_agg_distinct_arg,
KEY_PART_INFO *min_max_arg_part_arg,
@@ -2246,12 +2483,10 @@ int SQL_SELECT::test_quick_select(THD *t
else if (read_time <= 2.0 && !force_quick_range)
DBUG_RETURN(0); /* No need for quick select */
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto(thd->opt_trace, "range_analysis");
+ Opt_trace_object trace_range(thd->opt_trace, "range_analysis");
Opt_trace_object(thd->opt_trace, "table_scan").
- add(head->file->stats.records, "records").
- add(read_time, "cost");
-#endif
+ add("records", head->file->stats.records).
+ add("cost", read_time);
keys_to_use.intersect(head->keys_in_use_for_query);
if (!keys_to_use.is_clear_all())
@@ -2302,9 +2537,9 @@ int SQL_SELECT::test_quick_select(THD *t
thd->mem_root= &alloc;
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto1(thd->opt_trace, "indices");
-#endif
+ Opt_trace_array trace_idx(thd->opt_trace,
+ "potential_range_indices",
+ Opt_trace_context::RANGE_OPTIMIZER);
/*
Make an array with description of all key parts of all table keys.
This is used in get_mm_parts function.
@@ -2312,17 +2547,28 @@ int SQL_SELECT::test_quick_select(THD *t
key_info= head->key_info;
for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto1.add(key_info->name, "index");
-#endif
+ Opt_trace_object trace_idx_details(thd->opt_trace);
+ trace_idx_details.add_str("index",
+ key_info->name, strlen(key_info->name));
KEY_PART_INFO *key_part_info;
if (!keys_to_use.is_set(idx))
+ {
+ trace_idx_details.add("usable", false).
+ add_str("cause", "not_usable_by_conditions");
continue;
+ }
if (key_info->flags & HA_FULLTEXT)
+ {
+ trace_idx_details.add("usable", false).
+ add_str("cause", "fulltext");
continue; // ToDo: ft-keys in non-ft ranges, if possible SerG
+ }
+
+ trace_idx_details.add("usable", true);
param.key[param.keys]=key_parts;
key_part_info= key_info->key_part;
+ Opt_trace_array trace_keypart(thd->opt_trace, "key_parts");
for (uint part=0 ; part < key_info->key_parts ;
part++, key_parts++, key_part_info++)
{
@@ -2336,6 +2582,8 @@ int SQL_SELECT::test_quick_select(THD *t
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
/* Only HA_PART_KEY_SEG is used */
key_parts->flag= (uint8) key_part_info->key_part_flag;
+ trace_keypart.add_str(key_parts->field->field_name,
+ strlen(key_parts->field->field_name));
}
param.real_keynr[param.keys++]=idx;
}
@@ -2359,12 +2607,15 @@ int SQL_SELECT::test_quick_select(THD *t
chosen= true;
}
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object(thd->opt_trace, "best_covering_scan").
- add(head->key_info[key_for_use].name, "index").
- add(key_read_time, "cost").
- add(chosen, "chosen");
-#endif
+ Opt_trace_object trace_cov(thd->opt_trace,
+ "best_covering_index_scan",
+ Opt_trace_context::RANGE_OPTIMIZER);
+ trace_cov.add_str("index", head->key_info[key_for_use].name,
+ strlen(head->key_info[key_for_use].name)).
+ add("cost", key_read_time).
+ add("chosen", chosen);
+ if (!chosen)
+ trace_cov.add_str("cause", "cost");
}
TABLE_READ_PLAN *best_trp= NULL;
@@ -2377,6 +2628,7 @@ int SQL_SELECT::test_quick_select(THD *t
{
if (tree->type == SEL_TREE::IMPOSSIBLE)
{
+ trace_range.add("impossible_range", true);
records=0L; /* Return -1 from this function. */
read_time= (double) HA_POS_ERROR;
goto free_mem;
@@ -2386,7 +2638,14 @@ int SQL_SELECT::test_quick_select(THD *t
can construct a group-min-max quick select
*/
if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER)
+ {
+ DBUG_ASSERT(tree->type == SEL_TREE::ALWAYS); //anything else possible?
+ trace_range.add("range_scan_possible", false);
+ if (tree->type == SEL_TREE::ALWAYS)
+ trace_range.add_str("cause", "condition_always_true");
+
tree= NULL;
+ }
}
}
@@ -2399,11 +2658,20 @@ int SQL_SELECT::test_quick_select(THD *t
{
param.table->quick_condition_rows= min(group_trp->records,
head->file->stats.records);
+ Opt_trace_object grp_summary(thd->opt_trace,
+ "best_group_range_summary",
+ Opt_trace_context::RANGE_OPTIMIZER);
+#ifdef OPTIMIZER_TRACE
+ group_trp->trace_basic_info(¶m, &grp_summary);
+#endif
if (group_trp->read_cost < best_read_time)
{
+ grp_summary.add("chosen", true);
best_trp= group_trp;
best_read_time= best_trp->read_cost;
}
+ else
+ grp_summary.add("chosen", false).add_str("cause", "cost");
}
if (tree)
@@ -2414,6 +2682,9 @@ int SQL_SELECT::test_quick_select(THD *t
*/
if (tree->merges.is_empty())
{
+ Opt_trace_object trace_range(thd->opt_trace,
+ "analyzing_range_alternatives",
+ Opt_trace_context::RANGE_OPTIMIZER);
TRP_RANGE *range_trp;
TRP_ROR_INTERSECT *rori_trp;
bool can_build_covering= FALSE;
@@ -2450,7 +2721,10 @@ int SQL_SELECT::test_quick_select(THD *t
if (!rori_trp->is_covering && can_build_covering &&
(rori_trp= get_best_covering_ror_intersect(¶m, tree,
best_read_time)))
+ {
+ trace_range.add("made_roworder_intersect_covering", true);
best_trp= rori_trp;
+ }
}
}
}
@@ -2465,18 +2739,27 @@ int SQL_SELECT::test_quick_select(THD *t
DBUG_PRINT("info",("No range reads possible,"
" trying to construct index_merge"));
List_iterator_fast<SEL_IMERGE> it(tree->merges);
- while ((imerge= it++))
{
- new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time);
- if (new_conj_trp)
- set_if_smaller(param.table->quick_condition_rows,
- new_conj_trp->records);
- if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost <
- best_conj_trp->read_cost))
- best_conj_trp= new_conj_trp;
+ Opt_trace_array trace_idx_merge(thd->opt_trace,
+ "analyzing_index_merge",
+ Opt_trace_context::RANGE_OPTIMIZER);
+ while ((imerge= it++))
+ {
+ new_conj_trp= get_best_disjunct_quick(¶m, imerge,
+ best_read_time);
+ if (new_conj_trp)
+ set_if_smaller(param.table->quick_condition_rows,
+ new_conj_trp->records);
+ if (!best_conj_trp ||
+ (new_conj_trp &&
+ new_conj_trp->read_cost < best_conj_trp->read_cost))
+ {
+ best_conj_trp= new_conj_trp;
+ }
+ }
+ if (best_conj_trp)
+ best_trp= best_conj_trp;
}
- if (best_conj_trp)
- best_trp= best_conj_trp;
}
}
}
@@ -2494,18 +2777,26 @@ int SQL_SELECT::test_quick_select(THD *t
}
}
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto.add(param.table->quick_condition_rows, "quick_condition_rows");
-#endif
- free_mem:
+free_mem:
+ if (quick)
+ {
+ Opt_trace_object trace_range_summary(thd->opt_trace,
+ "chosen_range_access_summary");
+ {
+ Opt_trace_object trace_range_plan(thd->opt_trace,
+ "range_access_plan");
+ best_trp->trace_basic_info(¶m, &trace_range_plan);
+
+ }
+ trace_range_summary.add("records_in_plan", quick->records).
+ add("cost_of_plan", quick->read_time).
+ add("chosen", true);
+ }
+
free_root(&alloc,MYF(0)); // Return memory & allocator
thd->mem_root= param.old_root;
thd->no_errors=0;
}
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto.add(records, "records");
- OPT_TRACE2(thd->opt_trace, print_quick(quick, &needed_reg));
-#endif
/*
Assume that if the user is using 'limit' we will only need to scan
@@ -3837,49 +4128,63 @@ TABLE_READ_PLAN *get_best_disjunct_quick
DBUG_ENTER("get_best_disjunct_quick");
DBUG_PRINT("info", ("Full table scan cost: %g", read_time));
+ Opt_trace_context * const trace= param->thd->opt_trace;
+ Opt_trace_object trace_best_disjunct(trace);
if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root,
sizeof(TRP_RANGE*)*
n_child_scans)))
DBUG_RETURN(NULL);
- /*
- Collect best 'range' scan for each of disjuncts, and, while doing so,
- analyze possibility of ROR scans. Also calculate some values needed by
- other parts of the code.
- */
- for (ptree= imerge->trees, cur_child= range_scans;
- ptree != imerge->trees_next;
- ptree++, cur_child++)
- {
- DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map,
- "tree in SEL_IMERGE"););
- if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, FALSE, read_time)))
- {
- /*
- One of index scans in this index_merge is more expensive than entire
- table read for another available option. The entire index_merge (and
- any possible ROR-union) will be more expensive then, too. We continue
- here only to update SQL_SELECT members.
- */
- imerge_too_expensive= TRUE;
- }
- if (imerge_too_expensive)
- continue;
+ {
+ /*
+ Collect best 'range' scan for each of disjuncts, and, while doing so,
+ analyze possibility of ROR scans. Also calculate some values needed by
+ other parts of the code.
+ */
+ Opt_trace_array ota(trace,"indices_to_merge");
+ for (ptree= imerge->trees, cur_child= range_scans;
+ ptree != imerge->trees_next;
+ ptree++, cur_child++)
+ {
+ DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map,
+ "tree in SEL_IMERGE"););
+ Opt_trace_object trace_idx(trace);
+ if (!(*cur_child=
+ get_key_scans_params(param, *ptree, TRUE, FALSE, read_time)))
+ {
+ /*
+ One of index scans in this index_merge is more expensive than entire
+ table read for another available option. The entire index_merge (and
+ any possible ROR-union) will be more expensive then, too. We continue
+ here only to update SQL_SELECT members.
+ */
+ imerge_too_expensive= TRUE;
+ }
+ if (imerge_too_expensive)
+ {
+ trace_idx.add("chosen", false).add_str("cause", "cost");
+ continue;
+ }
- imerge_cost += (*cur_child)->read_cost;
- all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
- all_scans_rors &= (*cur_child)->is_ror;
- if (pk_is_clustered &&
- param->real_keynr[(*cur_child)->key_idx] ==
- param->table->s->primary_key)
- {
- cpk_scan= cur_child;
- cpk_scan_records= (*cur_child)->records;
+ uint keynr_in_table= param->real_keynr[(*cur_child)->key_idx];
+ imerge_cost += (*cur_child)->read_cost;
+ all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
+ all_scans_rors &= (*cur_child)->is_ror;
+ if (pk_is_clustered &&
+ keynr_in_table == param->table->s->primary_key)
+ {
+ cpk_scan= cur_child;
+ cpk_scan_records= (*cur_child)->records;
+ }
+ else
+ non_cpk_scan_records += (*cur_child)->records;
+
+ trace_idx.
+ add_str("index_to_merge", param->table->key_info[keynr_in_table].name,
+ strlen(param->table->key_info[keynr_in_table].name)).
+ add("cumulated_cost", imerge_cost);
}
- else
- non_cpk_scan_records += (*cur_child)->records;
}
-
- DBUG_PRINT("info", ("index_merge scans cost %g", imerge_cost));
+ trace_best_disjunct.add("cost_of_reading_ranges", imerge_cost);
if (imerge_too_expensive || (imerge_cost > read_time) ||
((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) &&
read_time != DBL_MAX))
@@ -3890,6 +4195,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick
*/
DBUG_PRINT("info", ("Sum of index_merge scans is more expensive than "
"full table scan, bailing out"));
+ trace_best_disjunct.add("chosen", false).
+ add_str("cause", "cost");
DBUG_RETURN(NULL);
}
@@ -3902,6 +4209,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick
param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_UNION))
{
roru_read_plans= (TABLE_READ_PLAN**)range_scans;
+ trace_best_disjunct.add("use_roworder_union", true).
+ add_str("cause", "always_cheaper_than_not_roworder_retrieval");
goto skip_to_ror_scan;
}
@@ -3911,7 +4220,10 @@ TABLE_READ_PLAN *get_best_disjunct_quick
Add one ROWID comparison for each row retrieved on non-CPK scan. (it
is done in QUICK_RANGE_SELECT::row_in_ranges)
*/
+
imerge_cost += non_cpk_scan_records / TIME_FOR_COMPARE_ROWID;
+ trace_best_disjunct.add("cost_of_mapping_rowid_in_non_cpk_scan",
+ non_cpk_scan_records / TIME_FOR_COMPARE_ROWID);
}
/* Calculate cost(rowid_to_row_scan) */
@@ -3922,12 +4234,16 @@ TABLE_READ_PLAN *get_best_disjunct_quick
get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted,
&sweep_cost);
imerge_cost += sweep_cost.total_cost();
+ trace_best_disjunct.add("cost_sort_rowid_and_read_disk",
+ sweep_cost.total_cost());
}
DBUG_PRINT("info",("index_merge cost with rowid-to-row scan: %g",
imerge_cost));
if (imerge_cost > read_time ||
!param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION))
{
+ trace_best_disjunct.add("use_roworder_index_merge", true).
+ add_str("cause", "cost");
goto build_ror_index_merge;
}
@@ -3944,12 +4260,19 @@ TABLE_READ_PLAN *get_best_disjunct_quick
param->imerge_cost_buff_size= unique_calc_buff_size;
}
- imerge_cost +=
- Unique::get_use_cost(param->imerge_cost_buff, (uint)non_cpk_scan_records,
- param->table->file->ref_length,
- param->thd->variables.sortbuff_size);
- DBUG_PRINT("info",("index_merge total cost: %g (wanted: less then %g)",
- imerge_cost, read_time));
+ {
+ double dup_removal_cost=
+ Unique::get_use_cost(param->imerge_cost_buff,
+ (uint)non_cpk_scan_records,
+ param->table->file->ref_length,
+ param->thd->variables.sortbuff_size);
+
+ trace_best_disjunct.add("cost_duplicate_removal", dup_removal_cost);
+ imerge_cost += dup_removal_cost;
+ trace_best_disjunct.add("total_cost", imerge_cost);
+ DBUG_PRINT("info",("index_merge total cost: %g (wanted: less then %g)",
+ imerge_cost, read_time));
+ }
if (imerge_cost < read_time)
{
if ((imerge_trp= new (param->mem_root)TRP_INDEX_MERGE))
@@ -3983,44 +4306,52 @@ skip_to_ror_scan:
cur_roru_plan= roru_read_plans;
/* Find 'best' ROR scan for each of trees in disjunction */
- for (ptree= imerge->trees, cur_child= range_scans;
- ptree != imerge->trees_next;
- ptree++, cur_child++, cur_roru_plan++)
+
{
- /*
- Assume the best ROR scan is the one that has cheapest full-row-retrieval
- scan cost.
- Also accumulate index_only scan costs as we'll need them to calculate
- overall index_intersection cost.
- */
- double cost;
- if ((*cur_child)->is_ror)
+ Opt_trace_array ota(trace, "analyzing_roworder_scans");
+ for (ptree= imerge->trees, cur_child= range_scans;
+ ptree != imerge->trees_next;
+ ptree++, cur_child++, cur_roru_plan++)
{
- /* Ok, we have index_only cost, now get full rows scan cost */
- cost= param->table->file->
- read_time(param->real_keynr[(*cur_child)->key_idx], 1,
- (*cur_child)->records) +
- rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
- }
- else
- cost= read_time;
- TABLE_READ_PLAN *prev_plan= *cur_child;
- if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
- &dummy)))
- {
- if (prev_plan->is_ror)
- *cur_roru_plan= prev_plan;
+ Opt_trace_object trp_info(trace);
+ (*cur_child)->trace_basic_info(param, &trp_info);
+
+ /*
+ Assume the best ROR scan is the one that has cheapest
+ full-row-retrieval scan cost.
+ Also accumulate index_only scan costs as we'll need them to
+ calculate overall index_intersection cost.
+ */
+ double cost;
+ if ((*cur_child)->is_ror)
+ {
+ /* Ok, we have index_only cost, now get full rows scan cost */
+ cost= param->table->file->
+ read_time(param->real_keynr[(*cur_child)->key_idx], 1,
+ (*cur_child)->records) +
+ rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
+ }
else
- DBUG_RETURN(imerge_trp);
- roru_index_costs += (*cur_roru_plan)->read_cost;
+ cost= read_time;
+
+ TABLE_READ_PLAN *prev_plan= *cur_child;
+ if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
+ &dummy)))
+ {
+ if (prev_plan->is_ror)
+ *cur_roru_plan= prev_plan;
+ else
+ DBUG_RETURN(imerge_trp);
+ roru_index_costs += (*cur_roru_plan)->read_cost;
+ }
+ else
+ roru_index_costs +=
+ ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
+ roru_total_records += (*cur_roru_plan)->records;
+ roru_intersect_part *= (*cur_roru_plan)->records /
+ param->table->file->stats.records;
}
- else
- roru_index_costs +=
- ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
- roru_total_records += (*cur_roru_plan)->records;
- roru_intersect_part *= (*cur_roru_plan)->records /
- param->table->file->stats.records;
}
/*
@@ -4052,13 +4383,14 @@ skip_to_ror_scan:
sweep_cost.total_cost();
}
- DBUG_PRINT("info", ("ROR-union: cost %g, %d members", roru_total_cost,
- n_child_scans));
+ trace_best_disjunct.add("index_roworder_union_cost", roru_total_cost).
+ add("members", n_child_scans);
TRP_ROR_UNION* roru;
if (roru_total_cost < read_time)
{
if ((roru= new (param->mem_root) TRP_ROR_UNION))
{
+ trace_best_disjunct.add("chosen", true);
roru->first_ror= roru_read_plans;
roru->last_ror= roru_read_plans + n_child_scans;
roru->read_cost= roru_total_cost;
@@ -4066,34 +4398,12 @@ skip_to_ror_scan:
DBUG_RETURN(roru);
}
}
+ trace_best_disjunct.add("chosen", false);
+
DBUG_RETURN(imerge_trp);
}
-typedef struct st_ror_scan_info
-{
- uint idx; /* # of used key in param->keys */
- uint keynr; /* # of used key in table */
- ha_rows records; /* estimate of # records this scan will return */
-
- /* Set of intervals over key fields that will be used for row retrieval. */
- SEL_ARG *sel_arg;
-
- /* Fields used in the query and covered by this ROR scan. */
- MY_BITMAP covered_fields;
- uint used_fields_covered; /* # of set bits in covered_fields */
- int key_rec_length; /* length of key record (including rowid) */
-
- /*
- Cost of reading all index records with values in sel_arg intervals set
- (assuming there is no need to access full table records)
- */
- double index_read_cost;
- uint first_uncovered_field; /* first unused bit in covered_fields */
- uint key_components; /* # of parts in the key */
-} ROR_SCAN_INFO;
-
-
/*
Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
sel_arg set of intervals.
@@ -4614,9 +4924,19 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
double min_cost= DBL_MAX;
DBUG_ENTER("get_best_ror_intersect");
+ Opt_trace_object trace_ror(param->thd->opt_trace,
+ "analyzing_roworder_intersect");
+
if ((tree->n_ror_scans < 2) || !param->table->file->stats.records ||
!param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
+ {
+ if (tree->n_ror_scans < 2)
+ trace_ror.add("usable", false).
+ add_str("cause", "too_few_roworder_scans");
+ else
+ trace_ror.add("usable", false).add("done_tracing", false);
DBUG_RETURN(NULL);
+ }
/*
Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
@@ -4683,28 +5003,42 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
ROR_SCAN_INFO **intersect_scans_best;
cur_ror_scan= tree->ror_scans;
intersect_scans_best= intersect_scans;
- while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
{
- /* S= S + first(R); R= R - first(R); */
- if (!ror_intersect_add(intersect, *cur_ror_scan, FALSE))
+ Opt_trace_array ota(param->thd->opt_trace, "intersecting_indices");
+ while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
{
- cur_ror_scan++;
- continue;
- }
+ Opt_trace_object trace_idx(param->thd->opt_trace);
+ char *idx_name= param->table->key_info[(*cur_ror_scan)->keynr].name;
+ trace_idx.add_str("index", idx_name, strlen(idx_name));
+ /* S= S + first(R); R= R - first(R); */
+ if (!ror_intersect_add(intersect, *cur_ror_scan, FALSE))
+ {
+ trace_idx.add("used_in_intersect", false).
+ add_str("cause", "does_not_reduce_cost_of_intersect");
+ cur_ror_scan++;
+ continue;
+ }
- *(intersect_scans_end++)= *(cur_ror_scan++);
-
- if (intersect->total_cost < min_cost)
- {
- /* Local minimum found, save it */
- ror_intersect_cpy(intersect_best, intersect);
- intersect_scans_best= intersect_scans_end;
- min_cost = intersect->total_cost;
+ trace_idx.add("used_in_intersect", true).
+ add("matching_records_now", intersect->out_rows).
+ add("cumulated_cost", intersect->total_cost).
+ add("isect_covering_with_this_index", intersect->is_covering);
+
+ *(intersect_scans_end++)= *(cur_ror_scan++);
+
+ if (intersect->total_cost < min_cost)
+ {
+ /* Local minimum found, save it */
+ ror_intersect_cpy(intersect_best, intersect);
+ intersect_scans_best= intersect_scans_end;
+ min_cost = intersect->total_cost;
+ }
}
}
if (intersect_scans_best == intersect_scans)
{
+ trace_ror.add("increases_selectivity", false).add("chosen", false);
DBUG_PRINT("info", ("None of scans increase selectivity"));
DBUG_RETURN(NULL);
}
@@ -4728,9 +5062,22 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
if (ror_intersect_add(intersect, cpk_scan, TRUE) &&
(intersect->total_cost < min_cost))
{
+ Opt_trace_object (param->thd->opt_trace, "clustered_pk").
+ add("cpk_scan_added_to_intersect", true).
+ add("cumulated_cost", intersect->total_cost);
cpk_scan_used= TRUE;
intersect_best= intersect; //just set pointer here
}
+ else
+ Opt_trace_object (param->thd->opt_trace, "clustered_pk").
+ add("cpk_added_to_intersect", false).add_str("cause", "cost");
+ }
+ else
+ {
+ Opt_trace_object trace_cpk(param->thd->opt_trace, "clustered_pk");
+ trace_cpk.add("cpk_added_to_intersect", false);
+ cpk_scan ? trace_cpk.add_str("cause", "ror_is_covering")
+ : trace_cpk.add_str("cause", "no_clustered_pk_index");
}
/* Ok, return ROR-intersect plan if we have found one */
@@ -4755,10 +5102,18 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
trp->records= best_rows;
trp->index_scan_costs= intersect_best->index_scan_costs;
trp->cpk_scan= cpk_scan_used? cpk_scan: NULL;
+
+ trace_ror.add("records", trp->records).
+ add("cost", trp->read_cost).
+ add("covering", trp->is_covering).
+ add("chosen", true);
+
DBUG_PRINT("info", ("Returning non-covering ROR-intersect plan:"
"cost %g, records %lu",
trp->read_cost, (ulong) trp->records));
}
+ else
+ trace_ror.add("chosen", false);
DBUG_RETURN(trp);
}
@@ -4805,6 +5160,12 @@ TRP_ROR_INTERSECT *get_best_covering_ror
ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end;
DBUG_ENTER("get_best_covering_ror_intersect");
+ // None of our tests enter this function
+ Opt_trace_object (param->thd->opt_trace).
+ add("get_best_covering_roworder_intersect", true).
+ add("untested_code", true).
+ add("need_tracing",true);
+
if (!param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
DBUG_RETURN(NULL);
@@ -4964,9 +5325,7 @@ static TRP_RANGE *get_key_scans_params(P
*/
DBUG_EXECUTE("info", print_sel_tree(param, tree, &tree->keys_map,
"tree scans"););
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto1(param->thd->opt_trace, "index_scans_parameters");
-#endif
+ Opt_trace_array ota(param->thd->opt_trace, "range_scan_alternatives");
tree->ror_scans_map.clear_all();
tree->n_ror_scans= 0;
@@ -4986,42 +5345,39 @@ static TRP_RANGE *get_key_scans_params(P
bool read_index_only= index_read_must_be_used ? TRUE :
(bool) param->table->covering_keys.is_set(keynr);
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto2(param->thd->opt_trace, "range_scan");
- oto2.add(param->table->key_info[keynr].name, "index");
-#endif
+ Opt_trace_object trace_idx(param->thd->opt_trace);
+ trace_idx.add_str("index", param->table->key_info[keynr].name,
+ strlen(param->table->key_info[keynr].name));
+
found_records= check_quick_select(param, idx, read_index_only, *key,
update_tbl_stats, &mrr_flags,
&buf_size, &cost);
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto2.add(read_index_only, "index_only").add(found_records, "records");
-#endif
+ trace_idx.add("index_only", read_index_only).
+ add("records", found_records).
+ add("cost", cost.total_cost());
if ((found_records != HA_POS_ERROR) && param->is_ror_scan)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto2.add(true, "rowid_ordered");
-#endif
+ trace_idx.add("rowid_ordered", true);
tree->n_ror_scans++;
tree->ror_scans_map.set_bit(idx);
}
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
else
- oto2.add(false, "rowid_ordered");
-#endif
+ trace_idx.add("rowid_ordered", false);
if (found_records != HA_POS_ERROR &&
read_time > (found_read_time= cost.total_cost()))
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto2.add(found_read_time, "cost").add(true, "chosen");
-#endif
+ trace_idx.add("chosen", true);
read_time= found_read_time;
best_records= found_records;
key_to_read= key;
best_mrr_flags= mrr_flags;
best_buf_size= buf_size;
}
+ else
+ trace_idx.add("chosen", false).add_str("cause", "cost");
+
}
}
@@ -5037,10 +5393,6 @@ static TRP_RANGE *get_key_scans_params(P
read_plan->is_ror= tree->ror_scans_map.is_set(idx);
read_plan->read_cost= read_time;
read_plan->mrr_buf_size= best_buf_size;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- oto1.add(param->table->key_info[param->real_keynr[idx]].name,
- "index_for_best_range_access");
-#endif
//DBUG_PRINT("info",
// ("Returning range plan for key %s, cost %g, records %lu",
// param->table->key_info[param->real_keynr[idx]].name,
@@ -5100,10 +5452,12 @@ QUICK_SELECT_I *TRP_ROR_INTERSECT::make_
"creating ROR-intersect",
first_scan, last_scan););
alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc;
- for (; first_scan != last_scan;++first_scan)
+ for (st_ror_scan_info **current= first_scan;
+ current != last_scan;
+ current++)
{
- if (!(quick= get_quick_select(param, (*first_scan)->idx,
- (*first_scan)->sel_arg,
+ if (!(quick= get_quick_select(param, (*current)->idx,
+ (*current)->sel_arg,
HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED,
0, alloc)) ||
quick_intrsect->push_quick_back(quick))
@@ -6010,6 +6364,12 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
value->result_type() == item_cmp_type(field->result_type(),
value->result_type()))
{
+ Opt_trace_object (param->thd->opt_trace, "impossible_condition",
+ Opt_trace_context::RANGE_OPTIMIZER).
+ add_str("table", *field->table_name, strlen(*field->table_name)).
+ add_str("field", field->field_name, strlen(field->field_name)).
+ add_str("cause", "incomparable_types");
+
tree= new (alloc) SEL_ARG(field, 0, 0);
tree->type= SEL_ARG::IMPOSSIBLE;
field->table->in_use->variables.sql_mode= orig_sql_mode;
@@ -6072,6 +6432,12 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
}
else if (err < 0)
{
+ Opt_trace_object (param->thd->opt_trace, "impossible_condition",
+ Opt_trace_context::RANGE_OPTIMIZER).
+ add_str("table", *field->table_name, strlen(*field->table_name)).
+ add_str("field", field->field_name, strlen(field->field_name)).
+ add_str("cause", "null_field_in_non_null_column");
+
field->table->in_use->variables.sql_mode= orig_sql_mode;
/* This happens when we try to insert a NULL field in a not null column */
tree= &null_element; // cmp with NULL is never TRUE
@@ -6085,6 +6451,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
*/
if (type != Item_func::EQUAL_FUNC && field->is_real_null())
{
+ Opt_trace_object (param->thd->opt_trace, "impossible_condition",
+ Opt_trace_context::RANGE_OPTIMIZER).
+ add_str("table", *field->table_name, strlen(*field->table_name)).
+ add_str("field", field->field_name, strlen(field->field_name)).
+ add_str("cause", "comparison_with_null_always_false");
tree= &null_element;
goto end;
}
@@ -6121,6 +6492,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
{
if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC)
{
+ Opt_trace_object (param->thd->opt_trace, "impossible_condition",
+ Opt_trace_context::RANGE_OPTIMIZER).
+ add_str("table", *field->table_name, strlen(*field->table_name)).
+ add_str("field", field->field_name, strlen(field->field_name)).
+ add_str("cause", "unsigned_int_cannot_be_negative");
tree->type= SEL_ARG::IMPOSSIBLE;
goto end;
}
@@ -7632,8 +8008,26 @@ range_seq_t sel_arg_range_seq_init(void
}
-static void step_down_to(SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree)
+static void step_down_to(String *s, SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree)
{
+
+ if (arg->param->thd->opt_trace && arg->param->thd->opt_trace->is_started())
+ {
+ /*
+ Stepping down will append the range for the current keypart (in
+ key_tree) to seq. Trace range here since this is where it is
+ human readable.
+ */
+ KEY_PART_INFO *key_part=
+ arg->param->table->key_info[arg->real_keyno].key_part + key_tree->part;
+
+ uint16 length= key_part->length;
+ append_range(s, key_part,
+ key_tree->min_value, length,
+ key_tree->max_value, length,
+ key_tree->min_flag | key_tree->max_flag);
+ }
+
RANGE_SEQ_ENTRY *cur= &arg->stack[arg->i+1];
RANGE_SEQ_ENTRY *prev= &arg->stack[arg->i];
@@ -7691,6 +8085,9 @@ uint sel_arg_range_seq_next(range_seq_t
{
SEL_ARG *key_tree;
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq;
+ String key_range_trace;
+ key_range_trace.set_charset(system_charset_info);
+
if (seq->at_start)
{
key_tree= seq->start;
@@ -7706,7 +8103,7 @@ uint sel_arg_range_seq_next(range_seq_t
{
//step down; (update the tuple, we'll step right and stay there)
seq->i--;
- step_down_to(seq, key_tree->next);
+ step_down_to(&key_range_trace, seq, key_tree->next);
key_tree= key_tree->next;
seq->param->is_ror_scan= FALSE;
goto walk_right_n_up;
@@ -7727,7 +8124,7 @@ uint sel_arg_range_seq_next(range_seq_t
{
// Step down; update the tuple
seq->i--;
- step_down_to(seq, key_tree->next);
+ step_down_to(&key_range_trace, seq, key_tree->next);
key_tree= key_tree->next;
seq->param->is_ror_scan= FALSE;
break;
@@ -7781,7 +8178,7 @@ walk_up_n_right:
/* Step up */
key_tree= key_tree->prev;
}
- step_down_to(seq, key_tree);
+ step_down_to(&key_range_trace, seq, key_tree);
}
/* Ok got a tuple */
@@ -7839,17 +8236,24 @@ walk_up_n_right:
seq->param->is_ror_scan= FALSE;
}
}
- OPT_TRACE2(seq->param->thd->opt_trace,
- print_range(seq->param->thd->opt_trace,
- seq->param->table->key_info[seq->real_keyno].key_part,
- range->start_key.key,
- range->start_key.length,
- range->end_key.key,
- range->end_key.length,
- cur->min_key_flag | cur->max_key_flag));
seq->param->range_count++;
seq->param->max_key_part=max(seq->param->max_key_part,key_tree->part);
+
+ if (key_range_trace.length())
+ {
+ DBUG_ASSERT(seq->param->thd->opt_trace);
+ DBUG_ASSERT(seq->param->thd->opt_trace->is_started());
+ /*
+ Should be Opt_trace_array, but don't cast because if it is
+ Opt_trace_object a cast will crash the server while just
+ add()'ing to Opt_trace_struct will cause a JSON syntax error
+ for the optimizer trace (less severe)
+ */
+ Opt_trace_struct *trace_range=
+ seq->param->thd->opt_trace->get_current_struct();
+ trace_range->add_str(key_range_trace.ptr(), key_range_trace.length());
+ }
return 0;
}
@@ -9722,14 +10126,30 @@ get_best_group_min_max(PARAM *param, SEL
DBUG_ENTER("get_best_group_min_max");
+ Opt_trace_object trace_group(thd->opt_trace, "group_index_range",
+ Opt_trace_context::RANGE_OPTIMIZER);
+
/* Perform few 'cheap' tests whether this access method is applicable. */
if (!join)
+ {
+ trace_group.add("chosen", false).add_str("cause", "no_join");
DBUG_RETURN(NULL); /* This is not a select statement. */
- if ((join->tables != 1) || /* The query must reference one table. */
- (join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
+ }
+ if (join->tables != 1) /* The query must reference one table. */
+ {
+ trace_group.add("chosen", false).add_str("cause", "not_single_table");
DBUG_RETURN(NULL);
+ }
+ if (join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */
+ {
+ trace_group.add("chosen", false).add_str("cause", "is_rollup");
+ DBUG_RETURN(NULL);
+ }
if (table->s->keys == 0) /* There are no indexes to use. */
+ {
+ trace_group.add("chosen", false).add_str("cause", "no_index");
DBUG_RETURN(NULL);
+ }
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
@@ -9741,7 +10161,10 @@ get_best_group_min_max(PARAM *param, SEL
if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
(!join->select_distinct) &&
!is_agg_distinct)
+ {
+ trace_group.add("chosen", false).add_str("cause", "not_group_by_or_distinct");
DBUG_RETURN(NULL);
+ }
/* Analyze the query in more detail. */
if (join->sum_funcs[0])
@@ -9759,7 +10182,11 @@ get_best_group_min_max(PARAM *param, SEL
min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)
continue;
else
+ {
+ trace_group.add("chosen", false).
+ add_str("cause", "not_applicable_aggregate_function");
DBUG_RETURN(NULL);
+ }
/* The argument of MIN/MAX. */
Item *expr= min_max_item->get_arg(0)->real_item();
@@ -9777,6 +10204,7 @@ get_best_group_min_max(PARAM *param, SEL
/* Check (SA5). */
if (join->select_distinct)
{
+ trace_group.add("is_distinct_query", true);
while ((item= select_items_it++))
{
if (item->real_item()->type() != Item::FIELD_ITEM)
@@ -9788,7 +10216,11 @@ get_best_group_min_max(PARAM *param, SEL
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
{
if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM)
+ {
+ trace_group.add("chosen", false).
+ add_str("cause", "group_field_is_expression");
DBUG_RETURN(NULL);
+ }
}
/*
@@ -9810,289 +10242,334 @@ get_best_group_min_max(PARAM *param, SEL
ha_rows cur_quick_prefix_records= 0;
uint cur_param_idx=MAX_KEY;
- for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
- cur_index_info++, cur_index++)
+
{
- KEY_PART_INFO *cur_part;
- KEY_PART_INFO *end_part; /* Last part for loops. */
- /* Last index part. */
- KEY_PART_INFO *last_part;
- KEY_PART_INFO *first_non_group_part;
- KEY_PART_INFO *first_non_infix_part;
- uint key_infix_parts;
- uint cur_group_key_parts= 0;
- uint cur_group_prefix_len= 0;
- double cur_read_cost;
- ha_rows cur_records;
- key_map used_key_parts_map;
- uint max_key_part= 0;
- uint cur_key_infix_len= 0;
- uchar cur_key_infix[MAX_KEY_LENGTH];
- uint cur_used_key_parts;
+ Opt_trace_array ota(thd->opt_trace, "potential_group_range_indices");
+ for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
+ cur_index_info++, cur_index++)
+ {
+ Opt_trace_object trace_idx(thd->opt_trace);
+ trace_idx.add_str("index", cur_index_info->name,
+ strlen(cur_index_info->name));
+ KEY_PART_INFO *cur_part;
+ KEY_PART_INFO *end_part; /* Last part for loops. */
+ /* Last index part. */
+ KEY_PART_INFO *last_part;
+ KEY_PART_INFO *first_non_group_part;
+ KEY_PART_INFO *first_non_infix_part;
+ uint key_infix_parts;
+ uint cur_group_key_parts= 0;
+ uint cur_group_prefix_len= 0;
+ double cur_read_cost;
+ ha_rows cur_records;
+ key_map used_key_parts_map;
+ uint max_key_part= 0;
+ uint cur_key_infix_len= 0;
+ uchar cur_key_infix[MAX_KEY_LENGTH];
+ uint cur_used_key_parts;
- /* Check (B1) - if current index is covering. */
- if (!table->covering_keys.is_set(cur_index))
- goto next_index;
-
- /*
- If the current storage manager is such that it appends the primary key to
- each index, then the above condition is insufficient to check if the
- index is covering. In such cases it may happen that some fields are
- covered by the PK index, but not by the current index. Since we can't
- use the concatenation of both indexes for index lookup, such an index
- does not qualify as covering in our case. If this is the case, below
- we check that all query fields are indeed covered by 'cur_index'.
- */
- if (pk < MAX_KEY && cur_index != pk &&
- (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
- {
- /* For each table field */
- for (uint i= 0; i < table->s->fields; i++)
+ /* Check (B1) - if current index is covering. */
+ if (!table->covering_keys.is_set(cur_index))
{
- Field *cur_field= table->field[i];
- /*
- If the field is used in the current query ensure that it's
- part of 'cur_index'
- */
- if (bitmap_is_set(table->read_set, cur_field->field_index) &&
- !cur_field->part_of_key_not_clustered.is_set(cur_index))
- goto next_index; // Field was not part of key
+ trace_idx.add("usable", false).add("covering", false);
+ goto next_index;
}
- }
- /*
- Check (GA1) for GROUP BY queries.
- */
- if (join->group_list)
- {
- cur_part= cur_index_info->key_part;
- end_part= cur_part + cur_index_info->key_parts;
- /* Iterate in parallel over the GROUP list and the index parts. */
- for (tmp_group= join->group_list; tmp_group && (cur_part != end_part);
- tmp_group= tmp_group->next, cur_part++)
+ /*
+ If the current storage manager is such that it appends the primary key to
+ each index, then the above condition is insufficient to check if the
+ index is covering. In such cases it may happen that some fields are
+ covered by the PK index, but not by the current index. Since we can't
+ use the concatenation of both indexes for index lookup, such an index
+ does not qualify as covering in our case. If this is the case, below
+ we check that all query fields are indeed covered by 'cur_index'.
+ */
+ if (pk < MAX_KEY && cur_index != pk &&
+ (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
{
- /*
- TODO:
- tmp_group::item is an array of Item, is it OK to consider only the
- first Item? If so, then why? What is the array for?
- */
- /* Above we already checked that all group items are fields. */
- DBUG_ASSERT((*tmp_group->item)->real_item()->type() == Item::FIELD_ITEM);
- Item_field *group_field= (Item_field *) (*tmp_group->item)->real_item();
- if (group_field->field->eq(cur_part->field))
+ /* For each table field */
+ for (uint i= 0; i < table->s->fields; i++)
{
- cur_group_prefix_len+= cur_part->store_length;
- ++cur_group_key_parts;
- max_key_part= cur_part - cur_index_info->key_part + 1;
- used_key_parts_map.set_bit(max_key_part);
+ Field *cur_field= table->field[i];
+ /*
+ If the field is used in the current query ensure that it's
+ part of 'cur_index'
+ */
+ if (bitmap_is_set(table->read_set, cur_field->field_index) &&
+ !cur_field->part_of_key_not_clustered.is_set(cur_index))
+ {
+ trace_idx.add("usable", false).add("covering", false);
+ goto next_index; // Field was not part of key
+ }
}
- else
- goto next_index;
}
- }
- /*
- Check (GA2) if this is a DISTINCT query.
- If GA2, then Store a new ORDER object in group_fields_array at the
- position of the key part of item_field->field. Thus we get the ORDER
- objects for each field ordered as the corresponding key parts.
- Later group_fields_array of ORDER objects is used to convert the query
- to a GROUP query.
- */
- if ((!join->group_list && join->select_distinct) ||
- is_agg_distinct)
- {
- if (!is_agg_distinct)
+ trace_idx.add("covering", true);
+
+ /*
+ Check (GA1) for GROUP BY queries.
+ */
+ if (join->group_list)
{
- select_items_it.rewind();
+ cur_part= cur_index_info->key_part;
+ end_part= cur_part + cur_index_info->key_parts;
+ /* Iterate in parallel over the GROUP list and the index parts. */
+ for (tmp_group= join->group_list; tmp_group && (cur_part != end_part);
+ tmp_group= tmp_group->next, cur_part++)
+ {
+ /*
+ TODO:
+ tmp_group::item is an array of Item, is it OK to consider only the
+ first Item? If so, then why? What is the array for?
+ */
+ /* Above we already checked that all group items are fields. */
+ DBUG_ASSERT((*tmp_group->item)->real_item()->type() == Item::FIELD_ITEM);
+ Item_field *group_field= (Item_field *) (*tmp_group->item)->real_item();
+ if (group_field->field->eq(cur_part->field))
+ {
+ cur_group_prefix_len+= cur_part->store_length;
+ ++cur_group_key_parts;
+ max_key_part= cur_part - cur_index_info->key_part + 1;
+ used_key_parts_map.set_bit(max_key_part);
+ }
+ else
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "group_attribute_not_prefix_in_index");
+ goto next_index;
+ }
+ }
}
- List_iterator<Item_field> agg_distinct_flds_it (agg_distinct_flds);
- while (NULL != (item = (is_agg_distinct ?
- (Item *) agg_distinct_flds_it++ : select_items_it++)))
+ /*
+ Check (GA2) if this is a DISTINCT query.
+ If GA2, then Store a new ORDER object in group_fields_array at the
+ position of the key part of item_field->field. Thus we get the ORDER
+ objects for each field ordered as the corresponding key parts.
+ Later group_fields_array of ORDER objects is used to convert the query
+ to a GROUP query.
+ */
+ if ((!join->group_list && join->select_distinct) ||
+ is_agg_distinct)
{
- /* (SA5) already checked above. */
- item_field= (Item_field*) item->real_item();
- DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM);
+ if (!is_agg_distinct)
+ {
+ select_items_it.rewind();
+ }
- /* not doing loose index scan for derived tables */
- if (!item_field->field)
- goto next_index;
+ List_iterator<Item_field> agg_distinct_flds_it (agg_distinct_flds);
+ while (NULL != (item = (is_agg_distinct ?
+ (Item *) agg_distinct_flds_it++ : select_items_it++)))
+ {
+ /* (SA5) already checked above. */
+ item_field= (Item_field*) item->real_item();
+ DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM);
- /* Find the order of the key part in the index. */
- key_part_nr= get_field_keypart(cur_index_info, item_field->field);
+ /* not doing loose index scan for derived tables */
+ if (!item_field->field)
+ {
+ trace_idx.add("usable", false).add_str("cause", "derived_table");
+ goto next_index;
+ }
+
+ /* Find the order of the key part in the index. */
+ key_part_nr= get_field_keypart(cur_index_info, item_field->field);
+ /*
+ Check if this attribute was already present in the select list.
+ If it was present, then its corresponding key part was alredy used.
+ */
+ if (used_key_parts_map.is_set(key_part_nr))
+ continue;
+ if (key_part_nr < 1 ||
+ (!is_agg_distinct && key_part_nr > join->fields_list.elements))
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "select_attribute_not_prefix_in_index");
+ goto next_index;
+ }
+ cur_part= cur_index_info->key_part + key_part_nr - 1;
+ cur_group_prefix_len+= cur_part->store_length;
+ used_key_parts_map.set_bit(key_part_nr);
+ ++cur_group_key_parts;
+ max_key_part= max(max_key_part,key_part_nr);
+ }
/*
- Check if this attribute was already present in the select list.
- If it was present, then its corresponding key part was alredy used.
+ Check that used key parts forms a prefix of the index.
+ To check this we compare bits in all_parts and cur_parts.
+ all_parts have all bits set from 0 to (max_key_part-1).
+ cur_parts have bits set for only used keyparts.
*/
- if (used_key_parts_map.is_set(key_part_nr))
- continue;
- if (key_part_nr < 1 ||
- (!is_agg_distinct && key_part_nr > join->fields_list.elements))
+ ulonglong all_parts, cur_parts;
+ all_parts= (1<<max_key_part) - 1;
+ cur_parts= used_key_parts_map.to_ulonglong() >> 1;
+ if (all_parts != cur_parts)
goto next_index;
- cur_part= cur_index_info->key_part + key_part_nr - 1;
- cur_group_prefix_len+= cur_part->store_length;
- used_key_parts_map.set_bit(key_part_nr);
- ++cur_group_key_parts;
- max_key_part= max(max_key_part,key_part_nr);
}
- /*
- Check that used key parts forms a prefix of the index.
- To check this we compare bits in all_parts and cur_parts.
- all_parts have all bits set from 0 to (max_key_part-1).
- cur_parts have bits set for only used keyparts.
- */
- ulonglong all_parts, cur_parts;
- all_parts= (1<<max_key_part) - 1;
- cur_parts= used_key_parts_map.to_ulonglong() >> 1;
- if (all_parts != cur_parts)
- goto next_index;
- }
-
- /* Check (SA2). */
- if (min_max_arg_item)
- {
- key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field);
- if (key_part_nr <= cur_group_key_parts)
- goto next_index;
- min_max_arg_part= cur_index_info->key_part + key_part_nr - 1;
- }
- /*
- Check (NGA1, NGA2) and extract a sequence of constants to be used as part
- of all search keys.
- */
-
- /*
- If there is MIN/MAX, each keypart between the last group part and the
- MIN/MAX part must participate in one equality with constants, and all
- keyparts after the MIN/MAX part must not be referenced in the query.
-
- If there is no MIN/MAX, the keyparts after the last group part can be
- referenced only in equalities with constants, and the referenced keyparts
- must form a sequence without any gaps that starts immediately after the
- last group keypart.
- */
- last_part= cur_index_info->key_part + cur_index_info->key_parts;
- first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ?
- cur_index_info->key_part + cur_group_key_parts :
- NULL;
- first_non_infix_part= min_max_arg_part ?
- (min_max_arg_part < last_part) ?
- min_max_arg_part :
- NULL :
- NULL;
- if (first_non_group_part &&
- (!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0)))
- {
- if (tree)
+ /* Check (SA2). */
+ if (min_max_arg_item)
{
- uint dummy;
- SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param,
- &dummy);
- if (!get_constant_key_infix(cur_index_info, index_range_tree,
- first_non_group_part, min_max_arg_part,
- last_part, thd, cur_key_infix,
- &cur_key_infix_len,
- &first_non_infix_part))
+ key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field);
+ if (key_part_nr <= cur_group_key_parts)
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "aggregate_column_not_suffix_in_idx");
goto next_index;
+ }
+ min_max_arg_part= cur_index_info->key_part + key_part_nr - 1;
}
- else if (min_max_arg_part &&
- (min_max_arg_part - first_non_group_part > 0))
- {
- /*
- There is a gap but no range tree, thus no predicates at all for the
- non-group keyparts.
- */
- goto next_index;
- }
- else if (first_non_group_part && join->conds)
+
+ /*
+ Check (NGA1, NGA2) and extract a sequence of constants to be used as part
+ of all search keys.
+ */
+
+ /*
+ If there is MIN/MAX, each keypart between the last group part and the
+ MIN/MAX part must participate in one equality with constants, and all
+ keyparts after the MIN/MAX part must not be referenced in the query.
+
+ If there is no MIN/MAX, the keyparts after the last group part can be
+ referenced only in equalities with constants, and the referenced keyparts
+ must form a sequence without any gaps that starts immediately after the
+ last group keypart.
+ */
+ last_part= cur_index_info->key_part + cur_index_info->key_parts;
+ first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ?
+ cur_index_info->key_part + cur_group_key_parts :
+ NULL;
+ first_non_infix_part= min_max_arg_part ?
+ (min_max_arg_part < last_part) ?
+ min_max_arg_part :
+ NULL :
+ NULL;
+ if (first_non_group_part &&
+ (!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0)))
{
- /*
- If there is no MIN/MAX function in the query, but some index
- key part is referenced in the WHERE clause, then this index
- cannot be used because the WHERE condition over the keypart's
- field cannot be 'pushed' to the index (because there is no
- range 'tree'), and the WHERE clause must be evaluated before
- GROUP BY/DISTINCT.
- */
- /*
- Store the first and last keyparts that need to be analyzed
- into one array that can be passed as parameter.
- */
- KEY_PART_INFO *key_part_range[2];
- key_part_range[0]= first_non_group_part;
- key_part_range[1]= last_part;
-
- /* Check if cur_part is referenced in the WHERE clause. */
- if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
- (uchar*) key_part_range))
+ if (tree)
+ {
+ uint dummy;
+ SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param,
+ &dummy);
+ if (!get_constant_key_infix(cur_index_info, index_range_tree,
+ first_non_group_part, min_max_arg_part,
+ last_part, thd, cur_key_infix,
+ &cur_key_infix_len,
+ &first_non_infix_part))
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "nonconst_equality_gap_attribute");
+ goto next_index;
+ }
+ }
+ else if (min_max_arg_part &&
+ (min_max_arg_part - first_non_group_part > 0))
+ {
+ /*
+ There is a gap but no range tree, thus no predicates at all for the
+ non-group keyparts.
+ */
+ trace_idx.add("usable", false).
+ add_str("cause", "no_nongroup_keypart_predicate");
goto next_index;
+ }
+ else if (first_non_group_part && join->conds)
+ {
+ /*
+ If there is no MIN/MAX function in the query, but some index
+ key part is referenced in the WHERE clause, then this index
+ cannot be used because the WHERE condition over the keypart's
+ field cannot be 'pushed' to the index (because there is no
+ range 'tree'), and the WHERE clause must be evaluated before
+ GROUP BY/DISTINCT.
+ */
+ /*
+ Store the first and last keyparts that need to be analyzed
+ into one array that can be passed as parameter.
+ */
+ KEY_PART_INFO *key_part_range[2];
+ key_part_range[0]= first_non_group_part;
+ key_part_range[1]= last_part;
+
+ /* Check if cur_part is referenced in the WHERE clause. */
+ if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
+ (uchar*) key_part_range))
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "indexpart_reference_from_where_clause");
+ goto next_index;
+ }
+ }
}
- }
- /*
- Test (WA1) partially - that no other keypart after the last infix part is
- referenced in the query.
- */
- if (first_non_infix_part)
- {
- cur_part= first_non_infix_part +
- (min_max_arg_part && (min_max_arg_part < last_part));
- for (; cur_part != last_part; cur_part++)
+ /*
+ Test (WA1) partially - that no other keypart after the last infix part is
+ referenced in the query.
+ */
+ if (first_non_infix_part)
{
- if (bitmap_is_set(table->read_set, cur_part->field->field_index))
- goto next_index;
+ cur_part= first_non_infix_part +
+ (min_max_arg_part && (min_max_arg_part < last_part));
+ for (; cur_part != last_part; cur_part++)
+ {
+ if (bitmap_is_set(table->read_set, cur_part->field->field_index))
+ {
+ trace_idx.add("usable", false).
+ add_str("cause", "keypart_after_infix_in_query");
+ goto next_index;
+ }
+ }
}
- }
- /* If we got to this point, cur_index_info passes the test. */
- key_infix_parts= cur_key_infix_len ? (uint)
- (first_non_infix_part - first_non_group_part) : 0;
- cur_used_key_parts= cur_group_key_parts + key_infix_parts;
+ /* If we got to this point, cur_index_info passes the test. */
+ key_infix_parts= cur_key_infix_len ? (uint)
+ (first_non_infix_part - first_non_group_part) : 0;
+ cur_used_key_parts= cur_group_key_parts + key_infix_parts;
- /* Compute the cost of using this index. */
- if (tree)
- {
- /* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
- cur_index_tree= get_index_range_tree(cur_index, tree, param,
- &cur_param_idx);
- /* Check if this range tree can be used for prefix retrieval. */
- COST_VECT dummy_cost;
- uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL;
- uint mrr_bufsize=0;
- cur_quick_prefix_records= check_quick_select(param, cur_param_idx,
- FALSE /*don't care*/,
- cur_index_tree, TRUE,
- &mrr_flags, &mrr_bufsize,
- &dummy_cost);
- }
- cost_group_min_max(table, cur_index_info, cur_used_key_parts,
- cur_group_key_parts, tree, cur_index_tree,
- cur_quick_prefix_records, have_min, have_max,
- &cur_read_cost, &cur_records);
- /*
- If cur_read_cost is lower than best_read_cost use cur_index.
- Do not compare doubles directly because they may have different
- representations (64 vs. 80 bits).
- */
- if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost))
- {
- index_info= cur_index_info;
- index= cur_index;
- best_read_cost= cur_read_cost;
- best_records= cur_records;
- best_index_tree= cur_index_tree;
- best_quick_prefix_records= cur_quick_prefix_records;
- best_param_idx= cur_param_idx;
- group_key_parts= cur_group_key_parts;
- group_prefix_len= cur_group_prefix_len;
- key_infix_len= cur_key_infix_len;
- if (key_infix_len)
- memcpy (key_infix, cur_key_infix, sizeof (key_infix));
- used_key_parts= cur_used_key_parts;
- }
+ /* Compute the cost of using this index. */
+ if (tree)
+ {
+ /* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
+ cur_index_tree= get_index_range_tree(cur_index, tree, param,
+ &cur_param_idx);
+ /* Check if this range tree can be used for prefix retrieval. */
+ COST_VECT dummy_cost;
+ uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL;
+ uint mrr_bufsize=0;
+ cur_quick_prefix_records= check_quick_select(param, cur_param_idx,
+ FALSE /*don't care*/,
+ cur_index_tree, TRUE,
+ &mrr_flags, &mrr_bufsize,
+ &dummy_cost);
+ }
+ cost_group_min_max(table, cur_index_info, cur_used_key_parts,
+ cur_group_key_parts, tree, cur_index_tree,
+ cur_quick_prefix_records, have_min, have_max,
+ &cur_read_cost, &cur_records);
+ /*
+ If cur_read_cost is lower than best_read_cost use cur_index.
+ Do not compare doubles directly because they may have different
+ representations (64 vs. 80 bits).
+ */
+ trace_idx.add("records", cur_records).add("cost", cur_read_cost);
+ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost))
+ {
+ index_info= cur_index_info;
+ index= cur_index;
+ best_read_cost= cur_read_cost;
+ best_records= cur_records;
+ best_index_tree= cur_index_tree;
+ best_quick_prefix_records= cur_quick_prefix_records;
+ best_param_idx= cur_param_idx;
+ group_key_parts= cur_group_key_parts;
+ group_prefix_len= cur_group_prefix_len;
+ key_infix_len= cur_key_infix_len;
+ if (key_infix_len)
+ memcpy (key_infix, cur_key_infix, sizeof (key_infix));
+ used_key_parts= cur_used_key_parts;
+ }
next_index:;
+ }
}
if (!index_info) /* No usable index found. */
DBUG_RETURN(NULL);
@@ -10102,8 +10579,11 @@ get_best_group_min_max(PARAM *param, SEL
!check_group_min_max_predicates(join->conds, min_max_arg_item,
(index_info->flags & HA_SPATIAL) ?
Field::itMBR : Field::itRAW))
+ {
+ trace_group.add("usable",false).
+ add_str("cause", "unsupported_predicate_on_agg_attribute");
DBUG_RETURN(NULL);
-
+ }
/* The query passes all tests, so construct a new TRP object. */
read_plan= new (param->mem_root)
TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct,
@@ -10123,6 +10603,7 @@ get_best_group_min_max(PARAM *param, SEL
read_plan->records= best_records;
if (read_time < best_read_cost && is_agg_distinct)
{
+ trace_group.add("is_index_scan", true);
read_plan->read_cost= 0;
read_plan->use_index_scan();
}
@@ -11782,7 +12263,6 @@ static void print_sel_tree(PARAM *param,
tmp.append(STRING_WITH_LEN("(empty)"));
DBUG_PRINT("info", ("SEL_TREE: %p (%s) scans: %s", tree, msg, tmp.ptr()));
- fprintf(DBUG_FILE,"SEL_TREE: %p (%s) scans: %s", tree, msg, tmp.ptr());
DBUG_VOID_RETURN;
}
@@ -11822,87 +12302,48 @@ static void print_ror_scans_arr(TABLE *t
#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
-/*
- Print a key into a stream
-
- SYNOPSIS
- key_part Index components description
- key Key tuple
- used_length Key tuple length
-*/
+/**
+ Append range info to a string
-static void
-print_key2(String *out, KEY_PART_INFO *key_part, const uchar *key,
- uint used_length)
+ @param[in,out] out String the range info is appended to
+ @param[in] key_parts Index components description
+ @param[in] min_key Key tuple describing lower bound of range
+ @param[in] min_length Length of min_key
+ @param[in] max_key Key tuple describing upper bound of range
+ @param[in] max_length Length of max_key
+ @param[in] flag Key range flags defining what min_key
+ and max_key represent @see my_base.h
+ */
+static void append_range(String *out,
+ const KEY_PART_INFO *key_parts,
+ const uchar *min_key, const uint16 min_length,
+ const uchar *max_key, const uint16 max_length,
+ const uint flag)
{
- const uchar *key_end= key+used_length;
- String tmp;
- uint store_length;
- TABLE *table= key_part->field->table;
- my_bitmap_map *old_sets[2];
-
- dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
-
- for (; key < key_end; key+=store_length, key_part++)
- {
- Field *field= key_part->field;
- store_length= key_part->store_length;
-
- if (field->real_maybe_null())
- {
- if (*key)
- {
- out->append("NULL", 4);
- continue;
- }
- key++; // Skip null byte
- store_length--;
- }
- field->set_key_image(key, key_part->length);
- if (field->type() == MYSQL_TYPE_BIT)
- (void) field->val_int_as_str(&tmp, 1);
- else
- field->val_str(&tmp);
- out->append(tmp.ptr(), tmp.length());
- if (key+store_length < key_end)
- out->append("'/",1);
- }
- dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
-}
-
+ if (out->length() > 0)
+ out->append(STRING_WITH_LEN(" : "));
-static void print_range(Opt_trace_context *out, KEY_PART_INFO *key_parts,
- const uchar *min_key, uint16 min_length,
- const uchar *max_key, uint16 max_length,
- uint flag)
-{
- String tmp;
if (!(flag & NO_MIN_RANGE))
{
- print_key2(&tmp, key_parts, min_key, min_length);
+ print_key2(out, key_parts, min_key, min_length);
if (flag & NEAR_MIN)
- tmp.append(" < ");
+ out->append(STRING_WITH_LEN(" < "));
else
- tmp.append(" <= ");
+ out->append(STRING_WITH_LEN(" <= "));
}
- tmp.append("X");
+ out->append(key_parts->field->field_name);
if (!(flag & NO_MAX_RANGE))
{
if (flag & NEAR_MAX)
- tmp.append(" < ");
+ out->append(STRING_WITH_LEN(" < "));
else
- tmp.append(" <= ");
- print_key2(&tmp, key_parts, max_key, max_length);
+ out->append(STRING_WITH_LEN(" <= "));
+ print_key2(out, key_parts, max_key, max_length);
}
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- OPT_TRACE(out, add(tmp.c_ptr()));
-#endif
}
-
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
{
char buf[MAX_KEY/8+1];
@@ -11927,20 +12368,18 @@ static void print_quick(QUICK_SELECT_I *
DBUG_UNLOCK_FILE;
DBUG_VOID_RETURN;
}
-#endif
-
void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
{
Opt_trace_context *out= current_thd->opt_trace;
+ Opt_trace_object oto(out, "range_scan");
+ oto.add_str("index", head->key_info[index].name,
+ strlen(head->key_info[index].name)).
+ add("key_length", max_used_key_length).
+ add("used_keyparts", used_key_parts);
+
+ Opt_trace_array trace_range(out, "ranges");
/* purecov: begin inspected */
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto(out, "range_select");
- oto.add(head->key_info[index].name, "index").
- add(static_cast<ulonglong>(max_used_key_length), "key_length");
-
- Opt_trace_array ota(out, "ranges");
-#endif
if (TRUE)
{
QUICK_RANGE *range;
@@ -11948,72 +12387,67 @@ void QUICK_RANGE_SELECT::dbug_dump(int i
QUICK_RANGE **end_range= pr + ranges.elements;
for (; pr != end_range; ++pr)
{
+ String range_info;
+ range_info.set_charset(system_charset_info);
range= *pr;
- print_range(out, head->key_info[index].key_part,
- range->min_key, range->min_length,
- range->max_key, range->max_length,
- range->flag);
+ append_range(&range_info, head->key_info[index].key_part,
+ range->min_key, range->min_length,
+ range->max_key, range->max_length,
+ range->flag);
+ trace_range.add_str(range_info.ptr(), range_info.length());
}
}
/* purecov: end */
}
-
void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
Opt_trace_context *out= current_thd->opt_trace;
-#endif
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
QUICK_RANGE_SELECT *quick;
/* purecov: begin inspected */
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto(out, "index_merge_sort_union");
-#endif
+ Opt_trace_array ota(out, "index_merge");
while ((quick= it++))
+ {
+ Opt_trace_object wrapper(out);
quick->dbug_dump(indent+2, verbose);
+ }
if (pk_quick_select)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
Opt_trace_object oto2(out, "clustered_pk_scan");
-#endif
pk_quick_select->dbug_dump(indent+2, verbose);
}
}
void QUICK_ROR_INTERSECT_SELECT::dbug_dump(int indent, bool verbose)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
Opt_trace_context *out= current_thd->opt_trace;
-#endif
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
QUICK_RANGE_SELECT *quick;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto(out, "index_merge_intersect");
-#endif
+ Opt_trace_array ota(out, "index_roworder_intersect");
while ((quick= it++))
+ {
+ Opt_trace_object wrapper(out);
quick->dbug_dump(indent+2, verbose);
+ }
if (cpk_quick)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
Opt_trace_object oto2(out, "clustered_pk_scan");
-#endif
cpk_quick->dbug_dump(indent+2, verbose);
}
}
void QUICK_ROR_UNION_SELECT::dbug_dump(int indent, bool verbose)
{
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
Opt_trace_context *out= current_thd->opt_trace;
-#endif
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
QUICK_SELECT_I *quick;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object oto(out, "index_merge_sort_union_intersect");
-#endif
+ Opt_trace_array ota(out, "index_roworder_union");
while ((quick= it++))
+ {
+ Opt_trace_object wrapper(out);
quick->dbug_dump(indent+2, verbose);
+ }
}
@@ -12039,6 +12473,11 @@ void QUICK_ROR_UNION_SELECT::dbug_dump(i
void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
{
+ Opt_trace_context *out= current_thd->opt_trace;
+ Opt_trace_object oto(out, "index_group");
+ oto.add_str("index", index_info->name, strlen(index_info->name)).
+ add("key_length", max_used_key_length);
+
fprintf(DBUG_FILE,
"%*squick_group_min_max_select: index %s (%d), length: %d\n",
indent, "", index_info->name, index, max_used_key_length);
=== modified file 'sql/opt_range.h'
--- a/sql/opt_range.h 2010-08-05 13:51:44 +0000
+++ b/sql/opt_range.h 2010-10-22 08:31:43 +0000
@@ -33,6 +33,7 @@
*/
#include "sql_class.h" // set_var.h: THD
#include "set_var.h" /* Item */
+#include "opt_trace.h"
class JOIN;
class Item_sum;
@@ -863,6 +864,12 @@ class SQL_SELECT :public Sql_alloc {
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
{
key_map tmp(key_map::ALL_BITS);
+
+ /* Entrypoint for insert/update/deletes with condition.
+ test_quick_select adds tracing with keys, and we are currently
+ in a trace array that does not accept keys.
+ */
+ Opt_trace_object wrapper(thd->opt_trace);
return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0;
}
inline bool skip_record(THD *thd, bool *skip_record)
=== modified file 'sql/opt_trace.cc'
--- a/sql/opt_trace.cc 2010-10-21 13:03:30 +0000
+++ b/sql/opt_trace.cc 2010-10-22 08:31:43 +0000
@@ -377,12 +377,13 @@ const char *Opt_trace_context::flag_name
const char *Opt_trace_context::feature_names[]=
{
- "misc", "greedy_search", "default", NullS
+ "misc", "greedy_search", "range_optimizer", "default", NullS
};
const Opt_trace_context::feature_value Opt_trace_context::FEATURES_DEFAULT=
Opt_trace_context::feature_value(Opt_trace_context::MISC |
- Opt_trace_context::GREEDY_SEARCH);
+ Opt_trace_context::GREEDY_SEARCH |
+ Opt_trace_context::RANGE_OPTIMIZER);
Opt_trace_context::Opt_trace_context(void):
oldest_stmt_to_show(NULL), newest_stmt_to_show(NULL), stmt_to_del(NULL),
=== modified file 'sql/opt_trace.h'
--- a/sql/opt_trace.h 2010-10-21 20:24:51 +0000
+++ b/sql/opt_trace.h 2010-10-22 08:31:43 +0000
@@ -370,6 +370,8 @@ public:
@c sys_vars.cc:
@li "misc" = anything unclassified
@li "greedy_search" = the greedy search for a plan
+ @li "range_optimizer" = the cost analysis of accessing data through
+ ranges in indices
@li "default".
*/
static const char *feature_names[];
@@ -380,7 +382,8 @@ public:
from parent", disabling MISC makes an empty trace).
*/
MISC= 1,
- GREEDY_SEARCH= 2 ///@todo range opt, join cache, semijoin...
+ GREEDY_SEARCH= 2,
+ RANGE_OPTIMIZER= 4 ///@todo join cache, semijoin...
/* if you add here, update FEATURES_DEFAULT! */
};
static const feature_value FEATURES_DEFAULT;
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2010-10-21 13:03:30 +0000
+++ b/sql/sql_select.cc 2010-10-22 08:31:43 +0000
@@ -259,6 +259,10 @@ void select_describe(JOIN *join, bool ne
bool distinct, const char *message=NullS);
static Item *remove_additional_cond(Item* conds);
static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
+static void trace_indices_added_group_distinct(Opt_trace_context *trace,
+ const JOIN_TAB *join_tab,
+ const key_map new_keys,
+ const char* cause);
static bool replace_subcondition(JOIN *join, Item **tree,
Item *old_cond, Item *new_cond,
bool do_fix_fields);
@@ -4362,7 +4366,9 @@ int pull_out_semijoin_tables(JOIN *join)
if (tbl->table->map & join->const_table_map)
{
pulled_tables |= tbl->table->map;
- Opt_trace_object(trace).add_str("table", tbl->table->alias).
+ Opt_trace_object(trace).
+ add_str("database", tbl->db, strlen(tbl->db)).
+ add_str("table", tbl->alias, strlen(tbl->alias)).
add("constant", true);
}
}
@@ -4388,7 +4394,9 @@ int pull_out_semijoin_tables(JOIN *join)
{
pulled_a_table= TRUE;
pulled_tables |= tbl->table->map;
- Opt_trace_object(trace).add_str("table", tbl->table->alias).
+ Opt_trace_object(trace).
+ add_str("database", tbl->db, strlen(tbl->db)).
+ add_str("table", tbl->alias, strlen(tbl->alias)).
add("functionally_dependent", true);
/*
Pulling a table out of uncorrelated subquery in general makes
@@ -4947,14 +4955,22 @@ make_join_statistics(JOIN *join, TABLE_L
for (s= stat ; s < stat_end ; s++)
{
+ Opt_trace_object trace_table(join->thd->opt_trace);
+ trace_table.add_str("database",s->join->tables_list->db,
+ strlen(s->join->tables_list->db)).
+ add_str("table", s->table->alias, strlen(s->table->alias));
if (s->type == JT_SYSTEM || s->type == JT_CONST)
{
+ trace_table.add("records", 1).
+ add("cost", 1);
+
+ trace_table.add_str("cause", (s->type == JT_SYSTEM) ?
+ "system_table": "const_table");
+
/* Only one matching row */
s->found_records= s->records= s->read_time=1; s->worst_seeks= 1.0;
continue;
}
- Opt_trace_object trace_one_table(trace);
- trace_one_table.add_str("table", s->table->alias);
/* Approximate found rows and time to read them */
s->found_records= s->records= s->table->file->stats.records;
s->read_time= (ha_rows) s->table->file->scan_time();
@@ -4985,10 +5001,6 @@ make_join_statistics(JOIN *join, TABLE_L
(s->table->pos_in_table_list->embedding && // (3)
s->table->pos_in_table_list->embedding->sj_on_expr))) // (3)
{
-#ifdef NO_OPT_TRACE_FOR_RANGE_OPT
- Opt_trace_object(join->thd->opt_trace, "more_range_optimizer_trace").
- add_str("TODO?", "yes!");
-#endif
ha_rows records;
SQL_SELECT *select;
select= make_select(s->table, found_const_table_map,
@@ -5017,9 +5029,16 @@ make_join_statistics(JOIN *join, TABLE_L
{
/* Generate empty row */
s->info= "Impossible ON condition";
+ trace_table.add("returning_empty_null_row", true).
+ add_str("cause", "impossible_on_condition");
found_const_table_map|= s->table->map;
s->type= JT_CONST;
mark_as_null_row(s->table); // All fields are NULL
+ }
+ else
+ {
+ trace_table.add("records", 0).
+ add_str("cause", "impossible_where_condition");
}
}
if (records != HA_POS_ERROR)
@@ -6498,11 +6517,14 @@ add_group_and_distinct_keys(JOIN *join,
Item_field *cur_item;
key_map possible_keys;
+ const char* cause;
+
if (join->group_list)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
(*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
(uchar*) &indexed_fields);
+ cause= (char*)"group_by";
}
else if (join->select_distinct)
{ /* Collect all query fields referenced in the SELECT clause. */
@@ -6512,10 +6534,12 @@ add_group_and_distinct_keys(JOIN *join,
while ((item= select_items_it++))
item->walk(&Item::collect_item_field_processor, 0,
(uchar*) &indexed_fields);
+ cause= (char*)"distinct";
}
else if (is_indexed_agg_distinct(join, &indexed_fields))
{
join->sort_and_group= 1;
+ cause= (char*) "indexed_distinct_aggregate";
}
else
return;
@@ -6531,8 +6555,49 @@ add_group_and_distinct_keys(JOIN *join,
possible_keys.intersect(cur_item->field->part_of_key);
}
- if (!possible_keys.is_clear_all())
+ if (!possible_keys.is_clear_all() &&
+ !(possible_keys == join_tab->const_keys))
+ {
+ Opt_trace_context *trace= join->thd->opt_trace;
+ if (trace && trace->is_started())
+ {
+ trace_indices_added_group_distinct(trace, join_tab,
+ possible_keys, cause);
+ }
join_tab->const_keys.merge(possible_keys);
+ }
+}
+
+/**
+ Print keys that were appended to join_tab->const_keys because they
+ can be used for GROUP BY or DISTINCT to the optimizer trace.
+
+ @param thd Thread for the connection that submitted the query
+ @param join_tab The table the indices cover
+ @param new_keys The keys that are considered useful because they can
+ be used for GROUP BY or DISTINCT
+ @param cause Zero-terminated string with reason for adding indices
+ to const_keys
+
+ @see add_group_and_distinct_keys()
+ */
+static void trace_indices_added_group_distinct(Opt_trace_context *trace,
+ const JOIN_TAB *join_tab,
+ const key_map new_keys,
+ const char* cause)
+{
+ KEY *key_info= join_tab->table->key_info;
+ key_map existing_keys= join_tab->const_keys;
+ uint nbrkeys= join_tab->table->s->keys;
+
+ Opt_trace_object trace_summary(trace, "const_keys_added");
+ {
+ Opt_trace_array trace_key(trace,"keys");
+ for (uint j= 0 ; j < nbrkeys ; j++)
+ if (new_keys.is_set(j) && !existing_keys.is_set(j))
+ trace_key.add_str(key_info[j].name, strlen(key_info[j].name));
+ }
+ trace_summary.add_str("cause", cause);
}
@@ -6974,9 +7039,9 @@ best_access_path(JOIN *join,
loose_scan_opt.next_ref_key();
DBUG_PRINT("info", ("Considering ref access on key %s",
keyuse->table->key_info[keyuse->key].name));
- Opt_trace_object trace_index_path(trace);
- trace_index_path.add_str("access_type", "index").
- add_str("index", keyinfo->name);
+ Opt_trace_object trace_access_idx(thd->opt_trace);
+ trace_access_idx.add_str("access_type", "index").
+ add_str("index", keyinfo->name, strlen(keyinfo->name));
/*
True if we find some keys from the range optimizer that match more
@@ -7032,7 +7097,7 @@ best_access_path(JOIN *join,
*/
if (!found_part && !ft_key && !loose_scan_opt.have_a_case())
{
- trace_index_path.add("usable", false);
+ trace_access_idx.add("usable", false);
goto done_with_index; // Nothing usable found
}
@@ -7311,7 +7376,7 @@ best_access_path(JOIN *join,
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
} /* not ft_key */
- trace_index_path.add("cost", tmp).add("records", records);
+ trace_access_idx.add("records", records).add("cost", tmp);
/** @todo trace quick_matches_more_parts etc? */
if (tmp < best_time - records/(double) TIME_FOR_COMPARE ||
(quick_matches_more_parts &&
@@ -7326,13 +7391,12 @@ best_access_path(JOIN *join,
best_ref_depends_map= found_ref;
}
done_with_index:
- trace_index_path.add("chosen", best_key == start_key);
+ trace_access_idx.add("chosen", best_key == start_key);
} /* for each key */
records= best_records;
}
- Opt_trace_object trace_scan_path(trace);
- trace_scan_path.add_str("access_type", "table scan");
+ Opt_trace_object trace_access_scan(thd->opt_trace);
/*
Don't test table scan if it can't be better.
Prefer key lookup if we would use the same key for scanning.
@@ -7363,28 +7427,38 @@ best_access_path(JOIN *join,
*/
if (!(records >= s->found_records || best > s->read_time)) // (1)
{
- trace_scan_path.add("cost", s->read_time).
- add("records", s->found_records);
+ trace_access_scan.add_str("access_type", s->quick ? "range" : "scan");
+ trace_access_scan.add("cost", s->read_time).
+ add("records", s->found_records).
+ add("chosen", false).
+ add_str("cause", "index_cheaper");
+
goto skip_table_scan;
}
if ((s->quick && best_key && s->quick->index == best_key->key && // (2)
best_max_key_part >= s->table->quick_key_parts[best_key->key])) // (2)
{
- trace_scan_path.add("heuristic_index_must_be_cheaper", true);
+ trace_access_scan.add_str("access_type", "range").
+ add("chosen", false).
+ add_str("cause", "heuristic_index_must_be_cheaper");
goto skip_table_scan;
}
if (((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
! s->table->covering_keys.is_clear_all() && best_key && !s->quick))// (3)
{
- trace_scan_path.add("index_is_covering", true);
+ trace_access_scan.add_str("access_type", s->quick ? "range" : "scan");
+ trace_access_scan.add("chosen", false).
+ add_str("cause", "covering_index_better_than_full_scan");
goto skip_table_scan;
}
if ((s->table->force_index && best_key && !s->quick)) // (4)
{
- trace_scan_path.add("FORCE_INDEX_used", true);
+ trace_access_scan.add_str("access_type", "scan").
+ add("chosen", false).
+ add_str("cause", "force_index");
goto skip_table_scan;
}
@@ -7417,6 +7491,7 @@ best_access_path(JOIN *join,
if (s->quick)
{
+ trace_access_scan.add_str("access_type", "range");
/*
For each record we:
- read record range through 'quick'
@@ -7434,6 +7509,7 @@ best_access_path(JOIN *join,
}
else
{
+ trace_access_scan.add_str("access_type", "scan");
/* Estimate cost of reading table. */
if (s->table->force_index && !best_key)
tmp= s->table->file->read_time(s->ref.key, 1, s->records);
@@ -7453,6 +7529,7 @@ best_access_path(JOIN *join,
}
else
{
+ trace_access_scan.add("using_join_cache", true);
/*
We read the table as many times as join buffer becomes full.
It would be more exact to round the result of the division with
@@ -7472,7 +7549,8 @@ best_access_path(JOIN *join,
}
}
- trace_scan_path.add("cost", tmp).add("records", rows2double(rnd_records));
+ trace_access_scan.add("records", rows2double(rnd_records)).
+ add("cost", tmp);
/*
We estimate the cost of evaluating WHERE clause for found records
as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
@@ -7495,11 +7573,10 @@ best_access_path(JOIN *join,
join->outer_join)));
}
}
+ trace_access_scan.add("chosen", best_key == NULL);
skip_table_scan:
- trace_scan_path.add("chosen", best_key == NULL);
-
/* Update the cost information for the current partial plan */
pos->records_read= records;
pos->read_time= best;
@@ -7515,7 +7592,10 @@ skip_table_scan:
idx == join->const_tables &&
s->table == join->sort_by_table &&
join->unit->select_limit_cnt >= records)
+ {
+ trace_access_scan.add("use_temp_table", true);
join->sort_by_table= (TABLE*) 1; // Must use temporary table
+ }
DBUG_VOID_RETURN;
}
@@ -8262,7 +8342,10 @@ best_extension_by_limited_search(JOIN
double current_record_count, current_read_time;
POSITION *position= join->positions + idx;
Opt_trace_object trace_one_table(trace);
- trace_one_table.add_str("table", s->table->alias);
+ trace_one_table.
+ add_str("database", s->join->tables_list->db,
+ strlen(s->join->tables_list->db)).
+ add_str("table", s->table->alias, strlen(s->table->alias));
/* Find the best access method from 's' to the current partial plan */
POSITION loose_scan_pos;
@@ -8684,7 +8767,10 @@ static bool fix_semijoin_strategies_for_
Opt_trace_object oto1(trace,
"reconsidering_access_paths_for_semijoin");
oto1.add_str("strategy", "MaterializationScan").
- add_str("table", join->best_positions[i].table->table->alias);
+ add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db)).
+ add_str("table", join->best_positions[i].table->table->alias,
+ strlen(join->best_positions[i].table->table->alias));
best_access_path(join, join->best_positions[i].table, rem_tables, i, FALSE,
prefix_rec_count, join->best_positions + i, &dummy);
prefix_rec_count *= join->best_positions[i].records_read;
@@ -8721,7 +8807,10 @@ static bool fix_semijoin_strategies_for_
Opt_trace_object oto1(trace,
"reconsidering_access_paths_for_semijoin");
oto1.add_str("strategy", "FirstMatch").
- add_str("table", join->best_positions[idx].table->table->alias);
+ add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db)).
+ add_str("table", join->best_positions[idx].table->table->alias,
+ strlen(join->best_positions[idx].table->table->alias));
best_access_path(join, join->best_positions[idx].table,
rem_tables, idx, TRUE /* no jbuf */,
record_count, join->best_positions + idx, &dummy);
@@ -8755,7 +8844,10 @@ static bool fix_semijoin_strategies_for_
Opt_trace_object oto1(trace,
"reconsidering_access_paths_for_semijoin");
oto1.add_str("strategy", "LooseScan").
- add("table", join->best_positions[idx].table->table->alias);
+ add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db)).
+ add_str("table", join->best_positions[idx].table->table->alias,
+ strlen(join->best_positions[idx].table->table->alias));
best_access_path(join, join->best_positions[idx].table,
rem_tables, idx, TRUE /* no jbuf */,
record_count, join->best_positions + idx,
@@ -9629,7 +9721,9 @@ static bool make_join_select(JOIN *join,
{
tab= join->join_tab+i;
Opt_trace_object trace_one_table(thd->opt_trace);
- trace_one_table.add_str("table", tab->table->alias);
+ trace_one_table.add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db)).
+ add_str("table", tab->table->alias, strlen(tab->table->alias));
/*
first_inner is the X in queries like:
SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X
@@ -13786,7 +13880,10 @@ void optimize_wo_join_buffering(JOIN *jo
{
/* Find the best access method that would not use join buffering */
Opt_trace_object trace_one_table(trace);
- trace_one_table.add_str("table", rs->table->alias);
+ trace_one_table.add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db));
+ trace_one_table.add_str("table", rs->table->alias,
+ strlen(rs->table->alias));
best_access_path(join, rs, reopt_remaining_tables, i,
i < no_jbuf_before, inner_fanout * outer_fanout,
&pos, &loose_scan_pos);
@@ -14227,8 +14324,10 @@ void advance_sj_state(JOIN *join, table_
for (i= first_tab + table_count; i <= idx; i++)
{
Opt_trace_object trace_one_table(trace);
- trace_one_table.add_str("table",
- join->positions[i].table->table->alias);
+ trace_one_table.add_str("database", join->tables_list->db,
+ strlen(join->tables_list->db)).
+ add_str("table", join->positions[i].table->table->alias,
+ strlen(join->positions[i].table->table->alias));
best_access_path(join, join->positions[i].table, rem_tables, i, FALSE,
prefix_rec_count, &curpos, &dummy);
prefix_rec_count *= curpos.records_read;
Attachment: [text/bzr-bundle] bzr/jorgen.loland@oracle.com-20101022083143-0a6nyb3mpamtl33r.bundle