Commit be8709eb authored by Varun Gupta's avatar Varun Gupta

MDEV-6111 Optimizer Trace

This task involves the implementation for the optimizer trace.

This feature produces a trace for any SELECT/UPDATE/DELETE/,
which contains information about decisions taken by the optimizer during
the optimization phase (choice of table access method, various costs,
transformations, etc). This feature would help to tell why some decisions were
taken by the optimizer and why some were rejected.

Trace is session-local, controlled by the @@optimizer_trace variable.
To enable optimizer trace we need to write:
   set @@optimizer_trace variable= 'enabled=on';

To display the trace one can run:
   SELECT trace FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

This task also involves:
    MDEV-18489: Limit the memory used by the optimizer trace
    introduces a switch optimizer_trace_max_mem_size which limits
    the memory used by the optimizer trace. This was implemented by
    Sergei Petrunia.
parent 6b979416
......@@ -122,6 +122,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_tvc.cc ../sql/sql_tvc.h
../sql/opt_split.cc
../sql/item_vers.cc
../sql/opt_trace.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
......
......@@ -67,6 +67,7 @@ GLOBAL_VARIABLES
INDEX_STATISTICS
KEY_CACHES
KEY_COLUMN_USAGE
OPTIMIZER_TRACE
PARAMETERS
PARTITIONS
PLUGINS
......@@ -864,6 +865,8 @@ information_schema COLUMNS COLUMN_DEFAULT
information_schema COLUMNS COLUMN_TYPE
information_schema COLUMNS GENERATION_EXPRESSION
information_schema EVENTS EVENT_DEFINITION
information_schema OPTIMIZER_TRACE QUERY
information_schema OPTIMIZER_TRACE TRACE
information_schema PARAMETERS DTD_IDENTIFIER
information_schema PARTITIONS PARTITION_EXPRESSION
information_schema PARTITIONS SUBPARTITION_EXPRESSION
......
......@@ -43,6 +43,7 @@ INNODB_TABLESPACES_SCRUBBING
INNODB_TRX
KEY_CACHES
KEY_COLUMN_USAGE
OPTIMIZER_TRACE
PARAMETERS
PARTITIONS
PLUGINS
......@@ -123,6 +124,7 @@ INNODB_TABLESPACES_SCRUBBING SPACE
INNODB_TRX trx_id
KEY_CACHES KEY_CACHE_NAME
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
OPTIMIZER_TRACE QUERY
PARAMETERS SPECIFIC_SCHEMA
PARTITIONS TABLE_SCHEMA
PLUGINS PLUGIN_NAME
......@@ -203,6 +205,7 @@ INNODB_TABLESPACES_SCRUBBING SPACE
INNODB_TRX trx_id
KEY_CACHES KEY_CACHE_NAME
KEY_COLUMN_USAGE CONSTRAINT_SCHEMA
OPTIMIZER_TRACE QUERY
PARAMETERS SPECIFIC_SCHEMA
PARTITIONS TABLE_SCHEMA
PLUGINS PLUGIN_NAME
......@@ -288,6 +291,7 @@ INNODB_TABLESPACES_SCRUBBING information_schema.INNODB_TABLESPACES_SCRUBBING 1
INNODB_TRX information_schema.INNODB_TRX 1
KEY_CACHES information_schema.KEY_CACHES 1
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
OPTIMIZER_TRACE information_schema.OPTIMIZER_TRACE 1
PARAMETERS information_schema.PARAMETERS 1
PARTITIONS information_schema.PARTITIONS 1
PLUGINS information_schema.PLUGINS 1
......@@ -358,6 +362,7 @@ Database: information_schema
| INNODB_TRX |
| KEY_CACHES |
| KEY_COLUMN_USAGE |
| OPTIMIZER_TRACE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
......@@ -428,6 +433,7 @@ Database: INFORMATION_SCHEMA
| INNODB_TRX |
| KEY_CACHES |
| KEY_COLUMN_USAGE |
| OPTIMIZER_TRACE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
......@@ -459,5 +465,5 @@ Wildcard: inf_rmation_schema
| information_schema |
SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') GROUP BY TABLE_SCHEMA;
table_schema count(*)
information_schema 65
information_schema 66
mysql 31
......@@ -693,6 +693,12 @@ The following specify which files/extra groups are read (specified before remain
extended_keys, exists_to_in, orderby_uses_equalities,
condition_pushdown_for_derived, split_materialized,
condition_pushdown_for_subquery
--optimizer-trace=name
Controls tracing of the Optimizer:
optimizer_trace=option=val[,option=val...], where option
is one of {enabled} and val is one of {on, off, default}
--optimizer-trace-max-mem-size=#
Maximum allowed size of an optimizer trace
--optimizer-use-condition-selectivity=#
Controls selectivity of which conditions the optimizer
takes into account to calculate cardinality of a partial
......@@ -1563,6 +1569,8 @@ optimizer-prune-level 1
optimizer-search-depth 62
optimizer-selectivity-sampling-limit 100
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on
optimizer-trace
optimizer-trace-max-mem-size 1048576
optimizer-use-condition-selectivity 4
performance-schema FALSE
performance-schema-accounts-size -1
......
This source diff could not be displayed because it is too large. You can view the blob instead.
--source include/not_embedded.inc
SELECT table_name, column_name FROM information_schema.columns where table_name="OPTIMIZER_TRACE";
show variables like 'optimizer_trace';
set optimizer_trace="enabled=on";
show variables like 'optimizer_trace';
set optimizer_trace="enabled=off";
create table t1 (a int, b int);
insert into t1 values (1,2),(2,3);
create table t2 (b int);
insert into t2 values (1),(2);
analyze table t1;
analyze table t2;
create function f1 (a int) returns INT
return 1;
create view v1 as select * from t1 where t1.a=1;
create view v2 as select * from t1 where t1.a=1 group by t1.b;
set optimizer_trace="enabled=on";
--echo # Mergeable views/derived tables
select * from v1;
select * from information_schema.OPTIMIZER_TRACE;
select * from (select * from t1 where t1.a=1)q;
select * from information_schema.OPTIMIZER_TRACE;
--echo # Non-Mergeable views
select * from v2;
select * from information_schema.OPTIMIZER_TRACE;
drop table t1,t2;
drop view v1,v2;
drop function f1;
create table t1(a int, b int);
insert into t1 values (0,0),(1,1),(2,1),(3,2),(4,3),
(5,3),(6,3),(7,3),(8,3),(9,3);
create table t2(a int, b int);
insert into t2 values (0,0),(1,1),(2,1),(3,2),(4,3),
(5,3),(6,3),(7,3),(8,3),(9,3);
ANALYZE TABLE t1;
ANALYZE TABLE t2;
create view v1 as select a from t1 group by b;
create view v2 as select a from t2;
--echo # Mergeable view
explain select * from v2 ;
select * from information_schema.OPTIMIZER_TRACE;
--echo # Non-Mergeable view
explain select * from v1 ;
select * from information_schema.OPTIMIZER_TRACE;
drop table t1,t2;
drop view v1,v2;
--echo #
--echo # print ref-keyues array
--echo #
create table t0 (a int);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int, key(a));
insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
create table t2(a int, b int, c int , key(a));
insert into t2 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
analyze table t1;
analyze table t2;
explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b;
select * from information_schema.OPTIMIZER_TRACE;
drop table t1,t2,t0;
--echo #
--echo # group_by min max optimization
--echo #
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT NOT NULL, KEY(a));
--disable_query_log
INSERT INTO t1(a) VALUES (1), (2), (3), (4);
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
INSERT INTO t1(a) SELECT a FROM t1;
--enable_query_log
analyze table t1;
EXPLAIN SELECT DISTINCT a FROM t1;
select * from information_schema.OPTIMIZER_TRACE;
drop table t1;
--echo #
--echo # With group by , where clause and MIN/MAX function
--echo #
CREATE TABLE t1 (a INT, b INT, c int, d int, KEY(a,b,c,d));
INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4), (1,0,1,1), (3,2,3,3), (4,5,4,4);
ANALYZE TABLE t1;
EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a;
select * from information_schema.OPTIMIZER_TRACE;
DROP TABLE t1;
CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a));
INSERT INTO t1 values (1,'2001-01-01'),(1,'2001-01-02'),
(1,'2001-01-03'),(1,'2001-01-04'),
(2,'2001-01-01'),(2,'2001-01-02'),
(2,'2001-01-03'),(2,'2001-01-04'),
(3,'2001-01-01'),(3,'2001-01-02'),
(3,'2001-01-03'),(3,'2001-01-04'),
(4,'2001-01-01'),(4,'2001-01-02'),
(4,'2001-01-03'),(4,'2001-01-04');
set optimizer_trace='enabled=on';
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
--echo #
--echo # Late ORDER BY optimization
--echo #
create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table one_k(a int primary key);
insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
create table t1 (
pk int not null,
a int,
b int,
c int,
filler char(100),
KEY a_a(c),
KEY a_c(a,c),
KEY a_b(a,b)
);
insert into t1
select a, a,a,a, 'filler-dataaa' from test.one_k;
update t1 set a=1 where pk between 0 and 180;
update t1 set b=2 where pk between 0 and 20;
analyze table t1;
set optimizer_trace='enabled=on';
explain select * from t1 where a=1 and b=2 order by c limit 1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1,ten,one_k;
--echo #
--echo # TABLE ELIMINATION
--echo #
create table t1 (a int);
insert into t1 values (0),(1),(2),(3);
create table t0 as select * from t1;
create table t2 (a int primary key, b int)
as select a, a as b from t1 where a in (1,2);
create table t3 (a int primary key, b int)
as select a, a as b from t1 where a in (1,3);
set optimizer_trace='enabled=on';
analyze table t1;
analyze table t2;
analyze table t3;
--echo # table t2 should be eliminated
explain
select t1.a from t1 left join t2 on t1.a=t2.a;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
--echo # no tables should be eliminated
explain select * from t1 left join t2 on t2.a=t1.a;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
--echo # multiple tables are eliminated
explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and t3.a=t1.a;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t0, t1, t2, t3;
--echo #
--echo # IN subquery to sem-join is traced
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1(a int, b int);
insert into t1 values (0,0),(1,1),(2,2);
create table t2 as select * from t1;
create table t11(a int, b int);
create table t10 (pk int, a int);
insert into t10 select a,a from t0;
create table t12 like t10;
insert into t12 select * from t10;
analyze table t1,t10;
set optimizer_trace='enabled=on';
explain extended select * from t1 where a in (select pk from t10);
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t0,t1,t11,t10,t12,t2;
--echo #
--echo # Selectivities for columns and indexes.
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (
pk int,
a int,
b int,
key pk(pk),
key pk_a(pk,a),
key pk_a_b(pk,a,b));
insert into t1 select a,a,a from t0;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (a,b) INDEXES ();
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
set @save_use_stat_tables= @@use_stat_tables;
set @@optimizer_use_condition_selectivity=4;
set @@use_stat_tables= PREFERABLY;
set optimizer_trace='enabled=on';
explain select * from t1 where pk = 2 and a=5 and b=1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
set @@use_stat_tables= @save_use_stat_tables;
drop table t0,t1;
set optimizer_trace="enabled=off";
--echo #
--echo # Tests added to show that sub-statements are not traced
--echo #
create table t1(a int);
insert into t1 values (1),(2),(3),(4);
create table t2(a int);
insert into t2 values (1),(2),(3),(4);
delimiter |;
create function f1(a int) returns int
begin
declare a int default 0;
set a= a+ (select count(*) from t2);
return a;
end|
create function f2(a int) returns int
begin
declare a int default 0;
select count(*) from t2 into a;
return a;
end|
delimiter ;|
set optimizer_trace='enabled=on';
select f1(a) from t1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
select f2(a) from t1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1,t2;
drop function f1;
drop function f2;
set optimizer_trace='enabled=off';
--echo #
--echo # MDEV-18489: Limit the memory used by the optimizer trace
--echo #
create table t1 (a int);
insert into t1 values (1),(2);
set optimizer_trace='enabled=on';
set @save_optimizer_trace_max_mem_size= @@optimizer_trace_max_mem_size;
select * from t1;
select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
set optimizer_trace_max_mem_size=100;
select * from t1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
set optimizer_trace_max_mem_size=0;
select * from t1;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
set optimizer_trace='enabled=off';
set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
--echo #
--echo # MDEV-18527: Optimizer trace for DELETE query shows table:null
--echo #
create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t0 (a int, b int);
insert into t0 select a,a from ten;
alter table t0 add key(a);
set optimizer_trace=1;
explain delete from t0 where t0.a<3;
select * from information_schema.optimizer_trace;
drop table ten,t0;
set optimizer_trace='enabled=off';
--echo #
--echo # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
--echo #
create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t0 (a int, b int);
insert into t0 select a,a from ten;
alter table t0 add key(a);
create table t1 like t0;
insert into t1 select * from t0;
explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3;
select * from information_schema.optimizer_trace;
drop table ten,t0,t1;
set @tmp_opt_switch= @@optimizer_switch;
set optimizer_switch='index_merge_sort_intersection=on';
set optimizer_trace='enabled=on';
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int, filler char(100),
key(a), key(b), key(c));
insert into t1 select
A.a * B.a*10 + C.a*100,
A.a * B.a*10 + C.a*100,
A.a,
'filler'
from t0 A, t0 B, t0 C;
This should use union:
explain select * from t1 where a=1 or b=1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge a,b a,b 5,5 NULL 2 Using union(a,b); Using where
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1 where a=1 or b=1 {
"steps": [
{
"join_preparation": {
"select_id": 1,
"steps": [
{
"expanded_query": "select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t1`.`filler` AS `filler` from `t1` where `t1`.`a` = 1 or `t1`.`b` = 1"
}
]
}
},
{
"join_optimization": {
"select_id": 1,
"steps": [
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "t1.a = 1 or t1.b = 1",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
},
{
"transformation": "constant_propagation",
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "multiple equal(1, t1.a) or multiple equal(1, t1.b)"
}
]
}
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"ref_optimizer_key_uses": []
},
{
"rows_estimation": [
{
"table": "t1",
"range_analysis": {
"table_scan": {
"rows": 1000,
"cost": 231.69
},
"potential_range_indexes": [
{
"index": "a",
"usable": true,
"key_parts": ["a"]
},
{
"index": "b",
"usable": true,
"key_parts": ["b"]
},
{
"index": "c",
"usable": false,
"cause": "not applicable"
}
],
"setup_range_conditions": [],
"group_index_range": {
"chosen": false,
"cause": "no group by or distinct"
},
"analyzing_range_alternatives": {
"range_scan_alternatives": [],
"analyzing_roworder_intersect": {
"cause": "too few roworder scans"
},
"analyzing_sort_intersect": {},
"analyzing_index_merge_union": [
{
"indexes_to_merge": [
{
"range_scan_alternatives": [
{
"index": "a",
"ranges": ["1 <= a <= 1"],
"rowid_ordered": true,
"using_mrr": false,
"index_only": true,
"rows": 1,
"cost": 2.21,
"chosen": true
}
],
"index_to_merge": "a",
"cumulated_cost": 2.21
},
{
"range_scan_alternatives": [
{
"index": "b",
"ranges": ["1 <= b <= 1"],
"rowid_ordered": true,
"using_mrr": false,
"index_only": true,
"rows": 1,
"cost": 2.21,
"chosen": true
}
],
"index_to_merge": "b",
"cumulated_cost": 4.42
}
],
"cost_of_reading_ranges": 4.42,
"use_roworder_union": true,
"cause": "always cheaper than non roworder retrieval",
"analyzing_roworder_scans": [
{
"type": "range_scan",
"index": "a",
"rows": 1,
"ranges": ["1 <= a <= 1"],
"analyzing_roworder_intersect": {
"cause": "too few roworder scans"
}
},
{
"type": "range_scan",
"index": "b",
"rows": 1,
"ranges": ["1 <= b <= 1"],
"analyzing_roworder_intersect": {
"cause": "too few roworder scans"
}
}
],
"index_roworder_union_cost": 6.2137,
"members": 2,
"chosen": true
}
]
},
"chosen_range_access_summary": {
"range_access_plan": {
"type": "index_roworder_union",
"union_of": [
{
"type": "range_scan",
"index": "a",
"rows": 1,
"ranges": ["1 <= a <= 1"]
},
{
"type": "range_scan",
"index": "b",
"rows": 1,
"ranges": ["1 <= b <= 1"]
}
]
},
"rows_for_plan": 2,
"cost_for_plan": 6.2137,
"chosen": true
}
}
},
{
"selectivity_for_indexes": [],
"selectivity_for_columns": []
}
]
},
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "range",
"resulting_rows": 2,
"cost": 6.2137,
"chosen": true
}
]
}
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1 or t1.b = 1",
"attached_conditions_computation": [],
"attached_conditions_summary": [
{
"table": "t1",
"attached": "t1.a = 1 or t1.b = 1"
}
]
}
}
]
}
},
{
"join_execution": {
"select_id": 1,
"steps": []
}
}
]
} 0 0
drop table t0,t1;
set optimizer_trace="enabled=off";
set @@optimizer_switch= @tmp_opt_switch;
--source include/not_embedded.inc
set @tmp_opt_switch= @@optimizer_switch;
set optimizer_switch='index_merge_sort_intersection=on';
set optimizer_trace='enabled=on';
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int, filler char(100),
key(a), key(b), key(c));
insert into t1 select
A.a * B.a*10 + C.a*100,
A.a * B.a*10 + C.a*100,
A.a,
'filler'
from t0 A, t0 B, t0 C;
--echo This should use union:
explain select * from t1 where a=1 or b=1;
select * from information_schema.OPTIMIZER_TRACE;
drop table t0,t1;
set optimizer_trace="enabled=off";
set @@optimizer_switch= @tmp_opt_switch;
create table t1
(
pk1 int not null,
pk2 int not null,
key1 int not null,
key2 int not null,
key (key1),
key (key2),
primary key (pk1, pk2)
)engine=Innodb;
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
set optimizer_trace="enabled=on";
set @tmp_index_merge_ror_cpk=@@optimizer_switch;
set optimizer_switch='extended_keys=off';
explain select * from t1 where pk1 != 0 and key1 = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref PRIMARY,key1 key1 4 const 1 Using index condition
select * from information_schema.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1 where pk1 != 0 and key1 = 1 {
"steps": [
{
"join_preparation": {
"select_id": 1,
"steps": [
{
"expanded_query": "select `t1`.`pk1` AS `pk1`,`t1`.`pk2` AS `pk2`,`t1`.`key1` AS `key1`,`t1`.`key2` AS `key2` from `t1` where `t1`.`pk1` <> 0 and `t1`.`key1` = 1"
}
]
}
},
{
"join_optimization": {
"select_id": 1,
"steps": [
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "t1.pk1 <> 0 and t1.key1 = 1",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
},
{
"transformation": "constant_propagation",
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "t1.pk1 <> 0 and multiple equal(1, t1.key1)"
}
]
}
},
{
"table_dependencies": [
{
"table": "t1",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": []
}
]
},
{
"ref_optimizer_key_uses": [
{
"table": "t1",
"field": "key1",
"equals": "1",
"null_rejecting": false
}
]
},
{
"rows_estimation": [
{
"table": "t1",
"range_analysis": {
"table_scan": {
"rows": 1000,
"cost": 206.1
},
"potential_range_indexes": [
{
"index": "PRIMARY",
"usable": true,
"key_parts": ["pk1", "pk2"]
},
{
"index": "key1",
"usable": true,
"key_parts": ["key1"]
},
{
"index": "key2",
"usable": false,
"cause": "not applicable"
}
],
"setup_range_conditions": [],
"group_index_range": {
"chosen": false,
"cause": "no group by or distinct"
},
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "PRIMARY",
"ranges": ["pk1 < 0", "0 < pk1"],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1001,
"cost": 203.59,
"chosen": true
},
{
"index": "key1",
"ranges": ["1 <= key1 <= 1"],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.21,
"chosen": true
}
],
"analyzing_roworder_intersect": {
"intersecting_indexes": [
{
"index": "key1",
"index_scan_cost": 1,
"cumulateed_index_scan_cost": 1,
"disk_sweep_cost": 1.0014,
"cumulative_total_cost": 2.0014,
"usable": true,
"matching_rows_now": 1,
"intersect_covering_with_this_index": false,
"chosen": true
}
],
"clustered_pk": {
"index_scan_cost": 0.002,
"cumulateed_index_scan_cost": 1.002,
"disk_sweep_cost": 1.0014,
"clustered_pk_added_to_intersect": false,
"cause": "cost"
},
"chosen": false,
"cause": "too few indexes to merge"
},
"analyzing_index_merge_union": []
},
"chosen_range_access_summary": {
"range_access_plan": {
"type": "range_scan",
"index": "key1",
"rows": 1,
"ranges": ["1 <= key1 <= 1"]
},
"rows_for_plan": 1,
"cost_for_plan": 2.21,
"chosen": true
}
}
},
{
"selectivity_for_indexes": [
{
"index_name": "PRIMARY",
"selectivity_from_index": 1.001
},
{
"index_name": "key1",
"selectivity_from_index": 0.001
}
],
"selectivity_for_columns": []
}
]
},
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"best_access_path": {
"considered_access_paths": [
{
"access_type": "ref",
"index": "key1",
"used_range_estimates": true,
"rows": 1,
"cost": 2,
"chosen": true
},
{
"type": "scan",
"chosen": false,
"cause": "cost"
}
]
}
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "t1.key1 = 1 and t1.pk1 <> 0",
"attached_conditions_computation": [],
"attached_conditions_summary": [
{
"table": "t1",
"attached": "t1.pk1 <> 0"
}
]
}
}
]
}
},
{
"join_execution": {
"select_id": 1,
"steps": []
}
}
]
} 0 0
drop table t1;
set @@optimizer_switch= @tmp_index_merge_ror_cpk;
set optimizer_trace="enabled=off";
--source include/not_embedded.inc
--source include/have_innodb.inc
create table t1
(
pk1 int not null,
pk2 int not null,
key1 int not null,
key2 int not null,
key (key1),
key (key2),
primary key (pk1, pk2)
)engine=Innodb;
--disable_query_log
let $1=1000;
while ($1)
{
eval insert into t1 values (1+$1/10,$1 mod 100,$1,$1/100);
dec $1;
}
--enable_query_log
analyze table t1;
set optimizer_trace="enabled=on";
set @tmp_index_merge_ror_cpk=@@optimizer_switch;
set optimizer_switch='extended_keys=off';
explain select * from t1 where pk1 != 0 and key1 = 1;
select * from information_schema.OPTIMIZER_TRACE;
drop table t1;
set @@optimizer_switch= @tmp_index_merge_ror_cpk;
set optimizer_trace="enabled=off";
This diff is collapsed.
--source include/not_embedded.inc
create database db1;
use db1;
create table t1(a int);
insert into t1 values (1),(2),(3);
create table t2(a int);
CREATE USER 'foo'@'%';
CREATE USER 'bar'@'%';
create definer=foo SQL SECURITY definer view db1.v1 as select * from db1.t1;
delimiter |;
create definer=foo function f1 (a int) returns INT SQL SECURITY DEFINER
BEGIN
insert into t2 select * from t1;
return a+1;
END|
delimiter ;|
--change_user foo
set optimizer_trace="enabled=on";
--error 1142
select * from db1.t1;
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user root
grant select(a) on db1.t1 to 'foo'@'%';
--change_user foo
set optimizer_trace="enabled=on";
select * from db1.t1;
--echo # INSUFFICIENT PRIVILEGES should be set to 1
--echo # Trace and Query should be empty
--echo # We need SELECT privilege on the table db1.t1;
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user root
select * from information_schema.OPTIMIZER_TRACE;
grant select on db1.t1 to 'foo'@'%';
grant select on db1.t2 to 'foo'@'%';
--change_user foo
set optimizer_trace="enabled=on";
--echo #
--echo # SELECT privilege on the table db1.t1
--echo # The trace would be present.
--echo #
select * from db1.t1;
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user root
grant select on db1.v1 to 'foo'@'%';
grant show view on db1.v1 to 'foo'@'%';
grant select on db1.v1 to 'bar'@'%';
grant show view on db1.v1 to 'bar'@'%';
--change_user foo
select current_user();
set optimizer_trace="enabled=on";
select * from db1.v1;
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user bar
select current_user();
set optimizer_trace="enabled=on";
select * from db1.v1;
--echo #
--echo # INSUFFICIENT PRIVILEGES should be set to 1
--echo # Trace and Query should be empty
--echo # Privileges for the underlying tables of the
--echo # view should also be present for the current user
--echo #
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user root
grant execute on function db1.f1 to 'foo'@'%';
grant execute on function db1.f1 to 'bar'@'%';
grant select on db1.t1 to 'bar'@'%';
grant insert on db1.t2 to 'foo'@'%';
--change_user foo
select current_user();
set optimizer_trace="enabled=on";
select db1.f1(a) from db1.t1;
select INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user bar
select current_user();
set optimizer_trace="enabled=on";
--echo #
--echo # The trace should be empty, because the current user
--echo # does not have INSERT privilege for table t2 which is
--echo # used in the function f1
--echo #
select db1.f1(a) from db1.t1;
select * from information_schema.OPTIMIZER_TRACE;
set optimizer_trace="enabled=off";
--change_user root
select current_user();
REVOKE ALL PRIVILEGES, GRANT OPTION FROM foo;
--change_user root
drop user if exists foo;
drop user if exists bar;
drop table db1.t1, db1.t2;
drop database db1;
--echo #
--echo # Privilege checking for optimizer trace across connections
--echo #
connection default;
create database db1;
use db1;
create table t1(a int);
insert into t1 values (1),(2),(3);
create table t2(a int);
CREATE USER 'foo'@'localhost';
CREATE USER 'bar'@'localhost';
grant all on *.* to foo@localhost with grant option;
grant all on *.* to bar@localhost with grant option;
#grant select on db1.t1 to bar@localhost;
#grant insert on db1.t2 to bar@localhost;
connect (con_foo,localhost, foo,, db1);
connection default;
connect (con_bar,localhost, bar,, db1);
connection default;
create definer=foo@localhost SQL SECURITY definer view db1.v1 as select * from db1.t1;
delimiter |;
create function f1 (a int) returns INT SQL SECURITY DEFINER
BEGIN
insert into t2 select * from t1;
return a+1;
END|
delimiter ;|
grant execute on function f1 to bar@localhost;
connection con_foo;
set optimizer_trace='enabled=on';
select * from db1.t1;
--echo #
--echo # Test that security context changes are allowed when, and only
--echo # when, invoker has all global privileges.
--echo #
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
set optimizer_trace='enabled=off';
connection con_bar;
set optimizer_trace='enabled=on';
select f1(a) from db1.t1;
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
set optimizer_trace='enabled=off';
connection default;
revoke shutdown on *.* from foo@localhost;
disconnect con_foo;
connect (con_foo, localhost, foo,, db1);
connection con_foo;
set optimizer_trace='enabled=on';
select f1(a) from db1.t1;
--echo #
--echo # Test to check if invoker has all global privileges or not, only then
--echo # the security context changes are allowed. The user has been revoked
--echo # shutdown privilege so INSUFFICIENT PRIVILEGES should be set to 1.
--echo #
select query, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
set optimizer_trace='enabled=off';
connection default;
select current_user();
select * from db1.v1;
drop user foo@localhost, bar@localhost;
drop view db1.v1;
drop table db1.t1;
drop database db1;
set optimizer_trace="enabled=off";
......@@ -205,6 +205,10 @@ def information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA 10 NULL YES varc
def information_schema KEY_COLUMN_USAGE TABLE_CATALOG 4 '' NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) select NEVER NULL
def information_schema KEY_COLUMN_USAGE TABLE_NAME 6 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema KEY_COLUMN_USAGE TABLE_SCHEMA 5 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES 4 0 NO tinyint NULL NULL 3 0 NULL NULL NULL tinyint(1) select NEVER NULL
def information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE 3 0 NO int NULL NULL 10 0 NULL NULL NULL int(20) select NEVER NULL
def information_schema OPTIMIZER_TRACE QUERY 1 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL
def information_schema OPTIMIZER_TRACE TRACE 2 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL
def information_schema PARAMETERS CHARACTER_MAXIMUM_LENGTH 8 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) select NEVER NULL
def information_schema PARAMETERS CHARACTER_OCTET_LENGTH 9 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) select NEVER NULL
def information_schema PARAMETERS CHARACTER_SET_NAME 13 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
......@@ -743,6 +747,10 @@ NULL information_schema KEY_COLUMN_USAGE POSITION_IN_UNIQUE_CONSTRAINT bigint NU
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_COLUMN_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
1.0000 information_schema OPTIMIZER_TRACE QUERY longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
1.0000 information_schema OPTIMIZER_TRACE TRACE longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
NULL information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE int NULL NULL NULL NULL int(20)
NULL information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES tinyint NULL NULL NULL NULL tinyint(1)
3.0000 information_schema PARAMETERS SPECIFIC_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
3.0000 information_schema PARAMETERS SPECIFIC_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema PARAMETERS SPECIFIC_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
......
......@@ -205,6 +205,10 @@ def information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA 10 NULL YES varc
def information_schema KEY_COLUMN_USAGE TABLE_CATALOG 4 '' NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) NEVER NULL
def information_schema KEY_COLUMN_USAGE TABLE_NAME 6 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema KEY_COLUMN_USAGE TABLE_SCHEMA 5 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES 4 0 NO tinyint NULL NULL 3 0 NULL NULL NULL tinyint(1) NEVER NULL
def information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE 3 0 NO int NULL NULL 10 0 NULL NULL NULL int(20) NEVER NULL
def information_schema OPTIMIZER_TRACE QUERY 1 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL
def information_schema OPTIMIZER_TRACE TRACE 2 '' NO longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL
def information_schema PARAMETERS CHARACTER_MAXIMUM_LENGTH 8 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) NEVER NULL
def information_schema PARAMETERS CHARACTER_OCTET_LENGTH 9 NULL YES int NULL NULL 10 0 NULL NULL NULL int(21) NEVER NULL
def information_schema PARAMETERS CHARACTER_SET_NAME 13 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
......@@ -743,6 +747,10 @@ NULL information_schema KEY_COLUMN_USAGE POSITION_IN_UNIQUE_CONSTRAINT bigint NU
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_TABLE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema KEY_COLUMN_USAGE REFERENCED_COLUMN_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
1.0000 information_schema OPTIMIZER_TRACE QUERY longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
1.0000 information_schema OPTIMIZER_TRACE TRACE longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
NULL information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE int NULL NULL NULL NULL int(20)
NULL information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES tinyint NULL NULL NULL NULL tinyint(1)
3.0000 information_schema PARAMETERS SPECIFIC_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
3.0000 information_schema PARAMETERS SPECIFIC_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema PARAMETERS SPECIFIC_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
......
......@@ -489,6 +489,31 @@ user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME OPTIMIZER_TRACE
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
MAX_DATA_LENGTH #MDL#
INDEX_LENGTH #IL#
DATA_FREE #DF#
AUTO_INCREMENT NULL
CREATE_TIME #CRT#
UPDATE_TIME #UT#
CHECK_TIME #CT#
TABLE_COLLATION utf8_general_ci
CHECKSUM NULL
CREATE_OPTIONS #CO#
TABLE_COMMENT #TC#
MAX_INDEX_LENGTH #MIL#
TEMPORARY Y
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME PARAMETERS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
......@@ -1530,6 +1555,31 @@ user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME OPTIMIZER_TRACE
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
MAX_DATA_LENGTH #MDL#
INDEX_LENGTH #IL#
DATA_FREE #DF#
AUTO_INCREMENT NULL
CREATE_TIME #CRT#
UPDATE_TIME #UT#
CHECK_TIME #CT#
TABLE_COLLATION utf8_general_ci
CHECKSUM NULL
CREATE_OPTIONS #CO#
TABLE_COMMENT #TC#
MAX_INDEX_LENGTH #MIL#
TEMPORARY Y
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME PARAMETERS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
......
......@@ -489,6 +489,31 @@ user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME OPTIMIZER_TRACE
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
MAX_DATA_LENGTH #MDL#
INDEX_LENGTH #IL#
DATA_FREE #DF#
AUTO_INCREMENT NULL
CREATE_TIME #CRT#
UPDATE_TIME #UT#
CHECK_TIME #CT#
TABLE_COLLATION utf8_general_ci
CHECKSUM NULL
CREATE_OPTIONS #CO#
TABLE_COMMENT #TC#
MAX_INDEX_LENGTH #MIL#
TEMPORARY Y
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME PARAMETERS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
......@@ -1530,6 +1555,31 @@ user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME OPTIMIZER_TRACE
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
VERSION 11
ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
MAX_DATA_LENGTH #MDL#
INDEX_LENGTH #IL#
DATA_FREE #DF#
AUTO_INCREMENT NULL
CREATE_TIME #CRT#
UPDATE_TIME #UT#
CHECK_TIME #CT#
TABLE_COLLATION utf8_general_ci
CHECKSUM NULL
CREATE_OPTIONS #CO#
TABLE_COMMENT #TC#
MAX_INDEX_LENGTH #MIL#
TEMPORARY Y
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA information_schema
TABLE_NAME PARAMETERS
TABLE_TYPE SYSTEM VIEW
ENGINE MYISAM_OR_MARIA
......
......@@ -2742,6 +2742,34 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE
SESSION_VALUE enabled=off
GLOBAL_VALUE enabled=off
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE enabled=off
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Controls tracing of the Optimizer: optimizer_trace=option=val[,option=val...], where option is one of {enabled} and val is one of {on, off, default}
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST enabled,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE_MAX_MEM_SIZE
SESSION_VALUE 1048576
GLOBAL_VALUE 1048576
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1048576
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum allowed size of an optimizer trace
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 18446744073709551615
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
SESSION_VALUE 4
GLOBAL_VALUE 4
......
......@@ -2966,6 +2966,34 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,condition_pushdown_for_subquery,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE
SESSION_VALUE enabled=off
GLOBAL_VALUE enabled=off
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE enabled=off
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Controls tracing of the Optimizer: optimizer_trace=option=val[,option=val...], where option is one of {enabled} and val is one of {on, off, default}
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST enabled,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE_MAX_MEM_SIZE
SESSION_VALUE 1048576
GLOBAL_VALUE 1048576
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1048576
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum allowed size of an optimizer trace
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 18446744073709551615
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
SESSION_VALUE 4
GLOBAL_VALUE 4
......
......@@ -139,6 +139,7 @@ SET (SQL_SOURCE
sql_sequence.cc sql_sequence.h ha_sequence.h
sql_tvc.cc sql_tvc.h
opt_split.cc
opt_trace.cc
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc backup.cc
......
......@@ -993,6 +993,7 @@ enum enum_schema_tables
SCH_KEY_CACHES,
SCH_KEY_COLUMN_USAGE,
SCH_OPEN_TABLES,
SCH_OPT_TRACE,
SCH_PARAMETERS,
SCH_PARTITIONS,
SCH_PLUGINS,
......
......@@ -219,19 +219,20 @@ void Json_writer::add_str(const String &str)
add_str(str.ptr(), str.length());
}
Json_writer_object::Json_writer_object(Json_writer *writer):Json_writer_struct(writer)
Json_writer_object::Json_writer_object(THD *thd) :
Json_writer_struct(thd)
{
if (my_writer)
my_writer->start_object();
}
Json_writer_object::Json_writer_object(Json_writer *writer, const char *str)
:Json_writer_struct(writer)
Json_writer_object::Json_writer_object(THD* thd, const char *str)
: Json_writer_struct(thd)
{
if (my_writer)
my_writer->add_member(str).start_object();
}
Json_writer_object::~Json_writer_object()
{
if (!closed && my_writer)
......@@ -239,14 +240,15 @@ Json_writer_object::~Json_writer_object()
closed= TRUE;
}
Json_writer_array::Json_writer_array(Json_writer *writer):Json_writer_struct(writer)
Json_writer_array::Json_writer_array(THD *thd) :
Json_writer_struct(thd)
{
if (my_writer)
my_writer->start_array();
}
Json_writer_array::Json_writer_array(Json_writer *writer, const char *str)
:Json_writer_struct(writer)
Json_writer_array::Json_writer_array(THD *thd, const char *str)
:Json_writer_struct(thd)
{
if (my_writer)
my_writer->add_member(str).start_array();
......
This diff is collapsed.
This diff is collapsed.
......@@ -566,7 +566,7 @@ class SEL_ARG :public Sql_alloc
FALSE Otherwise
*/
bool is_singlepoint()
bool is_singlepoint() const
{
/*
Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
......
......@@ -33,6 +33,7 @@
#include "opt_subselect.h"
#include "sql_test.h"
#include <my_bit.h>
#include "opt_trace.h"
/*
This file contains optimizations for semi-join subqueries.
......@@ -437,7 +438,7 @@ Currently, solution #2 is implemented.
LEX_CSTRING weedout_key= {STRING_WITH_LEN("weedout_key")};
static
bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
bool subquery_types_allow_materialization(THD *thd, Item_in_subselect *in_subs);
static bool replace_where_subcondition(JOIN *, Item **, Item *, Item *, bool);
static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
void *arg);
......@@ -521,7 +522,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
parent_unit->first_select()->leaf_tables.elements && // 2
child_select->outer_select() &&
child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
subquery_types_allow_materialization(thd, in_subs) &&
(in_subs->is_top_level_item() || //3
optimizer_flag(thd,
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
......@@ -682,7 +683,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
{
DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
(void)subquery_types_allow_materialization(in_subs);
(void)subquery_types_allow_materialization(thd, in_subs);
in_subs->is_flattenable_semijoin= TRUE;
......@@ -696,6 +697,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
if (arena)
thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE;
OPT_TRACE_TRANSFORM(thd, oto0, oto1, select_lex->select_number,
"IN (SELECT)", "semijoin");
oto1.add("chosen", true);
}
}
else
......@@ -823,7 +827,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
*/
static
bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
{
DBUG_ENTER("subquery_types_allow_materialization");
......@@ -831,9 +835,14 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
List_iterator<Item> it(in_subs->unit->first_select()->item_list);
uint elements= in_subs->unit->first_select()->item_list.elements;
const char* cause= NULL;
in_subs->types_allow_materialization= FALSE; // Assign default values
in_subs->sjm_scan_allowed= FALSE;
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
in_subs->get_select_lex()->select_number,
"IN (SELECT)", "materialization");
bool all_are_fields= TRUE;
uint32 total_key_length = 0;
......@@ -846,7 +855,11 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
total_key_length += inner->max_length;
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
outer))
{
oto1.add("possible", false);
oto1.add("cause", "types mismatch");
DBUG_RETURN(FALSE);
}
}
/*
......@@ -856,14 +869,23 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
Make sure that the length of the key for the temp_table is atleast
greater than 0.
*/
if (!total_key_length || total_key_length > tmp_table_max_key_length() ||
elements > tmp_table_max_key_parts())
DBUG_RETURN(FALSE);
in_subs->types_allow_materialization= TRUE;
in_subs->sjm_scan_allowed= all_are_fields;
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
DBUG_RETURN(TRUE);
if (!total_key_length)
cause= "zero length key for materialized table";
else if (total_key_length > tmp_table_max_key_length())
cause= "length of key greater than allowed key length for materialized tables";
else if (elements > tmp_table_max_key_parts())
cause= "#keyparts greater than allowed key parts for materialized tables";
else
{
in_subs->types_allow_materialization= TRUE;
in_subs->sjm_scan_allowed= all_are_fields;
oto1.add("sjm_scan_allowed", all_are_fields)
.add("possible", true);
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
DBUG_RETURN(TRUE);
}
oto1.add("possible", false).add("cause", cause);
DBUG_RETURN(FALSE);
}
......@@ -1213,15 +1235,30 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
/* Stop processing if we've reached a subquery that's attached to the ON clause */
if (in_subq->do_not_convert_to_sj)
{
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
in_subq->get_select_lex()->select_number,
"IN (SELECT)", "semijoin");
oto1.add("converted_to_semi_join", false)
.add("cause", "subquery attached to the ON clause");
break;
}
if (in_subq->is_flattenable_semijoin)
{
OPT_TRACE_TRANSFORM(thd, oto0, oto1,
in_subq->get_select_lex()->select_number,
"IN (SELECT)", "semijoin");
if (join->table_count +
in_subq->unit->first_select()->join->table_count >= MAX_TABLES)
{
oto1.add("converted_to_semi_join", false);
oto1.add("cause", "table in parent join now exceeds MAX_TABLES");
break;
}
if (convert_subq_to_sj(join, in_subq))
goto restore_arena_and_fail;
oto1.add("converted_to_semi_join", true);
}
else
{
......@@ -2340,8 +2377,13 @@ int pull_out_semijoin_tables(JOIN *join)
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
{
DBUG_ENTER("optimize_semijoin_nests");
THD *thd= join->thd;
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
TABLE_LIST *sj_nest;
Json_writer_object wrapper(thd);
Json_writer_object trace_semijoin_nest(thd,
"execution_plan_for_potential_materialization");
Json_writer_array trace_steps_array(thd, "steps");
while ((sj_nest= sj_list_it++))
{
/* semi-join nests with only constant tables are not valid */
......
......@@ -31,6 +31,8 @@
#include "mariadb.h"
#include "my_bit.h"
#include "sql_select.h"
#include "opt_trace.h"
#include "my_json_writer.h"
/*
OVERVIEW
......@@ -522,7 +524,8 @@ eliminate_tables_for_list(JOIN *join,
List<TABLE_LIST> *join_list,
table_map tables_in_list,
Item *on_expr,
table_map tables_used_elsewhere);
table_map tables_used_elsewhere,
Json_writer_array* eliminate_tables);
static
bool check_func_dependency(JOIN *join,
table_map dep_tables,
......@@ -541,7 +544,8 @@ static
Dep_module_expr *merge_eq_mods(Dep_module_expr *start,
Dep_module_expr *new_fields,
Dep_module_expr *end, uint and_level);
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl);
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
Json_writer_array* eliminate_tables);
static
void add_module_expr(Dep_analysis_context *dac, Dep_module_expr **eq_mod,
uint and_level, Dep_value_field *field_val, Item *right,
......@@ -608,6 +612,8 @@ void eliminate_tables(JOIN *join)
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_TABLE_ELIMINATION))
DBUG_VOID_RETURN; /* purecov: inspected */
Json_writer_object trace_wrapper(thd);
/* Find the tables that are referred to from WHERE/HAVING */
used_tables= (join->conds? join->conds->used_tables() : 0) |
(join->having? join->having->used_tables() : 0);
......@@ -663,13 +669,14 @@ void eliminate_tables(JOIN *join)
}
}
}
table_map all_tables= join->all_tables_map();
Json_writer_array eliminated_tables(thd,"eliminated_tables");
if (all_tables & ~used_tables)
{
/* There are some tables that we probably could eliminate. Try it. */
eliminate_tables_for_list(join, join->join_list, all_tables, NULL,
used_tables);
used_tables, &eliminated_tables);
}
DBUG_VOID_RETURN;
}
......@@ -712,7 +719,8 @@ void eliminate_tables(JOIN *join)
static bool
eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
table_map list_tables, Item *on_expr,
table_map tables_used_elsewhere)
table_map tables_used_elsewhere,
Json_writer_array *eliminate_tables)
{
TABLE_LIST *tbl;
List_iterator<TABLE_LIST> it(*join_list);
......@@ -734,9 +742,9 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
&tbl->nested_join->join_list,
tbl->nested_join->used_tables,
tbl->on_expr,
outside_used_tables))
outside_used_tables, eliminate_tables))
{
mark_as_eliminated(join, tbl);
mark_as_eliminated(join, tbl, eliminate_tables);
}
else
all_eliminated= FALSE;
......@@ -748,7 +756,7 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
check_func_dependency(join, tbl->table->map, NULL, tbl,
tbl->on_expr))
{
mark_as_eliminated(join, tbl);
mark_as_eliminated(join, tbl, eliminate_tables);
}
else
all_eliminated= FALSE;
......@@ -1788,7 +1796,8 @@ Dep_module* Dep_value_field::get_next_unbound_module(Dep_analysis_context *dac,
Mark one table or the whole join nest as eliminated.
*/
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
Json_writer_array* eliminate_tables)
{
TABLE *table;
/*
......@@ -1801,7 +1810,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
TABLE_LIST *child;
List_iterator<TABLE_LIST> it(tbl->nested_join->join_list);
while ((child= it++))
mark_as_eliminated(join, child);
mark_as_eliminated(join, child, eliminate_tables);
}
else if ((table= tbl->table))
{
......@@ -1812,6 +1821,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl)
tab->type= JT_CONST;
tab->table->const_table= 1;
join->eliminated_tables |= table->map;
eliminate_tables->add(table->alias.c_ptr_safe());
join->const_table_map|= table->map;
set_position(join, join->const_tables++, tab, (KEYUSE*)0);
}
......
This diff is collapsed.
This diff is collapsed.
#ifndef OPT_TRACE_CONTEXT_INCLUDED
#define OPT_TRACE_CONTEXT_INCLUDED
#include "sql_array.h"
class Opt_trace_stmt;
class Opt_trace_context
{
public:
Opt_trace_context();
~Opt_trace_context();
void start(THD *thd, TABLE_LIST *tbl,
enum enum_sql_command sql_command,
const char *query,
size_t query_length,
const CHARSET_INFO *query_charset,
ulong max_mem_size_arg);
void end();
void set_query(const char *query, size_t length, const CHARSET_INFO *charset);
void flush_optimizer_trace();
void set_allowed_mem_size(size_t mem_size);
size_t remaining_mem_size();
private:
Opt_trace_stmt* top_trace()
{
return *(traces->front());
}
public:
/*
This returns the top trace from the list of traces. This function
is used when we want to see the contents of the INFORMATION_SCHEMA.OPTIMIZER_TRACE
table.
*/
Opt_trace_stmt* get_top_trace()
{
if (!traces || !traces->elements())
return NULL;
return top_trace();
}
/*
This returns the current trace, to which we are still writing and has not been finished
*/
Json_writer* get_current_json();
bool empty()
{
return traces && (static_cast<uint>(traces->elements()) != 0);
}
bool is_started()
{
return current_trace && is_enabled();
}
bool disable_tracing_if_required();
bool enable_tracing_if_required();
bool is_enabled();
void missing_privilege();
static const char *flag_names[];
enum
{
FLAG_DEFAULT = 0,
FLAG_ENABLED = 1 << 0
};
private:
/*
List of traces (currently it stores only 1 trace)
*/
Dynamic_array<Opt_trace_stmt*> *traces;
Opt_trace_stmt *current_trace;
/*
TRUE: if we allocate memory for list of traces
FALSE: otherwise
*/
bool inited;
size_t max_mem_size;
};
#endif /* OPT_TRACE_CONTEXT_INCLUDED */
......@@ -275,6 +275,10 @@ class set_var_base :public Sql_alloc
virtual int update(THD *thd)=0; /* To set the value */
virtual int light_check(THD *thd) { return check(thd); } /* for PS */
virtual bool is_system() { return FALSE; }
/**
@returns whether this variable is @@@@optimizer_trace.
*/
virtual bool is_var_optimizer_trace() const { return false; }
};
......@@ -306,6 +310,11 @@ class set_var :public set_var_base
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
virtual bool is_var_optimizer_trace() const
{
extern sys_var *Sys_optimizer_trace_ptr;
return var == Sys_optimizer_trace_ptr;
}
};
......
This diff is collapsed.
......@@ -2024,6 +2024,7 @@ class sp_instr_set_case_expr : public sp_instr_opt_meta
}; // class sp_instr_set_case_expr : public sp_instr_opt_meta
bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -233,7 +233,7 @@ void Explain_query::print_explain_json(select_result_sink *output,
CHARSET_INFO *cs= system_charset_info;
List<Item> item_list;
String *buf= &writer.output;
const String *buf= writer.output.get_string();
item_list.push_back(new (thd->mem_root)
Item_string(thd, buf->ptr(), buf->length(), cs),
thd->mem_root);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment