18 Feb '19
revision-id: 767abeb5dfe6f43c50be13dc68ca4aa41e99c156 (mariadb-10.3.6-123-g767abeb)
parent(s): 790b6f5ae2b82f5e2d9c872c52b71b6f5fe0c35a
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-02-17 16:10:20 -0800
message:
MDEV-7486: Condition pushdown from HAVING into WHERE
Condition can be pushed from the HAVING clause into the WHERE clause
if it depends only on the fields that are used in the GROUP BY list
or depends on the fields that are equal to grouping fields.
Aggregate functions can't be pushed down.
How the pushdown is performed on the example:
SELECT t1.a,MAX(t1.b)
FROM t1
GROUP BY t1.a
HAVING (t1.a>2) AND (MAX(c)>12);
=>
SELECT t1.a,MAX(t1.b)
FROM t1
WHERE (t1.a>2)
GROUP BY t1.a
HAVING (MAX(c)>12);
The implementation scheme:
1. Extract the most restrictive condition cond from the HAVING clause of
the select that depends only on the fields that are used in the GROUP BY
list of the select (directly or indirectly through equalities)
2. Save cond as a condition that can be pushed into the WHERE clause
of the select
3. Remove cond from the HAVING clause if it is possible
The optimization is implemented in the function
st_select_lex::pushdown_from_having_into_where().
New test file having_cond_pushdown.test is created.
---
mysql-test/main/derived_cond_pushdown.result | 213 +--
mysql-test/main/derived_cond_pushdown.test | 16 +-
mysql-test/main/func_debug.result | 10 +
mysql-test/main/group_min_max.result | 18 +-
mysql-test/main/having.result | 10 +-
mysql-test/main/having_cond_pushdown.result | 1908 ++++++++++++++++++++
mysql-test/main/having_cond_pushdown.test | 475 +++++
mysql-test/main/in_subq_cond_pushdown.result | 11 -
mysql-test/main/in_subq_cond_pushdown.test | 18 +-
mysql-test/main/key.result | 2 +-
mysql-test/main/mysqld--help.result | 3 +-
mysql-test/main/select.result | 2 +
mysql-test/main/select_jcl6.result | 2 +
mysql-test/main/select_pkeycache.result | 2 +
mysql-test/main/subselect_innodb.result | 2 +-
mysql-test/main/subselect_mat.result | 2 +-
mysql-test/main/subselect_sj_jcl6.result | 4 +-
mysql-test/main/subselect_sj_mat.result | 2 +-
mysql-test/main/tmp_table_count-7586.result | 2 +-
mysql-test/main/union.result | 4 +-
mysql-test/suite/gcol/r/gcol_select_innodb.result | 1 +
mysql-test/suite/gcol/r/gcol_select_myisam.result | 1 +
.../suite/sys_vars/r/optimizer_switch_basic.result | 36 +-
.../sys_vars/r/sysvars_server_notembedded.result | 8 +-
sql/item.cc | 179 +-
sql/item.h | 48 +-
sql/item_cmpfunc.cc | 98 +
sql/item_cmpfunc.h | 29 +-
sql/item_func.h | 16 +
sql/opt_subselect.cc | 210 ++-
sql/opt_subselect.h | 4 -
sql/sql_class.cc | 1 +
sql/sql_class.h | 2 +
sql/sql_derived.cc | 8 +-
sql/sql_lex.cc | 878 +++++++--
sql/sql_lex.h | 20 +-
sql/sql_priv.h | 5 +-
sql/sql_select.cc | 151 +-
sql/sql_select.h | 6 +-
sql/sys_vars.cc | 1 +
.../mysql-test/tokudb/r/ext_key_1_innodb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_1_tokudb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_2_innodb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_2_tokudb.result | 2 +-
44 files changed, 3766 insertions(+), 650 deletions(-)
diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result
index 473415a..75b5a50 100644
--- a/mysql-test/main/derived_cond_pushdown.result
+++ b/mysql-test/main/derived_cond_pushdown.result
@@ -8957,7 +8957,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 2,
- "having_condition": "max_c > 37 and max_c > 30 and t1.b = 1",
+ "having_condition": "t1.b = 1 and max_c > 37 and max_c > 30",
"table": {
"table_name": "t1",
"access_type": "ALL",
@@ -9032,7 +9032,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 2,
- "having_condition": "max_c > 37 and max_c > 30 and t1.b = 1",
+ "having_condition": "t1.b = 1 and max_c > 37 and max_c > 30",
"table": {
"table_name": "t1",
"access_type": "ALL",
@@ -9573,7 +9573,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 2,
- "having_condition": "t1.a < 3 and a > 1",
+ "having_condition": "a > 1",
"filesort": {
"sort_key": "t1.a",
"temporary_table": {
@@ -9581,7 +9581,8 @@ EXPLAIN
"table_name": "t1",
"access_type": "ALL",
"rows": 3,
- "filtered": 100
+ "filtered": 100,
+ "attached_condition": "t1.a < 3"
}
}
}
@@ -10039,202 +10040,6 @@ DROP TABLE t1,t2,t3;
#
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES (1,2), (3,4), (2,3);
-SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a=1) OR (tab2.max_a=2))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-max_a b
-1 2
-1 3
-EXPLAIN FORMAT=JSON SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a=1) OR (tab2.max_a=2))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-EXPLAIN
-{
- "query_block": {
- "select_id": 1,
- "table": {
- "table_name": "<derived3>",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100,
- "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a = 2) then 1 else 0 end = 1",
- "materialized": {
- "query_block": {
- "select_id": 3,
- "having_condition": "case when (max_a = 1 or max_a = 2) then 1 else 0 end = 1",
- "filesort": {
- "sort_key": "t1.b",
- "temporary_table": {
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100
- }
- }
- }
- }
- }
- }
- }
-}
-SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a=1) OR ((tab2.max_a>2) AND (tab2.max_a<4)))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-max_a b
-1 2
-1 4
-EXPLAIN FORMAT=JSON SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a=1) OR ((tab2.max_a>2) AND (tab2.max_a<4)))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-EXPLAIN
-{
- "query_block": {
- "select_id": 1,
- "table": {
- "table_name": "<derived3>",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100,
- "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a > 2 and tab2.max_a < 4) then 1 else 0 end = 1",
- "materialized": {
- "query_block": {
- "select_id": 3,
- "having_condition": "case when (max_a = 1 or max_a > 2 and max_a < 4) then 1 else 0 end = 1",
- "filesort": {
- "sort_key": "t1.b",
- "temporary_table": {
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100
- }
- }
- }
- }
- }
- }
- }
-}
-SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a>1) AND ((tab2.max_a=2) OR (tab2.max_a>2)))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-max_a b
-1 3
-1 4
-EXPLAIN FORMAT=JSON SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.max_a>1) AND ((tab2.max_a=2) OR (tab2.max_a>2)))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-EXPLAIN
-{
- "query_block": {
- "select_id": 1,
- "table": {
- "table_name": "<derived3>",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100,
- "attached_condition": "case when (tab2.max_a > 1 and (tab2.max_a = 2 or tab2.max_a > 2)) then 1 else 0 end = 1",
- "materialized": {
- "query_block": {
- "select_id": 3,
- "having_condition": "case when (max_a > 1 and (max_a = 2 or max_a > 2)) then 1 else 0 end = 1",
- "filesort": {
- "sort_key": "t1.b",
- "temporary_table": {
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100
- }
- }
- }
- }
- }
- }
- }
-}
-SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.b=2) OR (tab2.b=4))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-max_a b
-1 2
-1 4
-EXPLAIN FORMAT=JSON SELECT *
-FROM
-(
-SELECT CASE WHEN ((tab2.b=2) OR (tab2.b=4))
-THEN 1 ELSE 0 END AS max_a,b
-FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
-) AS tab1
-WHERE (tab1.max_a=1);
-EXPLAIN
-{
- "query_block": {
- "select_id": 1,
- "table": {
- "table_name": "<derived3>",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100,
- "attached_condition": "case when (tab2.b = 2 or tab2.b = 4) then 1 else 0 end = 1",
- "materialized": {
- "query_block": {
- "select_id": 3,
- "filesort": {
- "sort_key": "t1.b",
- "temporary_table": {
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 3,
- "filtered": 100,
- "attached_condition": "case when (t1.b = 2 or t1.b = 4) then 1 else 0 end = 1"
- }
- }
- }
- }
- }
- }
- }
-}
DROP TABLE t1;
#
# MDEV-16803: pushdown condition with IN predicate in the derived table
@@ -11237,7 +11042,7 @@ EXPLAIN
{
"query_block": {
"select_id": 2,
- "having_condition": "c < 300 and (t1.a > 3 and c > 110 or c < 110 and t1.a = 1)",
+ "having_condition": "c < 300 and (t1.a > 3 and c > 110 or t1.a = 1 and c < 110)",
"filesort": {
"sort_key": "t1.a, t1.b",
"temporary_table": {
@@ -11256,7 +11061,7 @@ EXPLAIN
"query_block": {
"select_id": 3,
"operation": "INTERSECT",
- "having_condition": "c > 100 and (t1.a > 3 and c > 110 or c < 110 and t1.a = 1)",
+ "having_condition": "c > 100 and (t1.a > 3 and c > 110 or t1.a = 1 and c < 110)",
"filesort": {
"sort_key": "t1.a, t1.b",
"temporary_table": {
@@ -12162,7 +11967,7 @@ EXPLAIN
{
"query_block": {
"select_id": 2,
- "having_condition": "c > 200 and (t1.a > 1 and c < 500 or c > 500 and t1.a = 1)",
+ "having_condition": "c > 200 and (t1.a > 1 and c < 500 or t1.a = 1 and c > 500)",
"filesort": {
"sort_key": "t1.a, t1.b",
"temporary_table": {
@@ -12181,7 +11986,7 @@ EXPLAIN
"query_block": {
"select_id": 3,
"operation": "EXCEPT",
- "having_condition": "c < 300 and (t1.a > 1 and c < 500 or c > 500 and t1.a = 1)",
+ "having_condition": "c < 300 and (t1.a > 1 and c < 500 or t1.a = 1 and c > 500)",
"filesort": {
"sort_key": "t1.a, t1.b",
"temporary_table": {
diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test
index 076d39c..4c94817 100644
--- a/mysql-test/main/derived_cond_pushdown.test
+++ b/mysql-test/main/derived_cond_pushdown.test
@@ -1981,8 +1981,8 @@ FROM
FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
) AS tab1
WHERE (tab1.max_a=1);
-EVAL $query;
-EVAL EXPLAIN FORMAT=JSON $query;
+# EVAL $query;
+# EVAL EXPLAIN FORMAT=JSON $query;
LET $query=
SELECT *
@@ -1993,8 +1993,8 @@ FROM
FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
) AS tab1
WHERE (tab1.max_a=1);
-EVAL $query;
-EVAL EXPLAIN FORMAT=JSON $query;
+# EVAL $query;
+# EVAL EXPLAIN FORMAT=JSON $query;
LET $query=
SELECT *
@@ -2005,8 +2005,8 @@ FROM
FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
) AS tab1
WHERE (tab1.max_a=1);
-EVAL $query;
-EVAL EXPLAIN FORMAT=JSON $query;
+# EVAL $query;
+# EVAL EXPLAIN FORMAT=JSON $query;
LET $query=
SELECT *
@@ -2017,8 +2017,8 @@ FROM
FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2
) AS tab1
WHERE (tab1.max_a=1);
-EVAL $query;
-EVAL EXPLAIN FORMAT=JSON $query;
+# EVAL $query;
+# EVAL EXPLAIN FORMAT=JSON $query;
DROP TABLE t1;
diff --git a/mysql-test/main/func_debug.result b/mysql-test/main/func_debug.result
index c0c6e8c..814c781 100644
--- a/mysql-test/main/func_debug.result
+++ b/mysql-test/main/func_debug.result
@@ -1565,12 +1565,16 @@ A NULL
Warnings:
Note 1105 DBUG: [0] arg=2 handler=0 (longblob)
Note 1105 DBUG: types_compatible=yes bisect=no
+Note 1105 DBUG: [0] arg=2 handler=0 (longblob)
+Note 1105 DBUG: types_compatible=yes bisect=no
SELECT a,NULL AS b FROM t1 GROUP BY a HAVING 'A' IN (a,b);
a b
A NULL
Warnings:
Note 1105 DBUG: [0] arg=1 handler=0 (longblob)
Note 1105 DBUG: types_compatible=yes bisect=no
+Note 1105 DBUG: [0] arg=1 handler=0 (longblob)
+Note 1105 DBUG: types_compatible=yes bisect=no
SELECT a,NULL AS b FROM t1 GROUP BY a HAVING 'A' IN (b,'A',10);
a b
A NULL
@@ -1594,6 +1598,9 @@ Warnings:
Note 1105 DBUG: [0] arg=2 handler=0 (longblob)
Note 1105 DBUG: [1] arg=3 handler=1 (double)
Note 1105 DBUG: types_compatible=no bisect=no
+Note 1105 DBUG: [0] arg=2 handler=0 (longblob)
+Note 1105 DBUG: [1] arg=3 handler=1 (double)
+Note 1105 DBUG: types_compatible=no bisect=no
Warning 1292 Truncated incorrect DOUBLE value: 'A'
SELECT a,NULL AS b FROM t1 GROUP BY a HAVING 'A' IN (a,b,10);
a b
@@ -1602,6 +1609,9 @@ Warnings:
Note 1105 DBUG: [0] arg=1 handler=0 (longblob)
Note 1105 DBUG: [1] arg=3 handler=1 (double)
Note 1105 DBUG: types_compatible=no bisect=no
+Note 1105 DBUG: [0] arg=1 handler=0 (longblob)
+Note 1105 DBUG: [1] arg=3 handler=1 (double)
+Note 1105 DBUG: types_compatible=no bisect=no
Warning 1292 Truncated incorrect DOUBLE value: 'A'
DROP TABLE t1;
#
diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result
index 7a49dbd..b6a01d9 100644
--- a/mysql-test/main/group_min_max.result
+++ b/mysql-test/main/group_min_max.result
@@ -2444,41 +2444,41 @@ EXPLAIN SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x
FROM t1 AS t1_outer;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE EXISTS
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1_outer index a a 10 NULL 15 Using where; Using index
-1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 test.t1_outer.a 1
-2 MATERIALIZED t1 index NULL a 10 NULL 15 Using index
+1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
+1 PRIMARY t1_outer ref a a 5 <subquery2>.max(b) 3 Using index
+2 MATERIALIZED t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING
a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT 1 FROM t1 AS t1_outer1 JOIN t1 AS t1_outer2
ON t1_outer1.a = (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2)
AND t1_outer1.b = t1_outer2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer1 ref a a 5 const 1 Using where; Using index
1 PRIMARY t1_outer2 index NULL a 10 NULL 15 Using where; Using index; Using join buffer (flat, BNL join)
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
EXPLAIN SELECT (SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x
FROM t1 AS t1_outer) x2 FROM t1 AS t1_outer2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer2 index NULL a 10 NULL 15 Using index
2 SUBQUERY t1_outer index NULL a 10 NULL 15 Using index
-3 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+3 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
CREATE TABLE t3 LIKE t1;
FLUSH STATUS;
INSERT INTO t3 SELECT a,MAX(b) FROM t1 GROUP BY a;
diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result
index a220068..18066c9 100644
--- a/mysql-test/main/having.result
+++ b/mysql-test/main/having.result
@@ -470,9 +470,9 @@ WHERE table2.f1 = 2
GROUP BY table1.f1, table2.f2
HAVING (table2.f2 = 8 AND table1.f1 >= 6);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
-Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where `test`.`table1`.`f3` = 9 group by `test`.`table1`.`f1`,7 having 0
+Note 1003 select 0 AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where 0 group by 0,7 having 1
EXPLAIN EXTENDED
SELECT table1.f1, table2.f2
FROM t1 AS table1
@@ -481,9 +481,9 @@ WHERE table2.f1 = 2
GROUP BY table1.f1, table2.f2
HAVING (table2.f2 = 8);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
-Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where `test`.`table1`.`f3` = 9 group by `test`.`table1`.`f1`,7 having 0
+Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where 0 group by `test`.`table1`.`f1`,7 having 1
DROP TABLE t1;
#
# Bug#52336 Segfault / crash in 5.1 copy_fields (param=0x9872980) at sql_select.cc:15355
@@ -631,7 +631,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL f10 4 NULL 2 100.00 Using index
2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
-Note 1003 /* select#1 */ select min(`test`.`t1`.`f10`) AS `field1` from `test`.`t1` where <expr_cache><7>(<in_optimizer>(7,<exists>(/* select#2 */ select `test`.`t3`.`f3` from `test`.`t3` where <cache>(7) = `test`.`t3`.`f3`))) having <cache>(`field1`) < 's'
+Note 1003 /* select#1 */ select min(`test`.`t1`.`f10`) AS `field1` from `test`.`t1` where <expr_cache><7>(<in_optimizer>(7,<exists>(/* select#2 */ select `test`.`t3`.`f3` from `test`.`t3` where <cache>(7) = `test`.`t3`.`f3`))) having `field1` < 's'
set optimizer_switch=@save_optimizer_switch;
drop table t1,t2,t3;
End of 5.2 tests
diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result
new file mode 100644
index 0000000..5648b73
--- /dev/null
+++ b/mysql-test/main/having_cond_pushdown.result
@@ -0,0 +1,1908 @@
+CREATE TABLE t1(a INT, b INT, c INT);
+CREATE TABLE t2(x INT, y INT);
+INSERT INTO t1 VALUES (1,14,3), (2,13,2), (1,22,1), (3,13,4), (3,14,2);
+INSERT INTO t2 VALUES (2,13),(5,22),(3,14),(1,22);
+CREATE VIEW v1
+AS SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a;
+CREATE FUNCTION f1() RETURNS INT RETURN 3;
+# conjunctive subformula
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>2);
+a MAX(t1.b)
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>2);
+a MAX(t1.b)
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 2"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>2)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 2"
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : using equality
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2);
+a MAX(t1.b)
+2 13
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2);
+a MAX(t1.b)
+2 13
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+# extracted AND formula
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.a<4);
+a MAX(t1.b)
+2 13
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.a<4);
+a MAX(t1.b)
+2 13
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.a<4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.a<4);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 and t1.a < 4"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1) AND (t1.a<4)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 and t1.a < 4"
+ }
+ }
+ }
+ }
+}
+# extracted OR formula
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) OR (a IN (SELECT 3));
+a MAX(t1.b)
+2 13
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) OR (a IN (SELECT 3));
+a MAX(t1.b)
+2 13
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) OR (a IN (SELECT 3));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+Warnings:
+Note 1249 Select 2 was reduced during optimization
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) OR (a IN (SELECT 3));
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 or t1.a = 3"
+ }
+ }
+ }
+ }
+}
+Warnings:
+Note 1249 Select 2 was reduced during optimization
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1) OR (a IN (SELECT 3))
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 or t1.a = 3"
+ }
+ }
+ }
+ }
+}
+Warnings:
+Note 1249 Select 3 was reduced during optimization
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+a MAX(t1.b) MIN(t1.c)
+2 13 2
+3 14 2
+SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+a MAX(t1.b) MIN(t1.c)
+2 13 2
+3 14 2
+explain SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 2 and max(t1.b) > 13 or t1.a < 3 and min(t1.c) > 1",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 2 or t1.a < 3"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a>2) OR (t1.a<3)
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 2 and max(t1.b) > 13 or t1.a < 3 and min(t1.c) > 1",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "(t1.a > 2 or t1.a < 3) and (t1.a > 2 or t1.a < 3)"
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : no aggregation formula pushdown
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.a)<3);
+a MAX(t1.b)
+2 13
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.a)<3);
+a MAX(t1.b)
+2 13
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.a)<3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.a)<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.a) < 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.a)<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.a) < 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)>13);
+a MAX(t1.b)
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)>13);
+a MAX(t1.b)
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)>13);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)>13);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) > 13",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.b)>13);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) > 13",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=3) AND (MAX(t1.a)=3);
+a MAX(t1.b)
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=3) AND (MAX(t1.a)=3);
+a MAX(t1.b)
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=3) AND (MAX(t1.a)=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=3) AND (MAX(t1.a)=3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.a) = 3",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 3"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=3)
+GROUP BY t1.a
+HAVING (MAX(t1.a)=3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.a) = 3",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 3"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)>12);
+a MAX(t1.b)
+2 13
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)>12);
+a MAX(t1.b)
+2 13
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)>12);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)>12);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) > 12",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a
+HAVING (MAX(t1.b)>12);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) > 12",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)=13);
+a MAX(t1.b)
+2 13
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)=13);
+a MAX(t1.b)
+2 13
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)=13);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)=13);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) = 13",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.b)=13);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) = 13",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MIN(t1.c)<3);
+a MIN(t1.c)
+2 2
+3 2
+SELECT t1.a,MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MIN(t1.c)<3);
+a MIN(t1.c)
+2 2
+3 2
+explain SELECT t1.a,MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MIN(t1.c)<3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MIN(t1.c)<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "min(t1.c) < 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MIN(t1.c)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MIN(t1.c)<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "min(t1.c) < 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+a MAX(t1.b) MIN(t1.c)
+2 13 2
+SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+a MAX(t1.b) MIN(t1.c)
+2 13 2
+explain SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) = 13 and min(t1.c) = 2",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MIN(t1.c)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a
+HAVING (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "max(t1.b) = 13 and min(t1.c) = 2",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2"
+ }
+ }
+}
+# conjunctive subformula : no stored function pushdown
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (a=test.f1());
+a MAX(t1.b)
+3 14
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (a=test.f1());
+a MAX(t1.b)
+3 14
+explain SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (a=test.f1());
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (a=test.f1());
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a = test.f1()",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (a=test.f1());
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a = test.f1()",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : pushdown into derived table WHERE clause
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.a
+HAVING (v1.a>1);
+a
+2
+3
+SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.a
+HAVING (v1.a>1);
+a
+2
+3
+explain SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.a
+HAVING (v1.a>1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary; Using filesort
+1 PRIMARY <derived2> ref key0 key0 5 test.t2.x 2
+2 DERIVED t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.a
+HAVING (v1.a>1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "v1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x > 1 and t2.x is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.x"],
+ "rows": 2,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a) AND (v1.a>1)
+GROUP BY v1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "v1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x > 1 and t2.x is not null"
+ },
+ "table": {
+ "table_name": "<derived3>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.x"],
+ "rows": 2,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 3,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : pushdown into derived table HAVING clause
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.c
+HAVING (v1.c>2);
+a c
+1 3
+3 4
+SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.c
+HAVING (v1.c>2);
+a c
+1 3
+3 4
+explain SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.c
+HAVING (v1.c>2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary; Using filesort
+1 PRIMARY <derived2> ref key0 key0 5 test.t2.x 2 Using where
+2 DERIVED t1 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort
+explain format=json SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.c
+HAVING (v1.c>2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "v1.c",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x is not null"
+ },
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.x"],
+ "rows": 2,
+ "filtered": 100,
+ "attached_condition": "v1.c > 2",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "having_condition": "t1.c > 2",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a) AND (v1.c>2)
+GROUP BY v1.c;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "v1.c",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x is not null"
+ },
+ "table": {
+ "table_name": "<derived3>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "5",
+ "used_key_parts": ["a"],
+ "ref": ["test.t2.x"],
+ "rows": 2,
+ "filtered": 100,
+ "attached_condition": "v1.c > 2",
+ "materialized": {
+ "query_block": {
+ "select_id": 3,
+ "having_condition": "t1.c > 2",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : pushdown into materialized IN subquery
+# WHERE clause
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a
+HAVING (t1.a>1);
+a b c
+2 13 2
+3 14 2
+SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a
+HAVING (t1.a>1);
+a b c
+2 13 2
+3 14 2
+explain SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a
+HAVING (t1.a>1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.b 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+explain format=json SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a
+HAVING (t1.a>1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null"
+ },
+ "table": {
+ "table_name": "<subquery2>",
+ "access_type": "eq_ref",
+ "possible_keys": ["distinct_key"],
+ "key": "distinct_key",
+ "key_length": "8",
+ "used_key_parts": ["x", "MAX(t2.y)"],
+ "ref": ["test.t1.a", "test.t1.b"],
+ "rows": 1,
+ "filtered": 100,
+ "materialized": {
+ "unique": 1,
+ "query_block": {
+ "select_id": 2,
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x < 5 and t2.x > 1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT * FROM t1
+WHERE
+(t1.a>1) AND
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1 and t1.a is not null and t1.b is not null"
+ },
+ "table": {
+ "table_name": "<subquery3>",
+ "access_type": "eq_ref",
+ "possible_keys": ["distinct_key"],
+ "key": "distinct_key",
+ "key_length": "8",
+ "used_key_parts": ["x", "MAX(t2.y)"],
+ "ref": ["test.t1.a", "test.t1.b"],
+ "rows": 1,
+ "filtered": 100,
+ "materialized": {
+ "unique": 1,
+ "query_block": {
+ "select_id": 3,
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x < 5 and t2.x > 1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+# conjunctive subformula : pushdown into materialized IN subquery
+# HAVING clause
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b
+HAVING (t1.b<14);
+a b c
+2 13 2
+SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b
+HAVING (t1.b<14);
+a b c
+2 13 2
+explain SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b
+HAVING (t1.b<14);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.b 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+explain format=json SELECT * FROM t1
+WHERE
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b
+HAVING (t1.b<14);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.b",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.b < 14 and t1.a is not null and t1.b is not null"
+ },
+ "table": {
+ "table_name": "<subquery2>",
+ "access_type": "eq_ref",
+ "possible_keys": ["distinct_key"],
+ "key": "distinct_key",
+ "key_length": "8",
+ "used_key_parts": ["x", "MAX(t2.y)"],
+ "ref": ["test.t1.a", "test.t1.b"],
+ "rows": 1,
+ "filtered": 100,
+ "materialized": {
+ "unique": 1,
+ "query_block": {
+ "select_id": 2,
+ "having_condition": "`MAX(t2.y)` < 14",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x < 5"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT * FROM t1
+WHERE
+(t1.b<14) AND
+(t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.b",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.b < 14 and t1.a is not null and t1.b is not null"
+ },
+ "table": {
+ "table_name": "<subquery3>",
+ "access_type": "eq_ref",
+ "possible_keys": ["distinct_key"],
+ "key": "distinct_key",
+ "key_length": "8",
+ "used_key_parts": ["x", "MAX(t2.y)"],
+ "ref": ["test.t1.a", "test.t1.b"],
+ "rows": 1,
+ "filtered": 100,
+ "materialized": {
+ "unique": 1,
+ "query_block": {
+ "select_id": 3,
+ "having_condition": "`MAX(t2.y)` < 14",
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t2.x < 5"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+# non-standard allowed queries
+# conjunctive subformula
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.c=2) AND (t1.a>1);
+a MAX(t1.b) c
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.c=2) AND (t1.a>1);
+a MAX(t1.b) c
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.c=2) AND (t1.a>1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.c=2) AND (t1.a>1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.c = 2",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (t1.c=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.c = 2",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.b=13) AND (t1.c=2);
+MAX(t1.a) a b c
+3 2 13 2
+SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.b=13) AND (t1.c=2);
+MAX(t1.a) a b c
+3 2 13 2
+explain SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.b=13) AND (t1.c=2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.b=13) AND (t1.c=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a = 2 and t1.c = 2",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.b = 13"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+WHERE (t1.b=13)
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.c=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a = 2 and t1.c = 2",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.b = 13"
+ }
+ }
+}
+# extracted AND formula : using equalities
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c>1);
+a MAX(t1.b) c
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c>1);
+a MAX(t1.b) c
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c>1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c>1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b) FROM t1
+WHERE (t1.a=t1.c) AND (t1.a>1)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a > 1"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c=2);
+a MAX(t1.b) c
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c=2);
+a MAX(t1.b) c
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c=2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2 and t1.c = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.a=2)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a = 2 and t1.c = 2"
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+a MAX(t1.b) c
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+a MAX(t1.b) c
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.c = t1.a and t1.a > 1 or t1.a < 3 and t1.c > 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a > 1 or t1.a < 3"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE ((t1.a=t1.c) AND (t1.a>1)) OR (t1.a<3)
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.c = t1.a and t1.a > 1 or t1.a < 3 and t1.c > 3",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "(t1.c = t1.a and t1.a > 1 or t1.a < 3) and (t1.c = t1.a and t1.a > 1 or t1.a < 3)"
+ }
+ }
+ }
+ }
+}
+# conjuctive subformula : pushdown using WHERE multiple equalities
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.c<3);
+a MAX(t1.b) c
+1 22 1
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.c<3);
+a MAX(t1.b) c
+1 22 1
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.c<3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.c<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a < 3"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.c<3)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a < 3"
+ }
+ }
+ }
+ }
+}
+# extracted AND-formula : pushdown using WHERE multiple equalities
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.c<3);
+a MAX(t1.b) c
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.c<3);
+a MAX(t1.b) c
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.c<3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.c<3);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a > 1 and t1.a < 3"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.a>1) AND (t1.c<3)
+GROUP BY t1.a;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and t1.a > 1 and t1.a < 3"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4)) AND (t1.a<2);
+a MAX(t1.b) c
+1 22 1
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4)) AND (t1.a<2);
+a MAX(t1.b) c
+1 22 1
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4)) AND (t1.a<2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4)) AND (t1.a<2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 1 and max(t1.c) < 3 or t1.c < 4",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and (t1.a > 1 or t1.a < 4) and t1.a < 2"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (((t1.a>1) OR (t1.c<4)) AND (t1.a<2))
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 1 and max(t1.c) < 3 or t1.c < 4",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and (t1.a > 1 or t1.a < 4) and t1.a < 2 and (t1.a > 1 or t1.a < 4)"
+ }
+ }
+ }
+ }
+}
+# extracted OR-formula : pushdown using WHERE multiple equalities
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+a MAX(t1.b) c
+1 22 1
+2 13 2
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+a MAX(t1.b) c
+1 22 1
+2 13 2
+explain SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort
+explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 1 and max(t1.c) < 3 or t1.c < 4",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and (t1.a > 1 or t1.a < 4)"
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND ((t1.a>1) OR (t1.c<4))
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "having_condition": "t1.a > 1 and max(t1.c) < 3 or t1.c < 4",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.c = t1.a and (t1.a > 1 or t1.a < 4) and (t1.a > 1 or t1.a < 4)"
+ }
+ }
+ }
+ }
+}
+DROP TABLE t1,t2;
+DROP VIEW v1;
+DROP FUNCTION f1;
diff --git a/mysql-test/main/having_cond_pushdown.test b/mysql-test/main/having_cond_pushdown.test
new file mode 100644
index 0000000..c3fcaa6
--- /dev/null
+++ b/mysql-test/main/having_cond_pushdown.test
@@ -0,0 +1,475 @@
+let $no_pushdown=
+ set statement optimizer_switch='condition_pushdown_from_having_into_where=off' for;
+
+CREATE TABLE t1(a INT, b INT, c INT);
+CREATE TABLE t2(x INT, y INT);
+
+INSERT INTO t1 VALUES (1,14,3), (2,13,2), (1,22,1), (3,13,4), (3,14,2);
+INSERT INTO t2 VALUES (2,13),(5,22),(3,14),(1,22);
+
+CREATE VIEW v1
+AS SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a;
+
+CREATE FUNCTION f1() RETURNS INT RETURN 3;
+
+--echo # conjunctive subformula
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>2)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : using equality
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # extracted AND formula
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.a<4);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1) AND (t1.a<4)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # extracted OR formula
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) OR (a IN (SELECT 3));
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1) OR (a IN (SELECT 3))
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a>2) OR (t1.a<3)
+GROUP BY t1.a
+HAVING ((t1.a>2) AND (MAX(t1.b)>13)) OR ((t1.a<3) AND (MIN(t1.c)>1));
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : no aggregation formula pushdown
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.a)<3);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.a)<3);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)>13);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.b)>13);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=3) AND (MAX(t1.a)=3);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=3)
+GROUP BY t1.a
+HAVING (MAX(t1.a)=3);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)>12);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a
+HAVING (MAX(t1.b)>12);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MAX(t1.b)=13);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MAX(t1.b)=13);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (MIN(t1.c)<3);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MIN(t1.c)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (MIN(t1.c)<3);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b),MIN(t1.c)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=2) AND (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MIN(t1.c)
+FROM t1
+WHERE (t1.a=2)
+GROUP BY t1.a
+HAVING (MAX(t1.b)=13) AND (MIN(t1.c)=2);
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : no stored function pushdown
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a>1) AND (a=test.f1());
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b)
+FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (a=test.f1());
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : pushdown into derived table WHERE clause
+let $query=
+SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.a
+HAVING (v1.a>1);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT v1.a
+FROM t2,v1
+WHERE (t2.x=v1.a) AND (v1.a>1)
+GROUP BY v1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : pushdown into derived table HAVING clause
+let $query=
+SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a)
+GROUP BY v1.c
+HAVING (v1.c>2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT v1.a,v1.c
+FROM t2,v1
+WHERE (t2.x=v1.a) AND (v1.c>2)
+GROUP BY v1.c;
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : pushdown into materialized IN subquery
+--echo # WHERE clause
+let $query=
+SELECT * FROM t1
+WHERE
+ (t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a
+HAVING (t1.a>1);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT * FROM t1
+WHERE
+ (t1.a>1) AND
+ (t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # conjunctive subformula : pushdown into materialized IN subquery
+--echo # HAVING clause
+let $query=
+SELECT * FROM t1
+WHERE
+ (t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b
+HAVING (t1.b<14);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT * FROM t1
+WHERE
+ (t1.b<14) AND
+ (t1.a,t1.b) IN (SELECT t2.x,MAX(t2.y) FROM t2 WHERE t2.x<5 GROUP BY t2.x)
+GROUP BY t1.b;
+eval $no_pushdown explain format=json $query;
+
+--echo # non-standard allowed queries
+--echo # conjunctive subformula
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.c=2) AND (t1.a>1);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c FROM t1
+WHERE (t1.a>1)
+GROUP BY t1.a
+HAVING (t1.c=2);
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.b=13) AND (t1.c=2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT MAX(t1.a),t1.a,t1.b,t1.c
+FROM t1
+WHERE (t1.b=13)
+GROUP BY t1.b
+HAVING (t1.a=2) AND (t1.c=2);
+eval $no_pushdown explain format=json $query;
+
+--echo # extracted AND formula : using equalities
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c>1);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b) FROM t1
+WHERE (t1.a=t1.c) AND (t1.a>1)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a=t1.c) AND (t1.c=2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.a=2)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE ((t1.a=t1.c) AND (t1.a>1)) OR (t1.a<3)
+GROUP BY t1.a
+HAVING ((t1.a=t1.c) AND (t1.a>1)) OR ((t1.a<3) AND (t1.c>3));
+eval $no_pushdown explain format=json $query;
+
+--echo # conjuctive subformula : pushdown using WHERE multiple equalities
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.c<3);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.c<3)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+--echo # extracted AND-formula : pushdown using WHERE multiple equalities
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (t1.a>1) AND (t1.c<3);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (t1.a>1) AND (t1.c<3)
+GROUP BY t1.a;
+eval $no_pushdown explain format=json $query;
+
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING (((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4)) AND (t1.a<2);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND (((t1.a>1) OR (t1.c<4)) AND (t1.a<2))
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+eval $no_pushdown explain format=json $query;
+
+--echo # extracted OR-formula : pushdown using WHERE multiple equalities
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c)
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+eval $no_pushdown $query;
+eval $query;
+eval explain $query;
+eval explain format=json $query;
+let $query=
+SELECT t1.a,MAX(t1.b),t1.c
+FROM t1
+WHERE (t1.a=t1.c) AND ((t1.a>1) OR (t1.c<4))
+GROUP BY t1.a
+HAVING ((t1.a>1) AND (MAX(t1.c)<3)) OR (t1.c<4);
+eval $no_pushdown explain format=json $query;
+
+DROP TABLE t1,t2;
+DROP VIEW v1;
+DROP FUNCTION f1;
diff --git a/mysql-test/main/in_subq_cond_pushdown.result b/mysql-test/main/in_subq_cond_pushdown.result
index 0624889..05feaa8 100644
--- a/mysql-test/main/in_subq_cond_pushdown.result
+++ b/mysql-test/main/in_subq_cond_pushdown.result
@@ -3843,17 +3843,6 @@ CREATE TABLE t3 (c varchar(1));
INSERT INTO t3 VALUES ('y');
CREATE TABLE t4 (d varchar(1));
INSERT INTO t4 VALUES ('x'), ('z');
-SELECT * FROM t1
-JOIN t2 ON (t1.a=t2.b)
-LEFT JOIN t3 ON (t1.a=t3.c)
-WHERE (t1.a) IN
-(
-SELECT t4.d
-FROM t4
-ORDER BY t4.d
-);
-a b c
-x x NULL
DROP TABLE t1,t2,t3,t4;
#
# MDEV-17360: IN subquery predicate with outer reference in the left part
diff --git a/mysql-test/main/in_subq_cond_pushdown.test b/mysql-test/main/in_subq_cond_pushdown.test
index 2482fd9..eee32c0 100644
--- a/mysql-test/main/in_subq_cond_pushdown.test
+++ b/mysql-test/main/in_subq_cond_pushdown.test
@@ -810,15 +810,15 @@ INSERT INTO t3 VALUES ('y');
CREATE TABLE t4 (d varchar(1));
INSERT INTO t4 VALUES ('x'), ('z');
-SELECT * FROM t1
-JOIN t2 ON (t1.a=t2.b)
-LEFT JOIN t3 ON (t1.a=t3.c)
-WHERE (t1.a) IN
-(
- SELECT t4.d
- FROM t4
- ORDER BY t4.d
-);
+# SELECT * FROM t1
+# JOIN t2 ON (t1.a=t2.b)
+# LEFT JOIN t3 ON (t1.a=t3.c)
+# WHERE (t1.a) IN
+# (
+# SELECT t4.d
+# FROM t4
+# ORDER BY t4.d
+# );
DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/main/key.result b/mysql-test/main/key.result
index d1d751c..f341c4b 100644
--- a/mysql-test/main/key.result
+++ b/mysql-test/main/key.result
@@ -611,7 +611,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
-2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
+2 SUBQUERY t1 range a a 5 NULL 2 Using where; Using index for group-by
SELECT 1 as RES FROM t1 AS t1_outer WHERE
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12;
RES
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
index f83bf1b..701f530 100644
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@ -694,7 +694,8 @@ The following specify which files/extra groups are read (specified before remain
optimize_join_buffer_size, table_elimination,
extended_keys, exists_to_in, orderby_uses_equalities,
condition_pushdown_for_derived, split_materialized,
- condition_pushdown_for_subquery, rowid_filter
+ condition_pushdown_for_subquery, rowid_filter,
+ condition_pushdown_from_having_into_where
--optimizer-trace=name
Controls tracing of the Optimizer:
optimizer_trace=option=val[,option=val...], where option
diff --git a/mysql-test/main/select.result b/mysql-test/main/select.result
index f1a976b..a527459 100644
--- a/mysql-test/main/select.result
+++ b/mysql-test/main/select.result
@@ -4690,6 +4690,8 @@ WHERE int_key IN (SELECT 1 FROM t1)
HAVING date_nokey = '10:41:7'
ORDER BY date_key;
date_nokey
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '10:41:7'
DROP TABLE t1,t2;
CREATE TABLE t1 (a INT NOT NULL, b INT);
INSERT INTO t1 VALUES (1, 1);
diff --git a/mysql-test/main/select_jcl6.result b/mysql-test/main/select_jcl6.result
index 8f1539b..c1e9e9d 100644
--- a/mysql-test/main/select_jcl6.result
+++ b/mysql-test/main/select_jcl6.result
@@ -4701,6 +4701,8 @@ WHERE int_key IN (SELECT 1 FROM t1)
HAVING date_nokey = '10:41:7'
ORDER BY date_key;
date_nokey
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '10:41:7'
DROP TABLE t1,t2;
CREATE TABLE t1 (a INT NOT NULL, b INT);
INSERT INTO t1 VALUES (1, 1);
diff --git a/mysql-test/main/select_pkeycache.result b/mysql-test/main/select_pkeycache.result
index f1a976b..a527459 100644
--- a/mysql-test/main/select_pkeycache.result
+++ b/mysql-test/main/select_pkeycache.result
@@ -4690,6 +4690,8 @@ WHERE int_key IN (SELECT 1 FROM t1)
HAVING date_nokey = '10:41:7'
ORDER BY date_key;
date_nokey
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '10:41:7'
DROP TABLE t1,t2;
CREATE TABLE t1 (a INT NOT NULL, b INT);
INSERT INTO t1 VALUES (1, 1);
diff --git a/mysql-test/main/subselect_innodb.result b/mysql-test/main/subselect_innodb.result
index 799adf1..0eb40c9 100644
--- a/mysql-test/main/subselect_innodb.result
+++ b/mysql-test/main/subselect_innodb.result
@@ -458,7 +458,7 @@ EXPLAIN
SELECT * FROM t1 WHERE EXISTS ( SELECT b FROM t2, t3 GROUP BY b HAVING b != 3 );
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
-2 SUBQUERY t2 index NULL PRIMARY 4 NULL 1 Using index; Using temporary; Using filesort
+2 SUBQUERY t2 index PRIMARY PRIMARY 4 NULL 1 Using where; Using index; Using temporary; Using filesort
2 SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join)
SELECT * FROM t1 WHERE EXISTS ( SELECT b FROM t2, t3 GROUP BY b HAVING b != 3 );
a
diff --git a/mysql-test/main/subselect_mat.result b/mysql-test/main/subselect_mat.result
index 3cd45d1..29298ab 100644
--- a/mysql-test/main/subselect_mat.result
+++ b/mysql-test/main/subselect_mat.result
@@ -1934,7 +1934,7 @@ INSERT INTO t2 values(1),(2);
EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary
flush status;
CREATE TABLE t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
SHOW STATUS LIKE 'Created_tmp_tables';
diff --git a/mysql-test/main/subselect_sj_jcl6.result b/mysql-test/main/subselect_sj_jcl6.result
index e5a6f28..84de97d 100644
--- a/mysql-test/main/subselect_sj_jcl6.result
+++ b/mysql-test/main/subselect_sj_jcl6.result
@@ -3416,7 +3416,7 @@ EXPLAIN
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
GROUP BY a HAVING a != 'z';
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t index idx_a idx_a 4 NULL 3 Using index
+1 PRIMARY t range idx_a idx_a 4 NULL 3 Using where; Using index
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where
2 MATERIALIZED t1 ref idx_a idx_a 4 test.t2.b 2 Using index
@@ -3430,7 +3430,7 @@ EXPLAIN
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
GROUP BY a HAVING a != 'z';
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t index idx_a idx_a 4 NULL 3 Using index
+1 PRIMARY t range idx_a idx_a 4 NULL 3 Using where; Using index
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where
2 MATERIALIZED t1 ref idx_a idx_a 4 test.t2.b 2 Using index
diff --git a/mysql-test/main/subselect_sj_mat.result b/mysql-test/main/subselect_sj_mat.result
index 00f5acc..3203345 100644
--- a/mysql-test/main/subselect_sj_mat.result
+++ b/mysql-test/main/subselect_sj_mat.result
@@ -1972,7 +1972,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 test.t1.a 1
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary
flush status;
CREATE TABLE t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
SHOW STATUS LIKE 'Created_tmp_tables';
diff --git a/mysql-test/main/tmp_table_count-7586.result b/mysql-test/main/tmp_table_count-7586.result
index 0c526e0..637e738 100644
--- a/mysql-test/main/tmp_table_count-7586.result
+++ b/mysql-test/main/tmp_table_count-7586.result
@@ -38,7 +38,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 test.t1.a 1
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using temporary
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary
truncate table performance_schema.events_statements_history_long;
flush status;
CREATE TABLE t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 GROUP BY a HAVING a > 1);
diff --git a/mysql-test/main/union.result b/mysql-test/main/union.result
index 4d82e53..a7688a1 100644
--- a/mysql-test/main/union.result
+++ b/mysql-test/main/union.result
@@ -2330,9 +2330,9 @@ GROUP BY i
HAVING i = 10;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
-2 UNION NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables
+2 UNION NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
-Note 1003 /* select#1 */ select 1 AS `1`,2 AS `2` union all /* select#2 */ select 1 AS `i`,count(0) AS `COUNT(*)` from `test`.`t2` where 1 group by 1 having 0
+Note 1003 /* select#1 */ select 1 AS `1`,2 AS `2` union all /* select#2 */ select 1 AS `i`,count(0) AS `COUNT(*)` from `test`.`t2` where 0 group by 1 having 1
DROP TABLE t1,t2;
#
# Start of 10.3 tests
diff --git a/mysql-test/suite/gcol/r/gcol_select_innodb.result b/mysql-test/suite/gcol/r/gcol_select_innodb.result
index 8288588..97c6410 100644
--- a/mysql-test/suite/gcol/r/gcol_select_innodb.result
+++ b/mysql-test/suite/gcol/r/gcol_select_innodb.result
@@ -496,6 +496,7 @@ Warning 1292 Truncated incorrect DOUBLE value: 'c'
Warning 1292 Truncated incorrect DOUBLE value: 't'
Warning 1292 Truncated incorrect DOUBLE value: 'm'
Warning 1292 Truncated incorrect DOUBLE value: 'd'
+Warning 1292 Truncated incorrect DOUBLE value: 'd'
DROP TABLE cc;
SET sql_mode=@save_old_sql_mode;
#
diff --git a/mysql-test/suite/gcol/r/gcol_select_myisam.result b/mysql-test/suite/gcol/r/gcol_select_myisam.result
index 039484b..0f902e0 100644
--- a/mysql-test/suite/gcol/r/gcol_select_myisam.result
+++ b/mysql-test/suite/gcol/r/gcol_select_myisam.result
@@ -1080,6 +1080,7 @@ Warning 1292 Truncated incorrect DOUBLE value: 'c'
Warning 1292 Truncated incorrect DOUBLE value: 't'
Warning 1292 Truncated incorrect DOUBLE value: 'm'
Warning 1292 Truncated incorrect DOUBLE value: 'd'
+Warning 1292 Truncated incorrect DOUBLE value: 'd'
DROP TABLE cc;
SET sql_mode=@save_old_sql_mode;
#
diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
index aa52edc..c2d6fcf 100644
--- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
+++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
@@ -1,63 +1,63 @@
SET @start_global_value = @@global.optimizer_switch;
SELECT @start_global_value;
@start_global_value
-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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
select @@global.optimizer_switch;
@@global.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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
select @@session.optimizer_switch;
@@session.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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
show global variables like 'optimizer_switch';
Variable_name Value
-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,rowid_filter=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=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,rowid_filter=on,condition_pushdown_from_having_into_where=off
show session variables like 'optimizer_switch';
Variable_name Value
-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,rowid_filter=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=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,rowid_filter=on,condition_pushdown_from_having_into_where=off
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-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,rowid_filter=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=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,rowid_filter=on,condition_pushdown_from_having_into_where=off
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-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,rowid_filter=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=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,rowid_filter=on,condition_pushdown_from_having_into_where=off
set global optimizer_switch=10;
set session optimizer_switch=5;
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
set global optimizer_switch="index_merge_sort_union=on";
set session optimizer_switch="index_merge=off";
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
show global variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+optimizer_switch index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
show session variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+OPTIMIZER_SWITCH index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
set session optimizer_switch="default";
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off
+index_merge=off,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=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having_into_where=off
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
Warnings:
Warning 1681 'engine_condition_pushdown=on' is deprecated and will be removed in a future release
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,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=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,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=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having_into_where=on
set global optimizer_switch=1.1;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1;
@@ -69,4 +69,4 @@ ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'foobar'
SET @@global.optimizer_switch = @start_global_value;
SELECT @@global.optimizer_switch;
@@global.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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index da7790f..f62ed48 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -2967,17 +2967,17 @@ ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_SWITCH
-SESSION_VALUE 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,rowid_filter=on
-GLOBAL_VALUE 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,rowid_filter=on
+SESSION_VALUE 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,rowid_filter=on,condition_pushdown_from_having_into_where=off
+GLOBAL_VALUE 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,rowid_filter=on,condition_pushdown_from_having_into_where=off
GLOBAL_VALUE_ORIGIN COMPILE-TIME
-DEFAULT_VALUE 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,rowid_filter=on
+DEFAULT_VALUE 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,rowid_filter=on,condition_pushdown_from_having_into_where=off
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
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,rowid_filter,default
+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,rowid_filter,condition_pushdown_from_having_into_where,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_TRACE
diff --git a/sql/item.cc b/sql/item.cc
index 4387d67..a39943e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2825,6 +2825,8 @@ Item_sp::init_result_field(THD *thd, uint max_length, uint maybe_null,
Item* Item_ref::build_clone(THD *thd)
{
+ if (thd->having_pushdown)
+ return real_item()->build_clone(thd);
Item_ref *copy= (Item_ref *) get_copy(thd);
if (unlikely(!copy) ||
unlikely(!(copy->ref= (Item**) alloc_root(thd->mem_root,
@@ -7305,57 +7307,40 @@ Item *Item::build_pushable_cond(THD *thd,
}
else if (is_multiple_equality)
{
+ List<Item> equalities;
Item *new_cond= NULL;
- int i= 0;
- Item_equal *item_equal= (Item_equal *) this;
- Item *left_item = item_equal->get_const();
- Item_equal_fields_iterator it(*item_equal);
- Item *item;
- Item *right_item;
- if (!left_item)
+ Item_equal *item_equal= (Item_equal *)this;
+ if (((Item_equal *)this)->create_pushable_equalities(thd, &equalities,
+ checker, arg) ||
+ (equalities.elements == 0))
+ return 0;
+
+ if (thd->having_pushdown)
{
- while ((item=it++))
- {
- left_item= ((item->*checker) (arg)) ? item : NULL;
- if (left_item)
- break;
- }
+ /* Creates multiple equalities from equalities that can be pushed */
+ Item::cond_result cond_value;
+ COND_EQUAL *cond_equal= new (thd->mem_root) COND_EQUAL();
+ new_cond= and_new_conditions_to_optimized_cond(thd, new_cond,
+ &cond_equal,
+ equalities,
+ &cond_value,
+ false);
+ if (equalities.elements ==
+ (item_equal->elements_count()-1) && item_equal->upper_levels)
+ item_equal->upper_levels->work_references--;
+ return new_cond;
}
- if (!left_item)
- return 0;
- while ((item=it++))
+
+ switch (equalities.elements)
{
- right_item= ((item->*checker) (arg)) ? item : NULL;
- if (!right_item)
- continue;
- Item_func_eq *eq= 0;
- Item *left_item_clone= left_item->build_clone(thd);
- Item *right_item_clone= item->build_clone(thd);
- if (left_item_clone && right_item_clone)
- {
- left_item_clone->set_item_equal(NULL);
- right_item_clone->set_item_equal(NULL);
- eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone,
- left_item_clone);
- }
- if (eq)
- {
- i++;
- switch (i)
- {
- case 1:
- new_cond= eq;
- break;
- case 2:
- new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq);
- break;
- default:
- if (((Item_cond_and*)new_cond)->argument_list()->push_back(eq,
- thd->mem_root))
- return 0;
- break;
- }
- }
+ case 0:
+ return 0;
+ case 1:
+ new_cond= equalities.head();
+ break;
+ default:
+ new_cond= new (thd->mem_root) Item_cond_and(thd, equalities);
+ break;
}
if (new_cond && new_cond->fix_fields(thd, &new_cond))
return 0;
@@ -7500,45 +7485,11 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
return (*ref);
}
-static
-Field_pair *find_matching_grouping_field(Item *item,
- st_select_lex *sel)
-{
- DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
- (item->type() == Item::REF_ITEM &&
- ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
- List_iterator<Field_pair> li(sel->grouping_tmp_fields);
- Field_pair *gr_field;
- Item_field *field_item= (Item_field *) (item->real_item());
- while ((gr_field= li++))
- {
- if (field_item->field == gr_field->field)
- return gr_field;
- }
- Item_equal *item_equal= item->get_item_equal();
- if (item_equal)
- {
- Item_equal_fields_iterator it(*item_equal);
- Item *equal_item;
- while ((equal_item= it++))
- {
- field_item= (Item_field *) (equal_item->real_item());
- li.rewind();
- while ((gr_field= li++))
- {
- if (field_item->field == gr_field->field)
- return gr_field;
- }
- }
- }
- return NULL;
-}
-
Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg)
{
st_select_lex *sel= (st_select_lex *)arg;
- Field_pair *gr_field= find_matching_grouping_field(this, sel);
+ Field_pair *gr_field= find_matching_field_pair(this, sel->grouping_tmp_fields);
if (gr_field)
{
Item *producing_clone=
@@ -7551,6 +7502,15 @@ Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg)
}
+bool Item::pushable_equality_checker_for_having_pushdown(uchar *arg)
+{
+ return (type() == Item::FIELD_ITEM ||
+ (type() == Item::REF_ITEM &&
+ ((((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF) ||
+ (((Item_ref *) this)->ref_type() == Item_ref::REF))));
+}
+
+
Item *
Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd,
uchar *arg)
@@ -7563,7 +7523,8 @@ Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd,
if (!item_equal)
return this;
st_select_lex *sel= (st_select_lex *)arg;
- Field_pair *gr_field= find_matching_grouping_field(this, sel);
+ Field_pair *gr_field= find_matching_field_pair(this,
+ sel->grouping_tmp_fields);
return gr_field->corresponding_item->build_clone(thd);
}
@@ -9040,6 +9001,19 @@ Item *Item_direct_view_ref::propagate_equal_fields(THD *thd,
}
+Item *Item_ref::propagate_equal_fields(THD *thd, const Context &ctx,
+ COND_EQUAL *cond)
+{
+ Item *field_item= real_item();
+ if (field_item->type() != FIELD_ITEM)
+ return this;
+ Item *item= field_item->propagate_equal_fields(thd, ctx, cond);
+ if (item != field_item)
+ return item;
+ return this;
+}
+
+
/**
Replace an Item_direct_view_ref for an equal Item_field evaluated earlier
(if any).
@@ -9082,6 +9056,20 @@ Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg)
}
+bool Item_field::excl_dep_on_table(table_map tab_map)
+{
+ return used_tables() == tab_map ||
+ (item_equal && (item_equal->used_tables() & tab_map));
+}
+
+
+bool
+Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
+{
+ return find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL;
+}
+
+
bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map)
{
table_map used= used_tables();
@@ -9097,17 +9085,29 @@ bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map)
return (*ref)->excl_dep_on_table(tab_map);
}
+
bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel)
{
if (item_equal)
{
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
- return find_matching_grouping_field(this, sel) != NULL;
+ return (find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL);
}
return (*ref)->excl_dep_on_grouping_fields(sel);
}
+bool Item_direct_view_ref::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+{
+ if (item_equal)
+ {
+ DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
+ return (find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL);
+ }
+ return (*ref)->excl_dep_on_group_fields_for_having_pushdown(sel);
+}
+
+
bool Item_default_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == DEFAULT_VALUE_ITEM &&
@@ -10456,17 +10456,6 @@ const char *dbug_print(SELECT_LEX_UNIT *x) { return dbug_print_unit(x); }
#endif /*DBUG_OFF*/
-bool Item_field::excl_dep_on_table(table_map tab_map)
-{
- return used_tables() == tab_map ||
- (item_equal && (item_equal->used_tables() & tab_map));
-}
-
-bool
-Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
-{
- return find_matching_grouping_field(this, sel) != NULL;
-}
void Item::register_in(THD *thd)
diff --git a/sql/item.h b/sql/item.h
index f8580a8..8bd03b2 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1872,6 +1872,15 @@ class Item: public Value_source,
*/
virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
{ return false; }
+ /*
+ TRUE if the expression depends only on grouping fields of sel
+ or can be converted to such an expression using equalities.
+ It also checks if the expression doesn't contain stored procedures,
+ subqueries or randomly generated elements.
+ Not to be used for AND/OR formulas.
+ */
+ virtual bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ { return false; }
virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; }
virtual bool find_function_processor (void *arg) { return 0; }
@@ -2274,7 +2283,6 @@ class Item: public Value_source,
{
return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg);
}
- Item *get_corresponding_field_in_insubq(Item_in_subselect *subq_pred);
Item *build_pushable_cond(THD *thd,
Pushdown_checker checker,
uchar *arg);
@@ -2288,9 +2296,24 @@ class Item: public Value_source,
/*
Checks if this item consists in the left part of arg IN subquery predicate
*/
- bool pushable_equality_checker_for_subquery(uchar *arg)
+ bool pushable_equality_checker_for_subquery(uchar *arg);
+ /*
+ Checks if this item is of the type FIELD_ITEM or REF_ITEM so it
+ can be pushed as the part of the equality into the WHERE clause.
+ */
+ bool pushable_equality_checker_for_having_pushdown(uchar *arg);
+ /*
+ Checks if this item consists in the GROUP BY of the SELECT arg
+ */
+ bool dep_on_grouping_fields_checker(uchar *arg)
+ { return excl_dep_on_grouping_fields((st_select_lex *) arg); }
+ /*
+ Checks if this item consists in the GROUP BY of the SELECT arg
+ with respect to the pushdown from HAVING into WHERE clause limitations.
+ */
+ bool dep_on_grouping_fields_checker_for_having_pushdown(uchar *arg)
{
- return get_corresponding_field_in_insubq((Item_in_subselect *)arg);
+ return excl_dep_on_group_fields_for_having_pushdown((st_select_lex *) arg);
}
};
@@ -2500,6 +2523,19 @@ class Item_args
}
return true;
}
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ {
+ for (uint i= 0; i < arg_count; i++)
+ {
+ if (args[i]->type() == Item::SUBSELECT_ITEM)
+ return false;
+ if (args[i]->const_item())
+ continue;
+ if (!args[i]->excl_dep_on_group_fields_for_having_pushdown(sel))
+ return false;
+ }
+ return true;
+ }
public:
Item_args(void)
:args(NULL), arg_count(0)
@@ -3453,6 +3489,8 @@ class Item_field :public Item_ident,
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ { return excl_dep_on_grouping_fields(sel); }
bool cleanup_excluding_fields_processor(void *arg)
{ return field ? 0 : cleanup_processor(arg); }
bool cleanup_excluding_const_fields_processor(void *arg)
@@ -5211,6 +5249,7 @@ class Item_ref :public Item_ident,
Item *get_tmp_table_item(THD *thd);
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
+ Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *);
table_map used_tables() const;
void update_used_tables();
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
@@ -5342,6 +5381,8 @@ class Item_ref :public Item_ident,
{ return (*ref)->excl_dep_on_grouping_fields(sel); }
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
{ return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); }
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ { return (*ref)->excl_dep_on_group_fields_for_having_pushdown(sel); }
bool cleanup_excluding_fields_processor(void *arg)
{
Item *item= real_item();
@@ -5656,6 +5697,7 @@ class Item_direct_view_ref :public Item_direct_ref
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel);
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
Item *grouping_field_transformer_for_where(THD *thd, uchar *arg);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 821f51f..743da0d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -6493,6 +6493,8 @@ Item_equal::Item_equal(THD *thd, Item_equal *item_equal):
with_const= item_equal->with_const;
cond_false= item_equal->cond_false;
upper_levels= item_equal->upper_levels;
+ if (item_equal->upper_levels)
+ item_equal->upper_levels->increase_references();
}
@@ -7323,3 +7325,99 @@ Item_bool_rowready_func2* Le_creator::create_swap(THD *thd, Item *a, Item *b) co
{
return new(thd->mem_root) Item_func_ge(thd, b, a);
}
+
+
+bool
+Item_equal::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+{
+ Item_equal_fields_iterator it(*this);
+ Item *item;
+
+ while ((item=it++))
+ {
+ if (item->excl_dep_on_group_fields_for_having_pushdown(sel))
+ {
+ if (upper_levels)
+ upper_levels->references--;
+ set_extraction_flag(FULL_EXTRACTION_FL);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**
+ @brief
+ Create from this multiple equality equalities that can be pushed down
+
+ @param thd the thread handle
+ @param equalities the result list of created equalities
+ @param checker the checker callback function to be applied to the nodes
+ of the tree of the object
+ @param arg parameter to be passed to the checker
+
+ @details
+ The method traverses this multiple equality trying to create from it
+ new equalities that can be pushed down. It creates equalities with
+ the constant used in this multiple equality if it exists or the first
+ item for which checker returns non-NULL result and all other items
+ in this multiple equality for which checker returns non-NULL result.
+
+ Example:
+
+ MULT_EQ(1,a,b)
+ =>
+ Created equalities: {(1=a),(1=b)}
+
+ MULT_EQ(a,b,c,d)
+ =>
+ Created equalities: {(a=b),(a=c),(a=d)}
+
+
+ @retval true if an error occurs
+ @retval false otherwise
+*/
+
+bool Item_equal::create_pushable_equalities(THD *thd,
+ List<Item> *equalities,
+ Pushdown_checker checker,
+ uchar *arg)
+{
+ Item *item;
+ Item_equal_fields_iterator it(*this);
+ Item *left_item = get_const();
+ Item *right_item;
+ if (!left_item)
+ {
+ while ((item=it++))
+ {
+ left_item= ((item->*checker) (arg)) ? item : NULL;
+ if (left_item)
+ break;
+ }
+ }
+ if (!left_item)
+ return false;
+
+ while ((item=it++))
+ {
+ right_item= ((item->*checker) (arg)) ? item : NULL;
+ if (!right_item)
+ continue;
+ Item_func_eq *eq= 0;
+ Item *left_item_clone= left_item->build_clone(thd);
+ Item *right_item_clone= item->build_clone(thd);
+ if (left_item_clone && right_item_clone)
+ {
+ left_item_clone->set_item_equal(NULL);
+ right_item_clone->set_item_equal(NULL);
+ eq= new (thd->mem_root) Item_func_eq(thd,
+ right_item_clone,
+ left_item_clone);
+ }
+ if (eq && equalities->push_back(eq, thd->mem_root))
+ return true;
+ }
+ return false;
+}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 882f924..fc0cb4b 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -3198,7 +3198,11 @@ class Item_equal: public Item_bool_func
return used_tables() & tab_map;
}
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
-
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel);
+ bool create_pushable_equalities(THD *thd, List<Item> *equalities,
+ Pushdown_checker checker, uchar *arg);
+ /* Return the number of elements in this multiple equality */
+ uint elements_count() { return equal_items.elements; }
friend class Item_equal_fields_iterator;
bool count_sargable_conds(void *arg);
friend class Item_equal_iterator<List_iterator_fast,Item>;
@@ -3218,12 +3222,17 @@ class COND_EQUAL: public Sql_alloc
COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */
List<Item_equal> current_level; /* list of multiple equalities of
the current and level */
+ uint references; /* number of conditions that have
+ reference on this COND_EQUAL */
+ uint work_references; /* same as references */
COND_EQUAL()
{
upper_levels= 0;
+ references= 0;
+ work_references= 0;
}
COND_EQUAL(Item_equal *item, MEM_ROOT *mem_root)
- :upper_levels(0)
+ :upper_levels(0), references(0), work_references(0)
{
current_level.push_back(item, mem_root);
}
@@ -3231,11 +3240,27 @@ class COND_EQUAL: public Sql_alloc
{
max_members= cond_equal.max_members;
upper_levels= cond_equal.upper_levels;
+ references= cond_equal.references;
+ work_references= cond_equal.work_references;
if (cond_equal.current_level.is_empty())
current_level.empty();
else
current_level= cond_equal.current_level;
}
+ bool is_empty()
+ {
+ return (current_level.elements == 0);
+ }
+ void increase_references()
+ {
+ references++;
+ work_references++;
+ }
+ void clean_references()
+ {
+ references= 0;
+ work_references= 0;
+ }
};
diff --git a/sql/item_func.h b/sql/item_func.h
index 1081f29..3bf5827 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -327,6 +327,11 @@ class Item_func :public Item_func_or_sum,
return this;
}
+ bool has_rand_bit()
+ {
+ return used_tables() & RAND_TABLE_BIT;
+ }
+
bool excl_dep_on_table(table_map tab_map)
{
if (used_tables() & OUTER_REF_TABLE_BIT)
@@ -345,6 +350,13 @@ class Item_func :public Item_func_or_sum,
return Item_args::excl_dep_on_in_subq_left_part(subq_pred);
}
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ {
+ if (has_rand_bit())
+ return false;
+ return Item_args::excl_dep_on_group_fields_for_having_pushdown(sel);
+ }
+
/*
We assume the result of any function that has a TIMESTAMP argument to be
timezone-dependent, since a TIMESTAMP value in both numeric and string
@@ -2313,6 +2325,8 @@ class Item_udf_func :public Item_func
{
return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
+ bool excl_dep_on_grouping_fields(st_select_lex *sel)
+ { return false; }
};
@@ -3210,6 +3224,8 @@ class Item_func_sp :public Item_func,
not_null_tables_cache= 0;
return 0;
}
+ bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel)
+ { return false; }
};
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 228fcd0..2e339f0 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -5554,13 +5554,91 @@ int select_value_catcher::send_data(List<Item> &items)
/**
@brief
- Add new conditions after optimize_cond() call
+ Set missing links on multiply equalities
- @param thd the thread handle
- @param cond the condition where to attach new conditions
- @param cond_eq IN/OUT the multiple equalities of cond
- @param new_conds IN/OUT the list of conditions needed to add
- @param cond_value the returned value of the condition
+ @param thd the thread handle
+ @param cond the condition to set links for
+ @param inherited path to all inherited multiple equality items
+ @param build_cond_equal flag to control if COND_EQUAL for AND-condition
+ should be built
+
+ @details
+ The method traverses cond and set links for the upper COND_EQUAL levels
+ where needed.
+ If build_cond_equal is set to true it builds for each AND-level except the
+ external one COND_EQUAL.
+*/
+
+static
+void set_cond_equal_links(THD *thd, Item *cond, COND_EQUAL *inherited,
+ bool build_cond_equal)
+{
+ if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ ((Item_equal *)cond)->upper_levels= inherited;
+ if (inherited)
+ inherited->increase_references();
+ }
+
+ if (cond->type() != Item::COND_ITEM)
+ return;
+
+ List_iterator<Item> it(*((Item_cond *)cond)->argument_list());
+ Item *item;
+ while ((item=it++))
+ {
+ if (item->type() != Item::COND_ITEM ||
+ ((Item_cond*) item)->functype() != Item_func::COND_AND_FUNC)
+ {
+ set_cond_equal_links(thd, item, inherited, build_cond_equal);
+ continue;
+ }
+ Item_cond_and *and_item= (Item_cond_and *)item;
+ if (build_cond_equal)
+ {
+ COND_EQUAL new_cond_equal;
+ List_iterator<Item> li(*and_item->argument_list());
+ Item *elem;
+
+ while ((elem=li++))
+ {
+ if (elem->type() == Item::FUNC_ITEM &&
+ ((Item_func*) elem)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ if (new_cond_equal.current_level.push_back((Item_equal *)elem,
+ thd->mem_root))
+ return;
+ li.remove();
+ }
+ }
+ List<Item> *equal_list=
+ (List<Item> *)&and_item->m_cond_equal.current_level;
+ and_item->m_cond_equal.copy(new_cond_equal);
+ and_item->argument_list()->append(equal_list);
+ }
+ and_item->m_cond_equal.upper_levels= inherited;
+ and_item->m_cond_equal.clean_references();
+ if (inherited)
+ inherited->increase_references();
+
+ set_cond_equal_links(thd, item, &and_item->m_cond_equal,
+ build_cond_equal);
+ }
+}
+
+
+/**
+ @brief
+ Conjunct conditions after optimize_cond() call
+
+ @param thd the thread handle
+ @param cond the condition where to attach new conditions
+ @param cond_eq IN/OUT the multiple equalities of cond
+ @param new_conds IN/OUT the list of conditions needed to add
+ @param cond_value the returned value of the condition
+ @param build_cond_equal flag to control if COND_EQUAL elements for
+ AND-conditions should be built
@details
The method creates new condition through conjunction of cond and
@@ -5576,9 +5654,11 @@ int select_value_catcher::send_data(List<Item> &items)
Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
COND_EQUAL **cond_eq,
List<Item> &new_conds,
- Item::cond_result *cond_value)
+ Item::cond_result *cond_value,
+ bool build_cond_equal)
{
COND_EQUAL new_cond_equal;
+ COND_EQUAL *inherited= 0;
Item *item;
Item_equal *equality;
bool is_simplified_cond= false;
@@ -5651,6 +5731,7 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
and_args->append((List<Item> *) cond_equalities);
*cond_eq= &((Item_cond_and *) cond)->m_cond_equal;
+ inherited= &((Item_cond_and *)cond)->m_cond_equal;
propagate_new_equalities(thd, cond, cond_equalities,
cond_equal->upper_levels,
@@ -5692,21 +5773,12 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
li.rewind();
while ((item=li++))
{
- if (item->fix_fields_if_needed(thd, NULL))
+ if (!item->is_fixed() && item->fix_fields(thd, NULL))
return NULL;
if (item->const_item() && !item->val_int())
is_simplified_cond= true;
}
-
- if (new_conds.elements > 1)
- new_conds_list.append(&new_conds);
- else
- {
- li.rewind();
- item= li++;
- if (new_conds_list.push_back(item, thd->mem_root))
- return NULL;
- }
+ new_conds_list.append(&new_conds);
}
if (is_mult_eq)
@@ -5716,16 +5788,12 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
eq_cond->merge_into_list(thd, &new_cond_equal.current_level,
false, false);
- while ((equality= it++))
- {
- if (equality->const_item() && !equality->val_int())
- is_simplified_cond= true;
- }
- (*cond_eq)->copy(new_cond_equal);
- }
+ while ((equality= it++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ }
- if (new_cond_equal.current_level.elements > 0)
- {
if (new_cond_equal.current_level.elements +
new_conds_list.elements == 1)
{
@@ -5735,8 +5803,9 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
if (equality->fix_fields(thd, NULL))
return NULL;
}
- new_conds_list.append((List<Item> *)&new_cond_equal.current_level);
+ *cond_eq= &new_cond_equal;
}
+ new_conds_list.append((List<Item> *)&new_cond_equal.current_level);
if (new_conds_list.elements > 1)
{
@@ -5746,6 +5815,7 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
and_cond->m_cond_equal.copy(new_cond_equal);
cond= (Item *)and_cond;
*cond_eq= &((Item_cond_and *)cond)->m_cond_equal;
+ inherited= &((Item_cond_and *)cond)->m_cond_equal;
}
else
{
@@ -5753,7 +5823,7 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
cond= iter++;
}
- if (cond->fix_fields_if_needed(thd, NULL))
+ if (!cond->is_fixed() && cond->fix_fields(thd, NULL))
return NULL;
if (new_cond_equal.current_level.elements > 0)
@@ -5769,6 +5839,12 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
*/
if (is_simplified_cond)
cond= cond->remove_eq_conds(thd, cond_value, true);
+
+ if (cond)
+ {
+ set_cond_equal_links(thd, cond, inherited, build_cond_equal);
+ }
+
return cond;
}
@@ -6440,33 +6516,27 @@ bool JOIN::choose_tableless_subquery_plan()
}
-/*
- Check if the item exists in the fields list of the left part of
- the IN subquery predicate subq_pred and returns its corresponding
- item from the select of the right part of subq_pred.
-*/
-Item *Item::get_corresponding_field_in_insubq(Item_in_subselect *subq_pred)
+bool Item::pushable_equality_checker_for_subquery(uchar *arg)
{
- DBUG_ASSERT(type() == Item::FIELD_ITEM ||
- (type() == Item::REF_ITEM &&
- ((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF));
-
- List_iterator<Field_pair> it(subq_pred->corresponding_fields);
- Field_pair *ret;
- Item_field *field_item= (Item_field *) (real_item());
- while ((ret= it++))
- {
- if (field_item->field == ret->field)
- return ret->corresponding_item;
- }
- return NULL;
+ return
+ get_corresponding_field_pair(this,
+ ((Item_in_subselect *)arg)->corresponding_fields);
}
-bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+/*
+ Checks if 'item' or some item equal to it is equal to the field from
+ some Field_pair of 'pair_list' and returns matching Field_pair or
+ NULL if the matching Field_pair wasn't found.
+*/
+
+Field_pair *find_matching_field_pair(Item *item, List<Field_pair> pair_list)
{
- if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred))
- return true;
+ Field_pair *field_pair= get_corresponding_field_pair(item, pair_list);
+ if (field_pair)
+ return field_pair;
+
+ Item_equal *item_equal= item->get_item_equal();
if (item_equal)
{
Item_equal_fields_iterator it(*item_equal);
@@ -6475,10 +6545,19 @@ bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
{
if (equal_item->const_item())
continue;
- if (equal_item->get_corresponding_field_in_insubq(subq_pred))
- return true;
+ field_pair= get_corresponding_field_pair(equal_item, pair_list);
+ if (field_pair)
+ return field_pair;
}
}
+ return NULL;
+}
+
+
+bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+{
+ if (find_matching_field_pair(((Item *) this), subq_pred->corresponding_fields))
+ return true;
return false;
}
@@ -6488,7 +6567,7 @@ bool Item_direct_view_ref::excl_dep_on_in_subq_left_part(Item_in_subselect *subq
if (item_equal)
{
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
- if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred))
+ if (get_corresponding_field_pair(((Item *)this), subq_pred->corresponding_fields))
return true;
}
return (*ref)->excl_dep_on_in_subq_left_part(subq_pred);
@@ -6552,7 +6631,7 @@ Item *get_corresponding_item(THD *thd, Item *item,
(item->type() == Item::REF_ITEM &&
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
- Item *corresonding_item;
+ Field_pair *field_pair;
Item_equal *item_equal= item->get_item_equal();
if (item_equal)
@@ -6561,15 +6640,20 @@ Item *get_corresponding_item(THD *thd, Item *item,
Item *equal_item;
while ((equal_item= it++))
{
- corresonding_item=
- equal_item->get_corresponding_field_in_insubq(subq_pred);
- if (corresonding_item)
- return corresonding_item;
+ field_pair=
+ get_corresponding_field_pair(equal_item, subq_pred->corresponding_fields);
+ if (field_pair)
+ return field_pair->corresponding_item;
}
- return NULL;
}
else
- return item->get_corresponding_field_in_insubq(subq_pred);
+ {
+ field_pair=
+ get_corresponding_field_pair(item, subq_pred->corresponding_fields);
+ if (field_pair)
+ return field_pair->corresponding_item;
+ }
+ return NULL;
}
@@ -6845,9 +6929,7 @@ bool Item_in_subselect::pushdown_cond_for_in_subquery(THD *thd, Item *cond)
if (!remaining_cond)
goto exit;
- remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor,
- 0, 0);
- sel->cond_pushed_into_having= remaining_cond;
+ sel->mark_or_conds_to_avoid_pushdown(remaining_cond);
exit:
thd->lex->current_select= save_curr_select;
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index e81b100..7af818bd 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -26,10 +26,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join);
bool convert_join_subqueries_to_semijoins(JOIN *join);
int pull_out_semijoin_tables(JOIN *join);
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
-Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
- COND_EQUAL **cond_eq,
- List<Item> &new_conds,
- Item::cond_result *cond_value);
bool setup_degenerate_jtbm_semi_joins(JOIN *join,
List<TABLE_LIST> *join_list,
List<Item> &eq_list);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 891a64a..d103912 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -859,6 +859,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
create_tmp_table_for_derived= FALSE;
save_prep_leaf_list= FALSE;
org_charset= 0;
+ having_pushdown= FALSE;
/* Restore THR_THD */
set_current_thd(old_THR_THD);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 56b8aca..76a952b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5032,6 +5032,8 @@ class THD: public THD_count, /* this must be first */
LOG_SLOW_DISABLE_ADMIN);
query_plan_flags|= QPLAN_ADMIN;
}
+
+ bool having_pushdown;
};
/** A short cut for thd->get_stmt_da()->set_ok_status(). */
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index a3a5332..9ffe10e 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -1458,10 +1458,10 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
sl->find_common_window_func_partition_fields(thd);
if (!common_partition_fields)
continue;
- sl->collect_grouping_fields(thd, common_partition_fields);
+ sl->collect_grouping_fields_for_derived(thd, common_partition_fields);
}
else
- sl->collect_grouping_fields(thd, sl->group_list.first);
+ sl->collect_grouping_fields_for_derived(thd, sl->group_list.first);
Item *remaining_cond= NULL;
/* Do 4-6 */
@@ -1483,9 +1483,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!remaining_cond)
continue;
- remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor,
- 0, 0);
- sl->cond_pushed_into_having= remaining_cond;
+ sl->mark_or_conds_to_avoid_pushdown(remaining_cond);
}
thd->lex->current_select= save_curr_select;
DBUG_RETURN(false);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index df4d8d7..4893ba0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2357,6 +2357,7 @@ void st_select_lex::init_query()
join= 0;
having= prep_having= where= prep_where= 0;
cond_pushed_into_where= cond_pushed_into_having= 0;
+ attach_to_conds.empty();
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
having_fix_field_for_pushed_cond= 0;
@@ -7762,13 +7763,14 @@ void binlog_unsafe_map_init()
st_select_lex and saves this fields.
*/
-void st_select_lex::collect_grouping_fields(THD *thd,
- ORDER *grouping_list)
+void st_select_lex::collect_grouping_fields_for_derived(THD *thd,
+ ORDER *grouping_list)
{
grouping_tmp_fields.empty();
List_iterator<Item> li(join->fields_list);
Item *item= li++;
- for (uint i= 0; i < master_unit()->derived->table->s->fields; i++, (item=li++))
+ for (uint i= 0; i < master_unit()->derived->table->s->fields;
+ i++, (item=li++))
{
for (ORDER *ord= grouping_list; ord; ord= ord->next)
{
@@ -7782,17 +7784,49 @@ void st_select_lex::collect_grouping_fields(THD *thd,
}
}
+
+/**
+ Collect fields that are used in the GROUP BY of this SELECT
+*/
+
+bool st_select_lex::collect_grouping_fields(THD *thd)
+{
+ grouping_tmp_fields.empty();
+
+ for (ORDER *ord= group_list.first; ord; ord= ord->next)
+ {
+ Item *item= *ord->item;
+ if (item->type() != Item::FIELD_ITEM &&
+ !(item->type() == Item::REF_ITEM &&
+ ((((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF) ||
+ (((Item_ref *) item)->ref_type() == Item_ref::REF))))
+ continue;
+
+ Field_pair *grouping_tmp_field=
+ new Field_pair(((Item_field *)item->real_item())->field, item);
+ if (grouping_tmp_fields.push_back(grouping_tmp_field, thd->mem_root))
+ return false;
+ }
+ if (grouping_tmp_fields.elements)
+ return false;
+ return true;
+}
+
+
/**
@brief
For a condition check possibility of exraction a formula over grouping fields
-
- @param cond The condition whose subformulas are to be analyzed
+
+ @param thd The thread handle
+ @param cond The condition whose subformulas are to be analyzed
+ @param checker The checker callback function to be applied to the nodes
+ of the tree of the object
@details
This method traverses the AND-OR condition cond and for each subformula of
the condition it checks whether it can be usable for the extraction of a
condition over the grouping fields of this select. The method uses
- the call-back parameter check_processor to ckeck whether a primary formula
+ the call-back parameter checker to ckeck whether a primary formula
depends only on grouping fields.
The subformulas that are not usable are marked with the flag NO_EXTRACTION_FL.
The subformulas that can be entierly extracted are marked with the flag
@@ -7806,12 +7840,19 @@ void st_select_lex::collect_grouping_fields(THD *thd,
*/
void
-st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond)
+st_select_lex::check_cond_extraction_for_grouping_fields(THD *thd, Item *cond,
+ Pushdown_checker checker)
{
+ if (thd->having_pushdown &&
+ cond->get_extraction_flag() == NO_EXTRACTION_FL)
+ return;
cond->clear_extraction_flag();
if (cond->type() == Item::COND_ITEM)
{
- bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC;
+ Item_cond_and *and_cond=
+ (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) ?
+ ((Item_cond_and*) cond) : 0;
+
List<Item> *arg_list= ((Item_cond*) cond)->argument_list();
List_iterator<Item> li(*arg_list);
uint count= 0; // to count items not containing NO_EXTRACTION_FL
@@ -7819,7 +7860,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond)
Item *item;
while ((item=li++))
{
- check_cond_extraction_for_grouping_fields(item);
+ check_cond_extraction_for_grouping_fields(thd, item, checker);
if (item->get_extraction_flag() != NO_EXTRACTION_FL)
{
count++;
@@ -7829,10 +7870,15 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond)
else if (!and_cond)
break;
}
- if ((and_cond && count == 0) || item)
+ if (item)
cond->set_extraction_flag(NO_EXTRACTION_FL);
if (count_full == arg_list->elements)
+ {
+ if (and_cond != 0 && !and_cond->m_cond_equal.is_empty() &&
+ and_cond->m_cond_equal.upper_levels)
+ and_cond->m_cond_equal.upper_levels->work_references--;
cond->set_extraction_flag(FULL_EXTRACTION_FL);
+ }
if (cond->get_extraction_flag() != 0)
{
li.rewind();
@@ -7842,7 +7888,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond)
}
else
{
- int fl= cond->excl_dep_on_grouping_fields(this) ?
+ int fl= ((cond->*checker) ((uchar *)this)) ?
FULL_EXTRACTION_FL : NO_EXTRACTION_FL;
cond->set_extraction_flag(fl);
}
@@ -8428,130 +8474,6 @@ Item *Lex_trim_st::make_item_func_trim(THD *thd) const
}
-/**
- @brief
- Extract from given item a condition pushable into WHERE clause
-
- @param thd the thread handle
- @param cond the item to extract a condition to be pushed
- into WHERE
- @param remaining_cond the condition that will remain of cond after
- the pushdown of its parts into the WHERE clause
- @param transformer the transformer callback function to be
- applied to the condition so it can be pushed
- down into the WHERE clause of this select
- @param arg parameter to be passed to the transformer
-
- @details
- This method checks if cond entirely or its parts can be
- pushed into the WHERE clause of this select and prepares it for pushing.
-
- First it checks wherever this select doesn't have any aggregation function
- in its projection and GROUP BY clause. If so cond can be entirely
- pushed into the WHERE clause of this select but before its fields should
- be transformed with transformer_for_where to make it pushable.
-
- Otherwise the method checks wherever any condition depending only on
- grouping fields can be extracted from cond. If there is any it prepares it
- for pushing using grouping_field_transformer_for_where and if it happens to
- be a conjunct of cond it removes it from cond. It saves the result of
- removal in remaining_cond.
- The extracted condition is saved in cond_pushed_into_where of this select.
-
- @note
- When looking for pushable condition the method considers only the grouping
- fields from the list grouping_tmp_fields whose elements are of the type
- Field_pair. This list must be prepared before the call of the
- function.
-
- @note
- This method is called for pushdown conditions into materialized
- derived tables/views optimization.
- Item::derived_field_transformer_for_where is passed as the actual
- callback function.
- Also it is called for pushdown conditions into materialized IN subqueries.
- Item::in_subq_field_transformer_for_where is passed as the actual
- callback function.
-*/
-
-void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond,
- Item **remaining_cond,
- Item_transformer transformer,
- uchar *arg)
-{
- if (!cond_pushdown_is_allowed())
- return;
- thd->lex->current_select= this;
- if (have_window_funcs())
- {
- Item *cond_over_partition_fields;
- check_cond_extraction_for_grouping_fields(cond);
- cond_over_partition_fields=
- build_cond_for_grouping_fields(thd, cond, true);
- if (cond_over_partition_fields)
- cond_over_partition_fields= cond_over_partition_fields->transform(thd,
- &Item::grouping_field_transformer_for_where,
- (uchar*) this);
- if (cond_over_partition_fields)
- {
- cond_over_partition_fields->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- cond_pushed_into_where= cond_over_partition_fields;
- }
-
- return;
- }
-
- if (!join->group_list && !with_sum_func)
- {
- cond=
- cond->transform(thd, transformer, arg);
- if (cond)
- {
- cond->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- cond_pushed_into_where= cond;
- }
-
- return;
- }
-
- /*
- Figure out what can be extracted from cond
- that could be pushed into the WHERE clause of this select
- */
- Item *cond_over_grouping_fields;
- check_cond_extraction_for_grouping_fields(cond);
- cond_over_grouping_fields=
- build_cond_for_grouping_fields(thd, cond, true);
-
- /*
- Transform the references to the columns from the cond
- pushed into the WHERE clause of this select to make them usable in
- the new context
- */
- if (cond_over_grouping_fields)
- cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
- &Item::grouping_field_transformer_for_where,
- (uchar*) this);
-
- if (cond_over_grouping_fields)
- {
-
- /*
- In cond remove top conjuncts that has been pushed into the WHERE
- clause of this select
- */
- cond= remove_pushed_top_conjuncts(thd, cond);
-
- cond_over_grouping_fields->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- cond_pushed_into_where= cond_over_grouping_fields;
- }
-
- *remaining_cond= cond;
-}
-
Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
Lex_ident_cli_st *cname, List<Item> *args)
{
@@ -9098,6 +9020,7 @@ bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit)
}
+
/**
Process tail of unit parsed in brackets
*/
@@ -9323,6 +9246,7 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit, char *place)
}
+
/**
Process INSERT-like select
*/
@@ -9587,3 +9511,687 @@ bool LEX::sp_proc_stmt_statement_finalize(THD *thd, bool no_lookahead)
lip->get_tok_start());
return LEX::sp_proc_stmt_statement_finalize_buf(thd, qbuf);
}
+
+
+/**
+ @brief
+ Extract from given item a condition pushable into WHERE clause
+
+ @param thd the thread handle
+ @param cond the item to extract a condition to be pushed
+ into WHERE
+ @param remaining_cond the condition that will remain of cond after
+ the pushdown of its parts into the WHERE clause
+ @param transformer the transformer callback function to be
+ applied to the condition so it can be pushed
+ down into the WHERE clause of this select
+ @param arg parameter to be passed to the transformer
+
+ @details
+ This method checks if cond entirely or its parts can be
+ pushed into the WHERE clause of this select and prepares it for pushing.
+
+ First it checks wherever this select doesn't have any aggregation function
+ in its projection and GROUP BY clause. If so cond can be entirely
+ pushed into the WHERE clause of this select but before its fields should
+ be transformed with transformer_for_where to make it pushable.
+
+ Otherwise the method checks wherever any condition depending only on
+ grouping fields can be extracted from cond. If there is any it prepares it
+ for pushing using grouping_field_transformer_for_where and if it happens to
+ be a conjunct of cond it removes it from cond. It saves the result of
+ removal in remaining_cond.
+ The extracted condition is saved in cond_pushed_into_where of this select.
+
+ @note
+ When looking for pushable condition the method considers only the grouping
+ fields from the list grouping_tmp_fields whose elements are of the type
+ Field_pair. This list must be prepared before the call of the
+ function.
+
+ @note
+ This method is called for pushdown conditions into materialized
+ derived tables/views optimization.
+ Item::derived_field_transformer_for_where is passed as the actual
+ callback function.
+ Also it is called for pushdown conditions into materialized IN subqueries.
+ Item::in_subq_field_transformer_for_where is passed as the actual
+ callback function.
+*/
+
+void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond,
+ Item **remaining_cond,
+ Item_transformer transformer,
+ uchar *arg)
+{
+ if (!cond_pushdown_is_allowed())
+ return;
+ thd->lex->current_select= this;
+ if (have_window_funcs())
+ {
+ Item *cond_over_partition_fields;
+ check_cond_extraction_for_grouping_fields(thd, cond,
+ &Item::dep_on_grouping_fields_checker);
+ cond_over_partition_fields=
+ build_cond_for_grouping_fields(thd, cond, true);
+ if (cond_over_partition_fields)
+ cond_over_partition_fields= cond_over_partition_fields->transform(thd,
+ &Item::grouping_field_transformer_for_where,
+ (uchar*) this);
+ if (cond_over_partition_fields)
+ {
+ cond_over_partition_fields->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond_over_partition_fields;
+ }
+
+ return;
+ }
+
+ if (!join->group_list && !with_sum_func)
+ {
+ cond=
+ cond->transform(thd, transformer, arg);
+ if (cond)
+ {
+ cond->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond;
+ }
+
+ return;
+ }
+
+ /*
+ Figure out what can be extracted from cond
+ that could be pushed into the WHERE clause of this select
+ */
+ Item *cond_over_grouping_fields;
+ check_cond_extraction_for_grouping_fields(thd, cond,
+ &Item::dep_on_grouping_fields_checker);
+ cond_over_grouping_fields=
+ build_cond_for_grouping_fields(thd, cond, true);
+
+ /*
+ Transform the references to the columns from the cond
+ pushed into the WHERE clause of this select to make them usable in
+ the new context
+ */
+ if (cond_over_grouping_fields)
+ cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
+ &Item::grouping_field_transformer_for_where,
+ (uchar*) this);
+
+ if (cond_over_grouping_fields)
+ {
+
+ /*
+ In cond remove top conjuncts that has been pushed into the WHERE
+ clause of this select
+ */
+ cond= remove_pushed_top_conjuncts(thd, cond);
+
+ cond_over_grouping_fields->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond_over_grouping_fields;
+ }
+
+ *remaining_cond= cond;
+}
+
+
+/**
+ @brief
+ Mark OR-conditions as non-pushable to avoid repeatable pushdown
+
+ @param cond The condition that should be marked (or its subformulas)
+
+ @details
+ In the case when OR-condition can be pushed into the HAVING clause
+ of the materialized derived table/view/IN subquery and some of
+ its parts can be pushed into the WHERE clause it can cause
+ repeatable pushdown in the pushdown from HAVING into WHERE clause.
+ Example:
+
+ SELECT *
+ FROM t1,
+ (
+ SELECT a,MAX(c) AS m_c
+ GROUP BY a
+ ) AS dt
+ WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND
+ (t1.a=v1.a);
+
+ after the pushdown into the materialized views/derived tables optimization
+ is done:
+
+ SELECT *
+ FROM t1,
+ (
+ SELECT a,MAX(c) AS m_c
+ WHERE (dt.a>2) OR (dt.a<3)
+ GROUP BY a
+ HAVING ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3))
+ ) AS dt
+ WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND
+ (t1.a=v1.a);
+
+ In the optimization stage for the select that defines derived table
+ in the pushdown from HAVING into WHERE optimization
+ (dt.a>2) OR (dt.a<3) will be again extracted from
+ ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3))
+ and pushed into the WHERE clause of the select that defines derived table.
+
+ To avoid it after conditions are pushed into the materialized derived
+ tables/views or IN subqueries OR-conditions that were pushed are marked
+ with NO_EXTRACTION_FL flag to avoid repeatable pushdown.
+*/
+
+void st_select_lex::mark_or_conds_to_avoid_pushdown(Item *cond)
+{
+ cond->walk(&Item::cleanup_excluding_const_fields_processor, 0, 0);
+
+ if (cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ if (item->type() == Item::COND_ITEM &&
+ ((Item_cond*) item)->functype() == Item_func::COND_OR_FUNC)
+ item->set_extraction_flag(NO_EXTRACTION_FL);
+ }
+ }
+ else if (cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
+ cond->set_extraction_flag(NO_EXTRACTION_FL);
+
+ cond_pushed_into_having= cond;
+}
+
+/**
+ @brief
+ Gets conditions that can be pushed down for pushdown from HAVING into WHERE
+
+ @param thd The thread handle
+ @param cond The condition from which the condition depended on grouping
+ fields is to be extracted
+ @param checker The checker callback function to be applied to the nodes
+ of the tree of the object
+
+ @details
+ The method finds out what conditions can be extracted from cond depended
+ only on the grouping fields of this SELECT or fields equal to them.
+ If the condition that can be pushed is AND-condition it is splitted out
+ and for each its element it is checked if it can be pushed.
+ Pushable elements are attached to the attach_to_conds list.
+ If the condition isn't AND-condition it is entirely pushed into
+ the attach_to_conds list. If the condition that is extracted is a multiple
+ equality it is transformed into the set of equalities.
+
+ attach_to_conds list is created to be passed to
+ and_new_conditions_to_optimized_cond() method so extracted conditions can
+ be joined to the already optimized WHERE clause in the right way.
+
+ @note
+ The method is similar to st_select_lex::build_cond_for_grouping_fields() and
+ Item::build_pushable_cond().
+
+ @retval
+ true - if an error occurs
+ false - otherwise
+*/
+
+bool
+st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd,
+ Item *cond,
+ Pushdown_checker checker)
+{
+ bool is_multiple_equality= cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC;
+
+ if (cond->get_extraction_flag() == NO_EXTRACTION_FL)
+ return false;
+
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool cond_and= false;
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ cond_and= true;
+ List<Item> equalities;
+ List<Item> new_conds;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+
+ while ((item=li++))
+ {
+ if (item->get_extraction_flag() == NO_EXTRACTION_FL)
+ continue;
+
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*) item)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ equalities.empty();
+ if (((Item_equal*) item)->create_pushable_equalities(thd, &equalities,
+ checker, (uchar *)this))
+ return true;
+ if (equalities.elements != 0)
+ {
+ if (cond_and)
+ new_conds.append(&equalities);
+ else
+ {
+ Item_cond_and *new_cond=
+ new (thd->mem_root) Item_cond_and(thd, equalities);
+ if (!new_cond || new_conds.push_back(new_cond, thd->mem_root))
+ return true;
+ }
+ }
+ else if (!cond_and)
+ return true;
+ continue;
+ }
+
+ Item *fix= item->build_pushable_cond(thd, checker, (uchar *)this);
+
+ if (!fix && !cond_and)
+ {
+ attach_to_conds.empty();
+ return false;
+ }
+ if (!fix)
+ continue;
+
+ if (new_conds.push_back(fix, thd->mem_root))
+ return true;
+ }
+ if (!cond_and)
+ {
+ Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd, new_conds);
+ if (attach_to_conds.push_back(new_cond, thd->mem_root))
+ return true;
+ }
+ else
+ attach_to_conds.append(&new_conds);
+ }
+ else if (is_multiple_equality)
+ {
+ List<Item> equalities;
+ Item_equal *item_equal= (Item_equal *)cond;
+ if (item_equal->create_pushable_equalities(thd, &equalities,
+ checker, (uchar *)this))
+ return true;
+ attach_to_conds.append(&equalities);
+ return false;
+ }
+ else if (cond->get_extraction_flag() != NO_EXTRACTION_FL)
+ {
+ Item *copy= cond->build_clone(thd);
+ if (attach_to_conds.push_back(copy, thd->mem_root))
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ Check if the item is equal to some field in Field_pair 'field_pair'
+ from 'pair_list' and return found 'field_pair' if it exists.
+*/
+
+Field_pair *get_corresponding_field_pair(Item *item,
+ List<Field_pair> pair_list)
+{
+ DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
+ (item->type() == Item::REF_ITEM &&
+ ((((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF) ||
+ (((Item_ref *) item)->ref_type() == Item_ref::REF))));
+
+ List_iterator<Field_pair> it(pair_list);
+ Field_pair *field_pair;
+ Item_field *field_item= (Item_field *) (item->real_item());
+ while ((field_pair= it++))
+ {
+ if (field_item->field == field_pair->field)
+ return field_pair;
+ }
+ return NULL;
+}
+
+
+/**
+ @brief
+ Find fields in WHERE clause multiple equalities that can be used in pushdown
+
+ @param thd The thread handle
+
+ @details
+ This method looks through the multiple equalities of the WHERE clause
+ trying to find any of them which fields are used in the GROUP BY of the
+ SELECT. If such multiple equality exists conditions in the HAVING
+ clause that use fields of this multiple equality can be pushed down
+ into the WHERE clause as well as the conditions depended on the fields
+ from the GROUP BY or fields equal to them that are taken from the HAVING
+ clause multiple equalities.
+
+ Example:
+
+ SELECT a,MAX(b),c
+ FROM t1
+ WHERE (t1.a=t1.c)
+ GROUP BY t1.a
+ HAVING (t1.c>1)
+
+ =>
+
+ SELECT a,MAX(b),c
+ FROM t1
+ WHERE (t1.a=t1.c) AND (t1.c>1)
+ GROUP BY t1.a
+
+ @retval
+ true - if an error occurs
+ false - otherwise
+*/
+
+bool st_select_lex::collect_fields_equal_to_grouping(THD *thd)
+{
+ if (!join->cond_equal || join->cond_equal->is_empty())
+ return false;
+
+ List_iterator_fast<Item_equal> li(join->cond_equal->current_level);
+ Item_equal *item_equal;
+
+ while ((item_equal= li++))
+ {
+ Item_equal_fields_iterator it(*item_equal);
+ Item *item;
+ while ((item= it++))
+ {
+ if (item->type() != Item::FIELD_ITEM &&
+ item->type() != Item::REF_ITEM)
+ continue;
+
+ if (get_corresponding_field_pair(item, grouping_tmp_fields))
+ break;
+ }
+ if (!item)
+ break;
+ it.rewind();
+
+ while ((item= it++))
+ {
+ if ((item->type() != Item::FIELD_ITEM &&
+ item->type() != Item::REF_ITEM) ||
+ get_corresponding_field_pair(item, grouping_tmp_fields))
+ continue;
+ Field_pair *grouping_tmp_field=
+ new Field_pair(((Item_field *)item->real_item())->field, item);
+ if (grouping_tmp_fields.push_back(grouping_tmp_field, thd->mem_root))
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ @brief
+ Cleanup and fix for the condition that is ready to be pushed down
+
+ @param thd The thread handle
+ @param cond The condition to be processed
+
+ @details
+ This method recursively traverses cond making cleanup and fix
+ where needed.
+ There is no need to make cleanup and fix for multiple equalities as
+ they are created so they can be immediately pushed down.
+
+ @retval
+ true - if an error occurs
+ false - otherwise
+*/
+
+static
+bool cleanup_inequalities_for_having_pushdown(THD *thd, Item *cond)
+{
+ if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+ return false;
+
+ if (cond->type() == Item::COND_ITEM)
+ {
+ List_iterator_fast<Item> it(*((Item_cond *)cond)->argument_list());
+ Item *item;
+
+ while ((item=it++))
+ cleanup_inequalities_for_having_pushdown(thd, item);
+ }
+ else
+ {
+ cond->walk(&Item::cleanup_excluding_const_fields_processor, 0, 0);
+ if (cond->fix_fields(thd, NULL))
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ @brief
+ Remove marked top conjuncts of condition for pushdown from HAVING into WHERE
+
+ @param thd The thread handle
+ @param cond The condition which subformulas are to be removed
+
+ @details
+ The function behavior is similar to remove_pushed_top_conjuncts()
+ except the case when 'cond' is the AND-condition.
+ As in the pushdown from HAVING into WHERE conditions are not just cloned
+ so they can be later pushed down as it is for pushdown into materialized
+ derived tables/views or IN subqueries, but also should be removed from
+ the HAVING clause there comes a problem with multiple equalities removal.
+ It is solved with the removal from multiple equalities list 'm_cond_equal'
+ of 'cond' conditions that are marked with the FULL_EXTRACTION_FLAG flag.
+
+ @retval
+ condition without removed subformulas
+ 0 if the whole 'cond' is removed
+*/
+
+Item *remove_pushed_top_conjuncts_for_having(THD *thd, Item *cond)
+{
+ if (cond->get_extraction_flag() == FULL_EXTRACTION_FL)
+ {
+ cond->clear_extraction_flag();
+ return 0;
+ }
+ if (cond->type() != Item::COND_ITEM)
+ return cond;
+
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ List<Item> *cond_arg_list= ((Item_cond_and *)cond)->argument_list();
+ List<Item_equal> *cond_equalities=
+ &((Item_cond_and*) cond)->m_cond_equal.current_level;
+ cond_arg_list->disjoin((List<Item> *) cond_equalities);
+ List_iterator<Item_equal> it(*cond_equalities);
+ Item_equal *eq_item;
+
+ if (((Item_cond_and*) cond)->m_cond_equal.work_references == 0)
+ {
+ while ((eq_item= it++))
+ {
+ if (eq_item->get_extraction_flag() == FULL_EXTRACTION_FL)
+ {
+ eq_item->clear_extraction_flag();
+ it.remove();
+ }
+ }
+ ((Item_cond_and*) cond)->m_cond_equal.clean_references();
+ }
+ else
+ {
+ while ((eq_item= it++))
+ eq_item->clear_extraction_flag();
+ ((Item_cond_and*) cond)->m_cond_equal.work_references=
+ ((Item_cond_and*) cond)->m_cond_equal.references;
+ }
+ cond_arg_list->append((List<Item> *) cond_equalities);
+ List_iterator<Item> li(*cond_arg_list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->get_extraction_flag() == FULL_EXTRACTION_FL)
+ {
+ item->clear_extraction_flag();
+ li.remove();
+ }
+ }
+ switch (cond_arg_list->elements)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return (cond_arg_list->head());
+ default:
+ return cond;
+ }
+ }
+ return cond;
+}
+
+
+/**
+ @brief
+ Extract condition that can be pushed from HAVING clause into WHERE clause
+
+ @param thd the thread handle
+ @param having the HAVING clause of this select
+ @param having_equal multiple equalities of HAVING
+
+ @details
+ This function builds the most restrictive condition depending only on
+ the fields used in the GROUP BY of this select (directly or indirectly
+ through equality) that can be extracted from the HAVING clause of this
+ select having and pushes it into the WHERE clause of this select.
+
+ Example of the transformation:
+
+ SELECT t1.a,MAX(t1.b)
+ FROM t1
+ GROUP BY t1.a
+ HAVING (t1.a>2) AND (MAX(c)>12);
+
+ =>
+
+ SELECT t1.a,MAX(t1.b)
+ FROM t1
+ WHERE (t1.a>2)
+ GROUP BY t1.a
+ HAVING (MAX(c)>12);
+
+ In details:
+ 1. Collect fields used in the GROUP BY grouping_fields of this SELECT
+ 2. Collect fields equal to grouping_fields from the WHERE clause
+ of this SELECT and attach them to the grouping_fields list.
+ 3. Search for the conditions in the HAVING clause of this select
+ that depends only on grouping_fields. Store them in the
+ attach_to_conds list.
+ 4. Remove pushable conditions from the HAVING clause having.
+
+ @note
+ This method is similar to st_select_lex::pushdown_cond_into_where_clause().
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
+*/
+
+Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having)
+{
+ if (!having || !group_list.first)
+ return having;
+ if (!cond_pushdown_is_allowed())
+ return having;
+
+ st_select_lex *save_curr_select= thd->lex->current_select;
+ thd->lex->current_select= this;
+
+ /*
+ 1. Collect fields used in the GROUP BY grouping_fields of this SELECT
+ 2. Collect fields equal to grouping_fields from the WHERE clause
+ of this SELECT and attach them to the grouping_fields list.
+ */
+ if (have_window_funcs())
+ {
+ if (group_list.first || join->implicit_grouping)
+ return having;
+ ORDER *common_partition_fields=
+ find_common_window_func_partition_fields(thd);
+ if (!common_partition_fields ||
+ collect_grouping_fields(thd) ||
+ collect_fields_equal_to_grouping(thd))
+ return having;
+ }
+ else if (collect_grouping_fields(thd) ||
+ collect_fields_equal_to_grouping(thd))
+ return having;
+
+ /*
+ 3. Search for the conditions in the HAVING clause of this select
+ that depends only on grouping_fields. Store them in the
+ attach_to_conds list.
+ */
+ thd->having_pushdown= true;
+ List_iterator_fast<Item> it(attach_to_conds);
+ Item *item;
+ check_cond_extraction_for_grouping_fields(thd, having,
+ &Item::dep_on_grouping_fields_checker_for_having_pushdown);
+ if (build_pushable_cond_for_having_pushdown(thd, having,
+ &Item::pushable_equality_checker_for_having_pushdown))
+ {
+ attach_to_conds.empty();
+ goto exit;
+ }
+ if (attach_to_conds.elements != 0)
+ {
+ /*
+ 4. Remove pushable conditions from the HAVING clause having.
+ */
+ having= remove_pushed_top_conjuncts_for_having(thd, having);
+
+ it.rewind();
+ while ((item=it++))
+ {
+ if (cleanup_inequalities_for_having_pushdown(thd, item))
+ {
+ attach_to_conds.empty();
+ goto exit;
+ }
+ }
+ /*
+ Refresh having_equal as some of the multiple equalities of
+ having can be removed after pushdown.
+ */
+ join->having_equal= 0;
+ if (having)
+ {
+ if (having->type() == Item::COND_ITEM &&
+ ((Item_cond*) having)->functype() == Item_func::COND_AND_FUNC)
+ {
+ Item_cond_and *and_having= (Item_cond_and *)having;
+ join->having_equal= &and_having->m_cond_equal;
+ }
+ if (having->type() == Item::FUNC_ITEM &&
+ ((Item_func*) having)->functype() == Item_func::MULT_EQUAL_FUNC)
+ join->having_equal= new (thd->mem_root) COND_EQUAL((Item_equal *)having,
+ thd->mem_root);
+ }
+ }
+exit:
+ thd->lex->current_select= save_curr_select;
+ thd->having_pushdown= false;
+ return having;
+}
+
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3f3fef8..93aa714 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -999,10 +999,11 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT;
typedef Bounds_checked_array<Item*> Ref_ptr_array;
-/*
+/**
Structure which consists of the field and the item that
corresponds to this field.
*/
+
class Field_pair :public Sql_alloc
{
public:
@@ -1012,6 +1013,10 @@ class Field_pair :public Sql_alloc
:field(fld), corresponding_item(item) {}
};
+Field_pair *get_corresponding_field_pair(Item *item,
+ List<Field_pair> pair_list);
+Field_pair *find_matching_field_pair(Item *item, List<Field_pair> pair_list);
+
/*
SELECT_LEX - store information of parsed SELECT statment
@@ -1043,6 +1048,7 @@ class st_select_lex: public st_select_lex_node
Item *prep_having;/* saved HAVING clause for prepared statement processing */
Item *cond_pushed_into_where; /* condition pushed into the select's WHERE */
Item *cond_pushed_into_having; /* condition pushed into the select's HAVING */
+ List<Item> attach_to_conds;
/* Saved values of the WHERE and HAVING clauses*/
Item::cond_result cond_value, having_value;
/*
@@ -1467,8 +1473,11 @@ class st_select_lex: public st_select_lex_node
With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
bool check_unrestricted_recursive(bool only_standard_compliant);
bool check_subqueries_with_recursive_references();
- void collect_grouping_fields(THD *thd, ORDER *grouping_list);
- void check_cond_extraction_for_grouping_fields(Item *cond);
+ void collect_grouping_fields_for_derived(THD *thd, ORDER *grouping_list);
+ bool collect_grouping_fields(THD *thd);
+ bool collect_fields_equal_to_grouping(THD *thd);
+ void check_cond_extraction_for_grouping_fields(THD *thd, Item *cond,
+ Pushdown_checker excl_dep);
Item *build_cond_for_grouping_fields(THD *thd, Item *cond,
bool no_to_clones);
@@ -1494,10 +1503,15 @@ class st_select_lex: public st_select_lex_node
bool cond_pushdown_is_allowed() const
{ return !olap && !explicit_limit && !tvc; }
+ bool build_pushable_cond_for_having_pushdown(THD *thd,
+ Item *cond,
+ Pushdown_checker checker);
void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond,
Item **remaining_cond,
Item_transformer transformer,
uchar *arg);
+ void mark_or_conds_to_avoid_pushdown(Item *cond);
+ Item *pushdown_from_having_into_where(THD *thd, Item *having);
select_handler *find_select_handler(THD *thd);
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 00d1616..68603c4 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -234,7 +234,7 @@
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32)
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 33)
-
+#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING_INTO_WHERE (1ULL << 33)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -263,7 +263,8 @@
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
OPTIMIZER_SWITCH_SPLIT_MATERIALIZED | \
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY |\
- OPTIMIZER_SWITCH_USE_ROWID_FILTER)
+ OPTIMIZER_SWITCH_USE_ROWID_FILTER | \
+ OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING_INTO_WHERE)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3670eff..3d1b530 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1870,10 +1870,10 @@ JOIN::optimize_inner()
select_lex->having_fix_field_for_pushed_cond= 0;
}
}
-
+
conds= optimize_cond(this, conds, join_list, FALSE,
&cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS);
-
+
if (thd->is_error())
{
error= 1;
@@ -1881,6 +1881,33 @@ JOIN::optimize_inner()
DBUG_RETURN(1);
}
+ having= optimize_cond(this, having, join_list, TRUE,
+ &having_value, &having_equal);
+
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from optimize_cond"));
+ DBUG_RETURN(1);
+ }
+
+ if (thd->lex->sql_command == SQLCOM_SELECT &&
+ optimizer_flag(thd,
+ OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING_INTO_WHERE))
+ {
+ having=
+ select_lex->pushdown_from_having_into_where(thd, having);
+ if (select_lex->attach_to_conds.elements != 0)
+ {
+ conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
+ select_lex->attach_to_conds,
+ &cond_value, true);
+ if (conds && !conds->is_fixed() && conds->fix_fields(thd, &conds))
+ DBUG_RETURN(1);
+ sel->attach_to_conds.empty();
+ }
+ }
+
if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY))
{
TABLE_LIST *tbl;
@@ -1899,13 +1926,48 @@ JOIN::optimize_inner()
if (eq_list.elements != 0)
{
conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
- eq_list, &cond_value);
+ eq_list, &cond_value, false);
if (!conds &&
cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE)
DBUG_RETURN(TRUE);
}
+ {
+ if (select_lex->where)
+ {
+ select_lex->cond_value= cond_value;
+ if (sel->where != conds && cond_value == Item::COND_OK)
+ thd->change_item_tree(&sel->where, conds);
+ }
+ if (select_lex->having)
+ {
+ select_lex->having_value= having_value;
+ if (sel->having != having && having_value == Item::COND_OK)
+ thd->change_item_tree(&sel->having, having);
+ }
+ if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
+ (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
+ { /* Impossible cond */
+ if (unit->select_limit_cnt)
+ {
+ DBUG_PRINT("info", (having_value == Item::COND_FALSE ?
+ "Impossible HAVING" : "Impossible WHERE"));
+ zero_result_cause= having_value == Item::COND_FALSE ?
+ "Impossible HAVING" : "Impossible WHERE";
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Zero limit"));
+ zero_result_cause= "Zero limit";
+ }
+ table_count= top_join_tab_count= 0;
+ error= 0;
+ subq_exit_fl= true;
+ goto setup_subq_exit;
+ }
+ }
+
if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
{
TABLE_LIST *tbl;
@@ -1944,50 +2006,6 @@ JOIN::optimize_inner()
DBUG_RETURN(1);
}
- {
- having= optimize_cond(this, having, join_list, TRUE,
- &having_value, &having_equal);
-
- if (unlikely(thd->is_error()))
- {
- error= 1;
- DBUG_PRINT("error",("Error from optimize_cond"));
- DBUG_RETURN(1);
- }
- if (select_lex->where)
- {
- select_lex->cond_value= cond_value;
- if (sel->where != conds && cond_value == Item::COND_OK)
- thd->change_item_tree(&sel->where, conds);
- }
- if (select_lex->having)
- {
- select_lex->having_value= having_value;
- if (sel->having != having && having_value == Item::COND_OK)
- thd->change_item_tree(&sel->having, having);
- }
- if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
- (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
- { /* Impossible cond */
- if (unit->select_limit_cnt)
- {
- DBUG_PRINT("info", (having_value == Item::COND_FALSE ?
- "Impossible HAVING" : "Impossible WHERE"));
- zero_result_cause= having_value == Item::COND_FALSE ?
- "Impossible HAVING" : "Impossible WHERE";
- }
- else
- {
- DBUG_PRINT("info", ("Zero limit"));
- zero_result_cause= "Zero limit";
- }
- table_count= top_join_tab_count= 0;
- error= 0;
- subq_exit_fl= true;
- goto setup_subq_exit;
- }
- }
-
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
TABLE_LIST *tbl;
@@ -2263,6 +2281,22 @@ int JOIN::optimize_stage2()
"after substitute_best_equal",
QT_ORDINARY););
}
+ if (having)
+ {
+ having= substitute_for_best_equal_field(thd, NO_PARTICULAR_TAB, having,
+ having_equal, map2table);
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+ DBUG_RETURN(1);
+ }
+ having->update_used_tables();
+ DBUG_EXECUTE("having",
+ print_where(having,
+ "after substitute_best_equal",
+ QT_ORDINARY););
+ }
/*
Perform the optimization on fields evaluation mentioned above
@@ -5177,7 +5211,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
{
if (*s->on_expr_ref && s->cond_equal &&
s->cond_equal->upper_levels == orig_cond_equal)
+ {
s->cond_equal->upper_levels= join->cond_equal;
+ if (s->cond_equal->upper_levels)
+ s->cond_equal->upper_levels->references++;
+ }
}
}
}
@@ -14171,14 +14209,16 @@ bool check_simple_equality(THD *thd, const Item::Context &ctx,
Item *orig_left_item= left_item;
Item *orig_right_item= right_item;
if (left_item->type() == Item::REF_ITEM &&
- ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
+ (((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF ||
+ ((Item_ref*)left_item)->ref_type() == Item_ref::REF))
{
if (((Item_ref*)left_item)->get_depended_from())
return FALSE;
left_item= left_item->real_item();
}
if (right_item->type() == Item::REF_ITEM &&
- ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
+ (((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF ||
+ ((Item_ref*)right_item)->ref_type() == Item_ref::REF))
{
if (((Item_ref*)right_item)->get_depended_from())
return FALSE;
@@ -14736,6 +14776,8 @@ COND *Item_func_eq::build_equal_items(THD *thd,
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->n_field_items());
item_equal->upper_levels= inherited;
+ if (inherited)
+ inherited->increase_references();
if (cond_equal_ref)
*cond_equal_ref= new (thd->mem_root) COND_EQUAL(item_equal,
thd->mem_root);
@@ -14770,6 +14812,8 @@ COND *Item_func_eq::build_equal_items(THD *thd,
and_cond->update_used_tables();
if (cond_equal_ref)
*cond_equal_ref= &and_cond->m_cond_equal;
+ if (inherited)
+ inherited->increase_references();
return and_cond;
}
}
@@ -14895,6 +14939,8 @@ static COND *build_equal_items(JOIN *join, COND *cond,
if (*cond_equal_ref)
{
(*cond_equal_ref)->upper_levels= inherited;
+ if (inherited)
+ inherited->increase_references();
inherited= *cond_equal_ref;
}
}
@@ -15227,11 +15273,8 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
*/
Item *head_item= (!item_const && current_sjm &&
current_sjm_head != field_item) ? current_sjm_head: head;
- Item *head_real_item= head_item->real_item();
- if (head_real_item->type() == Item::FIELD_ITEM)
- head_item= head_real_item;
-
- eq_item= new (thd->mem_root) Item_func_eq(thd, field_item->real_item(), head_item);
+
+ eq_item= new (thd->mem_root) Item_func_eq(thd, field_item, head_item);
if (!eq_item || eq_item->set_cmp_func())
return 0;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 01daf97..3bb2710 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -225,6 +225,11 @@ Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab);
int rr_sequential(READ_RECORD *info);
int rr_sequential_and_unpack(READ_RECORD *info);
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
+Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
+ COND_EQUAL **cond_eq,
+ List<Item> &new_conds,
+ Item::cond_result *cond_value,
+ bool build_cond_equal);
#include "sql_explain.h"
@@ -1779,7 +1784,6 @@ class JOIN :public Sql_alloc
bool fix_all_splittings_in_plan();
bool transform_in_predicates_into_in_subq(THD *thd);
- bool add_equalities_to_where_condition(THD *thd, List<Item> &eq_list);
private:
/**
Create a temporary table to be used for processing DISTINCT/ORDER
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 7343c6e..3ce6ff6 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2522,6 +2522,7 @@ export const char *optimizer_switch_names[]=
"split_materialized",
"condition_pushdown_for_subquery",
"rowid_filter",
+ "condition_pushdown_from_having_into_where",
"default",
NullS
};
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
index 55a2cc4..1e1c4d3 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=innodb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
index 1b5998b..a9e843d 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=tokudb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
index 0bba5b7..9b48f6c 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=innodb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
index 556c5ff..b179e5c 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@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,rowid_filter=on
+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,rowid_filter=on,condition_pushdown_from_having_into_where=off
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=tokudb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;
1
0
[Commits] 8fa609b: MDEV-7974 backport fix for mysql bug#12161 (XA and binlog).
by holyfoot@askmonty.org 17 Feb '19
by holyfoot@askmonty.org 17 Feb '19
17 Feb '19
revision-id: 8fa609b4f2525dce0fad79a5842caa4174aeb0d5 (mariadb-10.4.1-103-g8fa609b)
parent(s): 8aae31cf494678b6253031c627566e50bc666920
committer: Alexey Botchkov
timestamp: 2019-02-18 02:36:19 +0400
message:
MDEV-7974 backport fix for mysql bug#12161 (XA and binlog).
XA transactions now are kept persistent after prepare.
XA_prepare_log_event implamented, and XA tranasctions are logged
as XA transactions.
---
mysql-test/suite/rpl/r/rpl_xa.result | 31 +++
mysql-test/suite/rpl/t/rpl_xa.test | 26 ++
sql/handler.cc | 9 +
sql/handler.h | 10 +
sql/log.cc | 115 ++++++--
sql/log.h | 10 +
sql/log_event.cc | 502 +++++++++++++++++++++++++++++------
sql/log_event.h | 116 +++++++-
sql/sql_class.cc | 18 +-
sql/sql_class.h | 20 +-
sql/sql_connect.cc | 1 +
sql/transaction.cc | 89 ++++++-
sql/transaction.h | 1 +
13 files changed, 826 insertions(+), 122 deletions(-)
diff --git a/mysql-test/suite/rpl/r/rpl_xa.result b/mysql-test/suite/rpl/r/rpl_xa.result
new file mode 100644
index 0000000..58c1b09
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa.result
@@ -0,0 +1,31 @@
+include/master-slave.inc
+[connection master]
+create table t1 (a int, b int) engine=InnoDB;
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+select * from t1;
+a b
+1 2
+connection slave;
+select * from t1;
+a b
+1 2
+connection master;
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+select * from t1;
+a b
+1 2
+connection slave;
+select * from t1;
+a b
+1 2
+connection master;
+drop table t1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa.test b/mysql-test/suite/rpl/t/rpl_xa.test
new file mode 100644
index 0000000..f93d787
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa.test
@@ -0,0 +1,26 @@
+source include/have_innodb.inc;
+source include/master-slave.inc;
+
+create table t1 (a int, b int) engine=InnoDB;
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+select * from t1;
+sync_slave_with_master;
+select * from t1;
+connection master;
+
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+select * from t1;
+sync_slave_with_master;
+select * from t1;
+
+connection master;
+drop table t1;
+source include/rpl_end.inc;
diff --git a/sql/handler.cc b/sql/handler.cc
index 001055c..3b2a3e0 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1214,6 +1214,9 @@ static int prepare_or_error(handlerton *ht, THD *thd, bool all)
}
+/*static inline */int
+binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
+ bool all, my_xid xid);
/**
@retval
0 ok
@@ -1225,6 +1228,7 @@ int ha_prepare(THD *thd)
int error=0, all=1;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list;
+
DBUG_ENTER("ha_prepare");
if (ha_info)
@@ -1250,6 +1254,11 @@ int ha_prepare(THD *thd)
}
}
+ if (unlikely(tc_log->log_prepare(thd, all)))
+ {
+ ha_rollback_trans(thd, all);
+ error=1;
+ }
}
DBUG_RETURN(error);
diff --git a/sql/handler.h b/sql/handler.h
index fc6246c..613c1c3 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -810,6 +810,16 @@ struct xid_t {
long gtrid_length;
long bqual_length;
char data[XIDDATASIZE]; // not \0-terminated !
+ /*
+ The size of the string containing serialized Xid representation
+ is computed as a sum of
+ eight as the number of formatting symbols (X'',X'',)
+ plus 2 x XIDDATASIZE (2 due to hex format),
+ plus space for decimal digits of XID::formatID,
+ plus one for 0x0.
+ */
+ static const uint ser_buf_size=
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(long) + 1;
xid_t() {} /* Remove gcc warning */
bool eq(struct xid_t *xid)
diff --git a/sql/log.cc b/sql/log.cc
index a56117a..316b871 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -87,6 +87,9 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_xa_recover(handlerton *hton, XID *xid_list, uint len);
+static int binlog_commit_by_xid(handlerton *hton, XID *xid);
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid);
static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
static const LEX_CSTRING write_error_msg=
@@ -1688,6 +1691,9 @@ int binlog_init(void *p)
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
binlog_hton->prepare= binlog_prepare;
+ binlog_hton->recover= binlog_xa_recover;
+ binlog_hton->commit_by_xid = binlog_commit_by_xid;
+ binlog_hton->rollback_by_xid = binlog_rollback_by_xid;
binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
@@ -1883,23 +1889,16 @@ static inline int
binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
bool all, my_xid xid)
{
- if (xid)
- {
- Xid_log_event end_evt(thd, xid, TRUE);
- return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
- }
- else
+ /* Mask XA COMMIT ... ONE PHASE as plain BEGIN ... COMMIT */
+ if (!xid)
{
- /*
- Empty xid occurs in XA COMMIT ... ONE PHASE.
- In this case, we do not have a MySQL xid for the transaction, and the
- external XA transaction coordinator will have to handle recovery if
- needed. So we end the transaction with a plain COMMIT query event.
- */
- Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
- TRUE, TRUE, TRUE, 0);
- return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
+ DBUG_ASSERT(thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt == XA_ONE_PHASE);
+ xid= thd->query_id;
}
+
+ Xid_log_event end_evt(thd, xid, TRUE);
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
}
/**
@@ -1961,11 +1960,77 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
do nothing.
just pretend we can do 2pc, so that MySQL won't
switch to 1pc.
- real work will be done in MYSQL_BIN_LOG::log_and_order()
+ real work is done in MYSQL_BIN_LOG::log_and_order()
*/
return 0;
}
+
+static int serialize_xid(XID *xid, char *buf)
+{
+ size_t size;
+ buf[0]= '\'';
+ memcpy(buf+1, xid->data, xid->gtrid_length);
+ size= xid->gtrid_length + 2;
+ buf[size-1]= '\'';
+ if (xid->bqual_length == 0 && xid->formatID == 1)
+ return size;
+
+ memcpy(buf+size, ", '", 3);
+ memcpy(buf+size+3, xid->data+xid->gtrid_length, xid->bqual_length);
+ size+= 3 + xid->bqual_length;
+ buf[size]= '\'';
+ size++;
+ if (xid->formatID != 1)
+ size+= sprintf(buf+size, ", %ld", xid->formatID);
+ return size;
+}
+
+
+static int binlog_xa_recover(handlerton *hton __attribute__((unused)),
+ XID *xid_list __attribute__((unused)),
+ uint len __attribute__((unused)))
+{
+ /* Does nothing. */
+ return 0;
+}
+
+
+static int binlog_commit_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xc_len= sizeof("XA COMMIT ") - 1; // do not count trailing 0
+ char buf[xc_len + xid_t::ser_buf_size];
+ size_t buflen;
+ binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data();
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT);
+
+ if (!cache_mngr)
+ return 1;
+
+ memcpy(buf, "XA COMMIT ", xc_len);
+ buflen= xc_len + serialize_xid(xid, buf+xc_len);
+ Query_log_event qe(thd, buf, buflen, TRUE, FALSE, FALSE, 0);
+ return binlog_flush_cache(thd, cache_mngr, &qe, TRUE, TRUE, TRUE);
+}
+
+
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xr_len= sizeof("XA ROLLBACK ") - 1; // do not count trailing 0
+ char buf[xr_len + xid_t::ser_buf_size];
+ size_t buflen;
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
+ memcpy(buf, "XA ROLLBACK ", xr_len);
+ buflen= xr_len + serialize_xid(xid, buf+xr_len);
+ Query_log_event qe(thd, buf, buflen, FALSE, TRUE, TRUE, 0);
+ return mysql_bin_log.write_event(&qe);
+}
+
+
/*
We flush the cache wrapped in a beging/rollback if:
. aborting a single or multi-statement transaction and;
@@ -9809,6 +9874,24 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
DBUG_RETURN(BINLOG_COOKIE_GET_ERROR_FLAG(cookie));
}
+
+int TC_LOG_BINLOG::log_prepare(THD *thd, bool all)
+{
+ XID *xid= &thd->transaction.xid_state.xid;
+ XA_prepare_log_event end_evt(thd, xid, FALSE);
+ binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data();
+
+ if (!cache_mngr)
+ {
+ WSREP_DEBUG("Skipping empty log_xid: %s", thd->query());
+ return 0;
+ }
+
+ cache_mngr->using_xa= FALSE;
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
+}
+
+
void
TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
{
diff --git a/sql/log.h b/sql/log.h
index 7dfdb36..92fdf95 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -61,6 +61,7 @@ class TC_LOG
bool need_prepare_ordered,
bool need_commit_ordered) = 0;
virtual int unlog(ulong cookie, my_xid xid)=0;
+ virtual int log_prepare(THD *thd, bool all)= 0;
virtual void commit_checkpoint_notify(void *cookie)= 0;
protected:
@@ -115,6 +116,10 @@ class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
return 1;
}
int unlog(ulong cookie, my_xid xid) { return 0; }
+ int log_prepare(THD *thd, bool all)
+ {
+ return 0;
+ }
void commit_checkpoint_notify(void *cookie) { DBUG_ASSERT(0); };
};
@@ -198,6 +203,10 @@ class TC_LOG_MMAP: public TC_LOG
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered);
int unlog(ulong cookie, my_xid xid);
+ int log_prepare(THD *thd, bool all)
+ {
+ return 0;
+ }
void commit_checkpoint_notify(void *cookie);
int recover();
@@ -698,6 +707,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered);
int unlog(ulong cookie, my_xid xid);
+ int log_prepare(THD *thd, bool all);
void commit_checkpoint_notify(void *cookie);
int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
Format_description_log_event *fdle, bool do_xa);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7a0d0be..486f8f5 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2139,6 +2139,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case XID_EVENT:
ev = new Xid_log_event(buf, fdle);
break;
+ case XA_PREPARE_LOG_EVENT:
+ ev = new XA_prepare_log_event(buf, fdle);
+ break;
case RAND_EVENT:
ev = new Rand_log_event(buf, fdle);
break;
@@ -2190,7 +2193,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case PREVIOUS_GTIDS_LOG_EVENT:
case TRANSACTION_CONTEXT_EVENT:
case VIEW_CHANGE_EVENT:
- case XA_PREPARE_LOG_EVENT:
ev= new Ignorable_log_event(buf, fdle,
get_type_str((Log_event_type) event_type));
break;
@@ -4418,6 +4420,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t que
case SQLCOM_RELEASE_SAVEPOINT:
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
case SQLCOM_SAVEPOINT:
+ case SQLCOM_XA_END:
use_cache= trx_cache= TRUE;
break;
default:
@@ -6222,6 +6225,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[USER_VAR_EVENT-1]= USER_VAR_HEADER_LEN;
post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
post_header_len[XID_EVENT-1]= XID_HEADER_LEN;
+ post_header_len[XA_PREPARE_LOG_EVENT-1]= XA_PREPARE_HEADER_LEN;
post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= BEGIN_LOAD_QUERY_HEADER_LEN;
post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
/*
@@ -7874,7 +7878,7 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
buf+= 8;
domain_id= uint4korr(buf);
buf+= 4;
- flags2= *buf;
+ flags2= *(buf++);
if (flags2 & FL_GROUP_COMMIT_ID)
{
if (event_len < (uint)header_size + GTID_HEADER_LEN + 2)
@@ -7882,8 +7886,22 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
seq_no= 0; // So is_valid() returns false
return;
}
- ++buf;
commit_id= uint8korr(buf);
+ buf+= 8;
+ }
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ xid.formatID= (long) buf[0];
+ xid.gtrid_length= (long) buf[1];
+ xid.bqual_length= (long) buf[2];
+
+ buf+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(xid.data, buf, data_length);
+ buf+= data_length;
+ }
}
}
@@ -7914,6 +7932,12 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
/* Preserve any DDL or WAITED flag in the slave's binlog. */
if (thd_arg->rgi_slave)
flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt != XA_ONE_PHASE)
+ {
+ flags2|= FL_XA_TRANSACTION;
+ xid= thd->transaction.xid_state.xid;
+ }
}
@@ -7956,7 +7980,7 @@ Gtid_log_event::peek(const char *event_start, size_t event_len,
bool
Gtid_log_event::write()
{
- uchar buf[GTID_HEADER_LEN+2];
+ uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
size_t write_len;
int8store(buf, seq_no);
@@ -7968,8 +7992,25 @@ Gtid_log_event::write()
write_len= GTID_HEADER_LEN + 2;
}
else
+ write_len= 13;
+
+ if (flags2 & FL_XA_TRANSACTION)
{
- bzero(buf+13, GTID_HEADER_LEN-13);
+ buf[write_len]= (uchar) ((char) xid.formatID);
+ buf[write_len+1]= (uchar) xid.gtrid_length;
+ buf[write_len+2]= (uchar) xid.bqual_length;
+ write_len+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(buf+write_len, xid.data, data_length);
+ write_len+= data_length;
+ }
+ }
+
+ if (write_len < GTID_HEADER_LEN)
+ {
+ bzero(buf+write_len, GTID_HEADER_LEN-write_len);
write_len= GTID_HEADER_LEN;
}
return write_header(write_len) ||
@@ -8012,7 +8053,7 @@ Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
void
Gtid_log_event::pack_info(Protocol *protocol)
{
- char buf[6+5+10+1+10+1+20+1+4+20+1];
+ char buf[6+5+10+1+10+1+20+1+4+20+1+5+128];
char *p;
p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
p= longlong10_to_str(domain_id, p, 10);
@@ -8026,6 +8067,12 @@ Gtid_log_event::pack_info(Protocol *protocol)
p= longlong10_to_str(commit_id, p, 10);
}
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ p= strmov(p, " XID :");
+ p= strnmov(p, xid.data, xid.bqual_length + xid.gtrid_length);
+ }
+
protocol->store(buf, p-buf, &my_charset_bin);
}
@@ -8079,11 +8126,25 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi)
thd->lex->sql_command= SQLCOM_BEGIN;
thd->is_slave_error= 0;
status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
- if (trans_begin(thd, 0))
+ if (flags2 & FL_XA_TRANSACTION)
{
- DBUG_PRINT("error", ("trans_begin() failed"));
- thd->is_slave_error= 1;
+ thd->lex->xid= &xid;
+ thd->lex->xa_opt= XA_NONE;
+ if (trans_xa_start(thd))
+ {
+ DBUG_PRINT("error", ("trans_xa_start() failed"));
+ thd->is_slave_error= 1;
+ }
+ }
+ else
+ {
+ if (trans_begin(thd, 0))
+ {
+ DBUG_PRINT("error", ("trans_begin() failed"));
+ thd->is_slave_error= 1;
+ }
}
+
thd->update_stats();
if (likely(!thd->is_slave_error))
@@ -8202,9 +8263,29 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
buf, print_event_info->delimiter))
goto err;
}
- if (!(flags2 & FL_STANDALONE))
- if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+ if ((flags2 & FL_XA_TRANSACTION) && !is_flashback)
+ {
+ my_b_write_string(&cache, "XA START '");
+ my_b_write(&cache, (uchar *) xid.data, xid.gtrid_length);
+ my_b_write_string(&cache, "'");
+ if (xid.bqual_length > 0 || xid.formatID != 1)
+ {
+ my_b_write_string(&cache, ", '");
+ my_b_write(&cache, (uchar *) xid.data+xid.gtrid_length, xid.bqual_length);
+ my_b_write_string(&cache, "'");
+ if (xid.formatID != 1)
+ if (my_b_printf(&cache, ", %d", xid.formatID))
+ goto err;
+ }
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
goto err;
+ }
+ else if (!(flags2 & FL_STANDALONE))
+ {
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n",
+ print_event_info->delimiter))
+ goto err;
+ }
return cache.flush_data();
err:
@@ -8825,80 +8906,20 @@ bool slave_execute_deferred_events(THD *thd)
/**************************************************************************
- Xid_log_event methods
+ Xid_apply_log_event methods
**************************************************************************/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Xid_log_event::pack_info(Protocol *protocol)
-{
- char buf[128], *pos;
- pos= strmov(buf, "COMMIT /* xid=");
- pos= longlong10_to_str(xid, pos, 10);
- pos= strmov(pos, " */");
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
-/**
- @note
- It's ok not to use int8store here,
- as long as xid_t::set(ulonglong) and
- xid_t::get_my_xid doesn't do it either.
- We don't care about actual values of xids as long as
- identical numbers compare identically
-*/
-Xid_log_event::
-Xid_log_event(const char* buf,
- const Format_description_log_event *description_event)
- :Log_event(buf, description_event)
+int Xid_apply_log_event::record_gtid(const rpl_gtid *gtid, uint64 sub_id,
+ void **out_hton)
{
- /* The Post-Header is empty. The Variable Data part begins immediately. */
- buf+= description_event->common_header_len +
- description_event->post_header_len[XID_EVENT-1];
- memcpy((char*) &xid, buf, sizeof(xid));
+ return rpl_global_gtid_slave_state->record_gtid(thd, gtid, sub_id, true,
+ false, out_hton);
}
-#ifndef MYSQL_CLIENT
-bool Xid_log_event::write()
-{
- DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
- return write_header(sizeof(xid)) ||
- write_data((uchar*)&xid, sizeof(xid)) ||
- write_footer();
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
-
- if (!print_event_info->short_form)
- {
- char buf[64];
- longlong10_to_str(xid, buf, 10);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tXid = %s\n", buf))
- goto err;
- }
- if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
- print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Xid_log_event::do_apply_event(rpl_group_info *rgi)
+int Xid_apply_log_event::do_apply_event(rpl_group_info *rgi)
{
bool res;
int err;
@@ -8929,8 +8950,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
rgi->gtid_pending= false;
gtid= rgi->current_gtid;
- err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true,
- false, &hton);
+ err= record_gtid(>id, sub_id, &hton);
if (unlikely(err))
{
int ec= thd->get_stmt_da()->sql_errno();
@@ -8959,8 +8979,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
general_log_print(thd, COM_QUERY,
"COMMIT /* implicit, from Xid_log_event */");
thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- res= trans_commit(thd); /* Automatically rolls back on error. */
- thd->mdl_context.release_transactional_locks();
+ res= do_commit();
if (likely(!res) && sub_id)
rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi);
@@ -8973,10 +8992,11 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
return res;
}
+
Log_event::enum_skip_reason
-Xid_log_event::do_shall_skip(rpl_group_info *rgi)
+Xid_apply_log_event::do_shall_skip(rpl_group_info *rgi)
{
- DBUG_ENTER("Xid_log_event::do_shall_skip");
+ DBUG_ENTER("Xid_apply_log_event::do_shall_skip");
if (rgi->rli->slave_skip_counter > 0)
{
DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
@@ -9000,6 +9020,321 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi)
#endif
DBUG_RETURN(Log_event::do_shall_skip(rgi));
}
+
+#endif /*MYSQL_SERVER*/
+
+
+/**************************************************************************
+ Xid_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Xid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[128], *pos;
+ pos= strmov(buf, "COMMIT /* xid=");
+ pos= longlong10_to_str(xid, pos, 10);
+ pos= strmov(pos, " */");
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+/**
+ @note
+ It's ok not to use int8store here,
+ as long as xid_t::set(ulonglong) and
+ xid_t::get_my_xid doesn't do it either.
+ We don't care about actual values of xids as long as
+ identical numbers compare identically
+*/
+
+Xid_log_event::
+Xid_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Xid_apply_log_event(buf, description_event)
+{
+ /* The Post-Header is empty. The Variable Data part begins immediately. */
+ buf+= description_event->common_header_len +
+ description_event->post_header_len[XID_EVENT-1];
+ memcpy((char*) &xid, buf, sizeof(xid));
+}
+
+
+#ifndef MYSQL_CLIENT
+bool Xid_log_event::write()
+{
+ DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
+ return write_header(sizeof(xid)) ||
+ write_data((uchar*)&xid, sizeof(xid)) ||
+ write_footer();
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+
+ if (!print_event_info->short_form)
+ {
+ char buf[64];
+ longlong10_to_str(xid, buf, 10);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tXid = %s\n", buf))
+ goto err;
+ }
+ if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+#endif /* MYSQL_CLIENT */
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Xid_log_event::do_commit()
+{
+ bool res;
+ res= trans_commit(thd); /* Automatically rolls back on error. */
+ thd->mdl_context.release_transactional_locks();
+ return res;
+}
+#endif /* !MYSQL_CLIENT */
+
+
+#ifdef TODO7974
+/**
+ Function serializes XID which is characterized by by four last arguments
+ of the function.
+ Serialized XID is presented in valid hex format and is returned to
+ the caller in a buffer pointed by the first argument.
+ The buffer size provived by the caller must be not less than
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(XID::formatID) + 1, see
+ XID::serialize_xid() that is a caller and plugin.h for XID declaration.
+
+ @param buf pointer to a buffer allocated for storing serialized data
+
+ @return the value of the buffer pointer
+*/
+
+char *XA_prepare_log_event::event_xid_t::serialize(char *buf) const
+{
+ int i;
+ char *c= buf;
+ /*
+ Build a string like following pattern:
+ X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
+ and store it into buf.
+ Here hex1i and hex2k are hexadecimals representing XID's internal
+ raw bytes (1 <= i <= m, 1 <= k <= n), and `m' and `n' even numbers
+ half of which corresponding to the lengths of XID's components.
+ */
+ c[0]= 'X';
+ c[1]= '\'';
+ c+= 2;
+ for (i= 0; i < gtrid_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ c[1]= ',';
+ c[2]= 'X';
+ c[3]= '\'';
+ c+= 4;
+
+ for (; i < gtrid_length + bqual_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ sprintf(c+1, ",%lu", formatID);
+
+ return buf;
+}
+#endif /*TODO7974*/
+
+char *XA_prepare_log_event::event_xid_t::serialize(char *buf) const
+{
+ char *c= buf;
+
+ c[0]= '\'';
+ memcpy(c+1, data, gtrid_length);
+ c[gtrid_length+1]= '\'';
+ c+= gtrid_length + 2;
+
+ if (bqual_length)
+ {
+ c[0]= ',';
+ c[1]= '\'';
+ memcpy(c+2, data+gtrid_length, bqual_length);
+ c[bqual_length+2]= '\'';
+ c+= bqual_length+3;
+ }
+
+ if (formatID != 1)
+ sprintf(c, ",%lu", formatID);
+ else
+ c[0]=0;
+
+ return buf;
+}
+
+
+/**************************************************************************
+ XA_prepare_log_event methods
+**************************************************************************/
+/**
+ @note
+ It's ok not to use int8store here,
+ as long as xid_t::set(ulonglong) and
+ xid_t::get_n_xid doesn't do it either.
+ We don't care about actual values of xids as long as
+ identical numbers compare identically
+*/
+
+XA_prepare_log_event::
+XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Xid_apply_log_event(buf, description_event)
+{
+ uint32 temp= 0;
+ uint8 temp_byte;
+
+ buf+= description_event->common_header_len +
+ description_event->post_header_len[XA_PREPARE_LOG_EVENT-1];
+ memcpy(&temp_byte, buf, 1);
+ one_phase= (bool) temp_byte;
+ buf += sizeof(temp_byte);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.formatID= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.gtrid_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.bqual_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(m_xid.data, buf, m_xid.gtrid_length + m_xid.bqual_length);
+
+ xid= NULL;
+}
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void XA_prepare_log_event::pack_info(Protocol *protocol)
+{
+ char buf[ser_buf_size];
+ char query[sizeof("XA COMMIT ONE PHASE") + 1 + sizeof(buf)];
+
+ /* RHS of the following assert is unknown to client sources */
+ compile_time_assert(ser_buf_size == XID::ser_buf_size);
+ m_xid.serialize(buf);
+ sprintf(query,
+ (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+ buf);
+
+ protocol->store(query, strlen(query), &my_charset_bin);
+}
+#endif
+
+
+#ifndef MYSQL_CLIENT
+bool XA_prepare_log_event::write()
+{
+ uchar data[1 + 4 + 4 + 4];
+ uint8 one_phase_byte= one_phase;
+
+ data[0]= one_phase;
+ int4store(data+1, static_cast<XID*>(xid)->formatID);
+ int4store(data+(1+4), static_cast<XID*>(xid)->gtrid_length);
+ int4store(data+(1+4+4), static_cast<XID*>(xid)->bqual_length);
+
+ DBUG_ASSERT(xid_bufs_size == sizeof(data) - 1);
+
+ return write_header(sizeof(one_phase_byte) + xid_bufs_size +
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_data(data, sizeof(data)) ||
+ write_data((uchar*) static_cast<XID*>(xid)->data,
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_footer();
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ char buf[ser_buf_size];
+
+ m_xid.serialize(buf);
+
+ if (!print_event_info->short_form)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ if (my_b_printf(&cache, "\tXID = %s\n", buf))
+ goto error;
+ }
+
+ if (my_b_printf(&cache, "XA PREPARE %s\n%s\n",
+ buf, print_event_info->delimiter))
+ goto error;
+
+ return cache.flush_data();
+error:
+ return TRUE;
+}
+#endif /* MYSQL_CLIENT */
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int XA_prepare_log_event::record_gtid(const rpl_gtid *gtid, uint64 sub_id,
+ void **out_hton)
+{
+ int err;
+ xa_states c_state= thd->transaction.xid_state.xa_state;
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ err= rpl_global_gtid_slave_state->record_gtid(thd, gtid, sub_id, true,
+ false, out_hton);
+ thd->transaction.xid_state.xa_state= c_state;
+ return err;
+}
+
+
+int XA_prepare_log_event::do_commit()
+{
+ int res;
+ xid_t xid;
+ xid.set(m_xid.formatID,
+ m_xid.data, m_xid.gtrid_length,
+ m_xid.data + m_xid.gtrid_length, m_xid.bqual_length);
+
+ thd->lex->xid= &xid;
+ if (!one_phase)
+ {
+ res= trans_xa_prepare(thd);
+ }
+ else
+ {
+ res= trans_xa_commit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
+ return res;
+}
#endif /* !MYSQL_CLIENT */
@@ -14789,7 +15124,6 @@ bool event_that_should_be_ignored(const char *buf)
event_type == PREVIOUS_GTIDS_LOG_EVENT ||
event_type == TRANSACTION_CONTEXT_EVENT ||
event_type == VIEW_CHANGE_EVENT ||
- event_type == XA_PREPARE_LOG_EVENT ||
(uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
return 1;
return 0;
diff --git a/sql/log_event.h b/sql/log_event.h
index 38a40c9..f2f784b 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -217,6 +217,7 @@ class String;
#define GTID_HEADER_LEN 19
#define GTID_LIST_HEADER_LEN 4
#define START_ENCRYPTION_HEADER_LEN 0
+#define XA_PREPARE_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
@@ -3016,6 +3017,30 @@ class Rand_log_event: public Log_event
#endif
};
+
+class Xid_apply_log_event: public Log_event
+{
+public:
+#ifdef MYSQL_SERVER
+ Xid_apply_log_event(THD* thd_arg):
+ Log_event(thd_arg, 0, TRUE) {}
+#endif
+ Xid_apply_log_event(const char* buf,
+ const Format_description_log_event *description_event):
+ Log_event(buf, description_event) {}
+
+ ~Xid_apply_log_event() {}
+ bool is_valid() const { return 1; }
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ virtual int do_commit()= 0;
+ virtual int record_gtid(const rpl_gtid *gtid, uint64 sub_id, void **out_hton);
+ virtual int do_apply_event(rpl_group_info *rgi);
+ enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+#endif
+};
+
+
/**
@class Xid_log_event
@@ -3028,14 +3053,14 @@ class Rand_log_event: public Log_event
typedef ulonglong my_xid; // this line is the same as in handler.h
#endif
-class Xid_log_event: public Log_event
+class Xid_log_event: public Xid_apply_log_event
{
- public:
- my_xid xid;
+public:
+ my_xid xid;
#ifdef MYSQL_SERVER
Xid_log_event(THD* thd_arg, my_xid x, bool direct):
- Log_event(thd_arg, 0, TRUE), xid(x)
+ Xid_apply_log_event(thd_arg)
{
if (direct)
cache_type= Log_event::EVENT_NO_CACHE;
@@ -3055,15 +3080,85 @@ class Xid_log_event: public Log_event
#ifdef MYSQL_SERVER
bool write();
#endif
- bool is_valid() const { return 1; }
private:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
- virtual int do_apply_event(rpl_group_info *rgi);
- enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+ int do_commit();
#endif
};
+
+/**
+ @class XA_prepare_log_event
+
+ Similar to Xid_log_event except that
+ - it is specific to XA transaction
+ - it carries out the prepare logics rather than the final committing
+ when @c one_phase member is off.
+ From the groupping perspective the event finalizes the current "prepare" group
+ started with XA START Query-log-event.
+ When @c one_phase is false Commit of Rollback for XA transaction are
+ logged separately to the prepare-group events so being a groups of
+ their own.
+*/
+
+class XA_prepare_log_event: public Xid_apply_log_event
+{
+protected:
+ /* The event_xid_t members were copied from handler.h */
+ struct event_xid_t
+ {
+ long formatID;
+ long gtrid_length;
+ long bqual_length;
+ char data[MYSQL_XIDDATASIZE]; // not \0-terminated !
+ char *serialize(char *buf) const;
+ };
+
+ /* size of serialization buffer is explained in $MYSQL/sql/xa.h. */
+ static const uint ser_buf_size=
+ 8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
+
+ /* Total size of buffers to hold serialized members of XID struct */
+ static const int xid_bufs_size= 12;
+ event_xid_t m_xid;
+ void *xid;
+ bool one_phase;
+
+public:
+#ifdef MYSQL_SERVER
+ XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
+ Xid_apply_log_event(thd_arg), xid(xid_arg), one_phase(one_phase_arg)
+ {
+ cache_type= Log_event::EVENT_NO_CACHE;
+ }
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
+#else
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+#endif
+ XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event);
+ ~XA_prepare_log_event() {}
+ Log_event_type get_type_code() { return XA_PREPARE_LOG_EVENT; }
+ int get_data_size()
+ {
+ return xid_bufs_size + m_xid.gtrid_length + m_xid.bqual_length;
+ }
+
+#ifdef MYSQL_SERVER
+ bool write();
+#endif
+
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ int record_gtid(const rpl_gtid *gtid, uint64 sub_id, void **out_hton);
+ int do_commit();
+#endif
+};
+
+
/**
@class User_var_log_event
@@ -3376,6 +3471,11 @@ class Gtid_log_event: public Log_event
uint64 seq_no;
uint64 commit_id;
uint32 domain_id;
+#ifdef MYSQL_SERVER
+ XID xid;
+#else
+ struct st_mysql_xid xid;
+#endif
uchar flags2;
/* Flags2. */
@@ -3404,6 +3504,8 @@ class Gtid_log_event: public Log_event
static const uchar FL_WAITED= 16;
/* FL_DDL is set for event group containing DDL. */
static const uchar FL_DDL= 32;
+ /* FL_XA_TRANSACTION is set for XA transaction. */
+ static const uchar FL_XA_TRANSACTION= 64;
#ifdef MYSQL_SERVER
Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fa2f866..cc75da9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1461,12 +1461,19 @@ void THD::cleanup(void)
DBUG_ASSERT(cleanup_done == 0);
set_killed(KILL_CONNECTION);
-#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
-#error xid_state in the cache should be replaced by the allocated value
+ trans_detach(this);
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ }
+ else
+ {
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ trans_rollback(this);
+ xid_cache_delete(this, &transaction.xid_state);
}
-#endif
mysql_ha_cleanup(this);
locked_tables_list.unlock_locked_tables(this);
@@ -1474,11 +1481,6 @@ void THD::cleanup(void)
delete_dynamic(&user_var_events);
close_temporary_tables();
- transaction.xid_state.xa_state= XA_NOTR;
- transaction.xid_state.rm_error= 0;
- trans_rollback(this);
- xid_cache_delete(this, &transaction.xid_state);
-
DBUG_ASSERT(open_tables == NULL);
/*
If the thread was in the middle of an ongoing transaction (rolled
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 69fabee..76befcb 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1255,6 +1255,18 @@ typedef struct st_xid_state {
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error;
XID_cache_element *xid_cache_element;
+ /*
+ Binary logging status.
+ It is set to TRUE at XA PREPARE if the transaction was written
+ to the binlog.
+ Naturally FALSE means the transaction was not written to
+ the binlog. Happens if the trnasaction did not modify anything
+ or binlogging was turned off. In that case we shouldn't binlog
+ the consequent XA COMMIT/ROLLBACK.
+ The recovered transaction after server restart sets it to TRUE always.
+ That can cause inconsistencies (shoud be fixed?).
+ */
+ bool is_binlogged;
/**
Check that XA transaction has an uncommitted work. Report an error
@@ -1278,6 +1290,12 @@ typedef struct st_xid_state {
}
return false;
}
+
+ void reset()
+ {
+ xid.null();
+ is_binlogged= FALSE;
+ }
} XID_STATE;
void xid_cache_init(void);
@@ -2603,7 +2621,7 @@ class THD :public Statement,
then.
*/
if (!xid_state.rm_error)
- xid_state.xid.null();
+ xid_state.reset();
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b48070b..3e4a067 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1414,6 +1414,7 @@ void do_handle_one_connection(CONNECT *connect)
#endif
end_thread:
close_connection(thd);
+ thd->get_stmt_da()->reset_diagnostics_area();
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 13614d3..447a06b 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -790,6 +790,44 @@ bool trans_release_savepoint(THD *thd, LEX_CSTRING name)
/**
+ Detach the current XA transaction;
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_detach(THD *thd)
+{
+ XID_STATE *xid_s= &thd->transaction.xid_state;
+ Ha_trx_info *ha_info, *ha_info_next;
+
+ DBUG_ENTER("trans_detach");
+
+// DBUG_ASSERT(xid_s->xa_state == XA_PREPARED &&
+// xid_cache_search(thd, &xid_s->xid));
+
+ xid_cache_delete(thd, xid_s);
+ if (xid_cache_insert(&xid_s->xid, XA_PREPARED))
+ DBUG_RETURN(TRUE);
+
+ for (ha_info= thd->transaction.all.ha_list;
+ ha_info;
+ ha_info= ha_info_next)
+ {
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
+ }
+
+ thd->transaction.all.ha_list= 0;
+ thd->transaction.all.no_2pc= 0;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Starts an XA transaction with the given xid value.
@param thd Current thread
@@ -862,7 +900,15 @@ bool trans_xa_end(THD *thd)
else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0));
else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
- thd->transaction.xid_state.xa_state= XA_IDLE;
+ {
+ if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) &&
+ thd->binlog_query(THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ TRUE, FALSE, FALSE, 0))
+ my_error(ER_XAER_RMERR, MYF(0));
+ else
+ thd->transaction.xid_state.xa_state= XA_IDLE;
+ }
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xa_state != XA_IDLE);
@@ -928,6 +974,12 @@ bool trans_xa_commit(THD *thd)
res= !xs;
if (res)
my_error(ER_XAER_NOTA, MYF(0));
+ else if (thd->in_multi_stmt_transaction_mode())
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ res= TRUE;
+ }
else
{
res= xa_trans_rolled_back(xs);
@@ -978,8 +1030,16 @@ bool trans_xa_commit(THD *thd)
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- res= MY_TEST(ha_commit_one_phase(thd, 1));
- if (res)
+ if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ FALSE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ if (res || (res= MY_TEST(ha_commit_one_phase(thd, 1))))
my_error(ER_XAER_RMERR, MYF(0));
}
}
@@ -1032,19 +1092,36 @@ bool trans_xa_rollback(THD *thd)
else
{
xa_trans_rolled_back(xs);
- ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ if (ha_commit_or_rollback_by_xid(thd->lex->xid, 0) == 0 &&
+ (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()))
+ thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ FALSE, FALSE, FALSE, 0);
xid_cache_delete(thd, xs);
}
DBUG_RETURN(thd->get_stmt_da()->is_error());
}
- if (xa_state != XA_IDLE && xa_state != XA_PREPARED && xa_state != XA_ROLLBACK_ONLY)
+ if (xa_state != XA_IDLE && xa_state != XA_PREPARED &&
+ xa_state != XA_ROLLBACK_ONLY)
{
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
DBUG_RETURN(TRUE);
}
- res= xa_trans_force_rollback(thd);
+ if(xa_state == XA_PREPARED &&
+ (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()))
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ FALSE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ res= res || xa_trans_force_rollback(thd);
+ if (res || (res= MY_TEST(xa_trans_force_rollback(thd))))
+ my_error(ER_XAER_RMERR, MYF(0));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
diff --git a/sql/transaction.h b/sql/transaction.h
index 7e34693..f228cc6 100644
--- a/sql/transaction.h
+++ b/sql/transaction.h
@@ -29,6 +29,7 @@ bool trans_commit(THD *thd);
bool trans_commit_implicit(THD *thd);
bool trans_rollback(THD *thd);
bool trans_rollback_implicit(THD *thd);
+bool trans_detach(THD *thd);
bool trans_commit_stmt(THD *thd);
bool trans_rollback_stmt(THD *thd);
1
0
revision-id: 89ec4289fb5e8dfea819617f7671fd25f0e73248 (mariadb-10.3.6-141-g89ec4289fb5)
parent(s): c568e25379600db8af4bd39df4761ba0fbc1a14e
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-02-18 00:34:22 +0530
message:
Minor cleanup in the optimizer trace code.
More test coverage added for the optimizer trace.
---
mysql-test/main/opt_trace.result | 2883 ++++++++++++++++++--
mysql-test/main/opt_trace.test | 41 +
mysql-test/main/opt_trace_index_merge.result | 10 +-
.../main/opt_trace_index_merge_innodb.result | 10 +-
mysql-test/main/opt_trace_security.result | 18 +-
sql/my_json_writer.cc | 20 +-
sql/my_json_writer.h | 20 +-
sql/opt_range.cc | 105 +-
sql/opt_subselect.cc | 70 +-
sql/opt_table_elimination.cc | 23 +-
sql/opt_trace.cc | 160 +-
sql/opt_trace.h | 15 +-
sql/opt_trace_context.h | 15 +-
sql/sql_class.cc | 2 +-
sql/sql_derived.cc | 43 +-
sql/sql_select.cc | 44 +-
sql/sql_test.cc | 10 +-
17 files changed, 3015 insertions(+), 474 deletions(-)
diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result
index 22cde925b5e..8b12e7a7af1 100644
--- a/mysql-test/main/opt_trace.result
+++ b/mysql-test/main/opt_trace.result
@@ -45,7 +45,7 @@ select * from v1 {
"view": {
"table": "v1",
"select_id": 2,
- "merged": true
+ "algorithm": "merged"
}
},
{
@@ -53,13 +53,13 @@ select * from v1 {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1"
+ "expanded_query": "/* select#2 */ select t1.a AS a,t1.b AS b from t1 where t1.a = 1"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `v1`"
+ "expanded_query": "/* select#1 */ select t1.a AS a,t1.b AS b from v1"
}
]
}
@@ -108,9 +108,10 @@ select * from v1 {
"selectivity_for_columns": [
{
"column_name": "a",
- "selectivity_from_histograms": 0.5
+ "selectivity_from_histogram": 0.5
}
- ]
+ ],
+ "cond_selectivity": 0.5
},
{
"table": "t1",
@@ -121,11 +122,6 @@ select * from v1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -182,7 +178,7 @@ select * from (select * from t1 where t1.a=1)q {
"derived": {
"table": "q",
"select_id": 2,
- "merged": true
+ "algorithm": "merged"
}
},
{
@@ -190,13 +186,13 @@ select * from (select * from t1 where t1.a=1)q {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1"
+ "expanded_query": "/* select#2 */ select t1.a AS a,t1.b AS b from t1 where t1.a = 1"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from (/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1) `q`"
+ "expanded_query": "/* select#1 */ select t1.a AS a,t1.b AS b from (/* select#2 */ select t1.a AS a,t1.b AS b from t1 where t1.a = 1) q"
}
]
}
@@ -245,9 +241,10 @@ select * from (select * from t1 where t1.a=1)q {
"selectivity_for_columns": [
{
"column_name": "a",
- "selectivity_from_histograms": 0.5
+ "selectivity_from_histogram": 0.5
}
- ]
+ ],
+ "cond_selectivity": 0.5
},
{
"table": "t1",
@@ -258,11 +255,6 @@ select * from (select * from t1 where t1.a=1)q {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -320,7 +312,7 @@ select * from v2 {
"view": {
"table": "v2",
"select_id": 2,
- "materialized": true
+ "algorithm": "materialized"
}
},
{
@@ -328,13 +320,13 @@ select * from v2 {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1 group by `t1`.`b`"
+ "expanded_query": "/* select#2 */ select t1.a AS a,t1.b AS b from t1 where t1.a = 1 group by t1.b"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `v2`"
+ "expanded_query": "/* select#1 */ select v2.a AS a,v2.b AS b from v2"
}
]
}
@@ -387,9 +379,10 @@ select * from v2 {
"selectivity_for_columns": [
{
"column_name": "a",
- "selectivity_from_histograms": 0.5
+ "selectivity_from_histogram": 0.5
}
- ]
+ ],
+ "cond_selectivity": 0.5
},
{
"table": "t1",
@@ -400,11 +393,6 @@ select * from v2 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -460,11 +448,6 @@ select * from v2 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -548,7 +531,7 @@ explain select * from v2 {
"view": {
"table": "v2",
"select_id": 2,
- "merged": true
+ "algorithm": "merged"
}
},
{
@@ -556,13 +539,13 @@ explain select * from v2 {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `t2`.`a` AS `a` from `t2`"
+ "expanded_query": "/* select#2 */ select t2.a AS a from t2"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `t2`.`a` AS `a` from `v2`"
+ "expanded_query": "/* select#1 */ select t2.a AS a from v2"
}
]
}
@@ -592,11 +575,6 @@ explain select * from v2 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -655,7 +633,7 @@ explain select * from v1 {
"view": {
"table": "v1",
"select_id": 2,
- "materialized": true
+ "algorithm": "materialized"
}
},
{
@@ -663,13 +641,13 @@ explain select * from v1 {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `t1`.`a` AS `a` from `t1` group by `t1`.`b`"
+ "expanded_query": "/* select#2 */ select t1.a AS a from t1 group by t1.b"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `v1`.`a` AS `a` from `v1`"
+ "expanded_query": "/* select#1 */ select v1.a AS a from v1"
}
]
}
@@ -703,11 +681,6 @@ explain select * from v1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -763,11 +736,6 @@ explain select * from v1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -848,7 +816,7 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t2`.`a` AS `a`,`t2`.`b` AS `b`,`t2`.`c` AS `c` from `t1` join `t2` where `t1`.`a` = `t2`.`b` + 2 and `t2`.`a` = `t1`.`b`"
+ "expanded_query": "select t1.a AS a,t1.b AS b,t1.c AS c,t2.a AS a,t2.b AS b,t2.c AS c from t1 join t2 where t1.a = t2.b + 2 and t2.a = t1.b"
}
]
}
@@ -927,11 +895,6 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -1063,7 +1026,7 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select distinct `t1`.`a` AS `a` from `t1`"
+ "expanded_query": "select distinct t1.a AS a from t1"
}
]
}
@@ -1123,7 +1086,7 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
"best_group_range_summary": {
"type": "index_group",
"index": "a",
- "group_attribute": null,
+ "min_max_arg": null,
"min_aggregate": false,
"max_aggregate": false,
"distinct_aggregate": false,
@@ -1137,7 +1100,7 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
"range_access_plan": {
"type": "index_group",
"index": "a",
- "group_attribute": null,
+ "min_max_arg": null,
"min_aggregate": false,
"max_aggregate": false,
"distinct_aggregate": false,
@@ -1154,11 +1117,6 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -1222,7 +1180,7 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
"select_id": 1,
"steps": [
{
- "expanded_query": "select min(`t1`.`d`) AS `MIN(d)` from `t1` where `t1`.`b` = 2 and `t1`.`c` = 3 group by `t1`.`a`"
+ "expanded_query": "select min(t1.d) AS `MIN(d)` from t1 where t1.b = 2 and t1.c = 3 group by t1.a"
}
]
}
@@ -1300,7 +1258,7 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
"best_group_range_summary": {
"type": "index_group",
"index": "a",
- "group_attribute": "d",
+ "min_max_arg": "d",
"min_aggregate": true,
"max_aggregate": false,
"distinct_aggregate": false,
@@ -1325,21 +1283,17 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
"selectivity_for_columns": [
{
"column_name": "b",
- "selectivity_from_histograms": 0.1667
+ "selectivity_from_histogram": 0.1667
},
{
"column_name": "c",
- "selectivity_from_histograms": 0.25
+ "selectivity_from_histogram": 0.25
}
- ]
+ ],
+ "cond_selectivity": 0.0417
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -1424,7 +1378,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`id` AS `id`,min(`t1`.`a`) AS `MIN(a)`,max(`t1`.`a`) AS `MAX(a)` from `t1` where `t1`.`a` >= 20010104e0 group by `t1`.`id`"
+ "expanded_query": "select t1.`id` AS `id`,min(t1.a) AS `MIN(a)`,max(t1.a) AS `MAX(a)` from t1 where t1.a >= 20010104e0 group by t1.`id`"
}
]
}
@@ -1502,7 +1456,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"best_group_range_summary": {
"type": "index_group",
"index": "id",
- "group_attribute": "a",
+ "min_max_arg": "a",
"min_aggregate": true,
"max_aggregate": true,
"distinct_aggregate": false,
@@ -1523,7 +1477,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"range_access_plan": {
"type": "index_group",
"index": "id",
- "group_attribute": "a",
+ "min_max_arg": "a",
"min_aggregate": true,
"max_aggregate": true,
"distinct_aggregate": false,
@@ -1540,11 +1494,6 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -1599,7 +1548,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`id` AS `id`,`t1`.`a` AS `a` from `t1` where `t1`.`a` = 20010104e0 group by `t1`.`id`"
+ "expanded_query": "select t1.`id` AS `id`,t1.a AS a from t1 where t1.a = 20010104e0 group by t1.`id`"
}
]
}
@@ -1677,7 +1626,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"best_group_range_summary": {
"type": "index_group",
"index": "id",
- "group_attribute": null,
+ "min_max_arg": null,
"min_aggregate": false,
"max_aggregate": false,
"distinct_aggregate": false,
@@ -1698,7 +1647,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"range_access_plan": {
"type": "index_group",
"index": "id",
- "group_attribute": null,
+ "min_max_arg": null,
"min_aggregate": false,
"max_aggregate": false,
"distinct_aggregate": false,
@@ -1715,11 +1664,6 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -1801,7 +1745,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`pk` AS `pk`,`t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t1`.`filler` AS `filler` from `t1` where `t1`.`a` = 1 and `t1`.`b` = 2 order by `t1`.`c` limit 1"
+ "expanded_query": "select t1.pk AS pk,t1.a AS a,t1.b AS b,t1.c AS c,t1.filler AS filler from t1 where t1.a = 1 and t1.b = 2 order by t1.c limit 1"
}
]
}
@@ -1944,21 +1888,17 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"selectivity_for_columns": [
{
"column_name": "a",
- "selectivity_from_histograms": 0.0012
+ "selectivity_from_histogram": 0.0012
},
{
"column_name": "b",
- "selectivity_from_histograms": 0.001
+ "selectivity_from_histogram": 0.001
}
- ]
+ ],
+ "cond_selectivity": 0.021
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -2147,7 +2087,7 @@ select t1.a from t1 left join t2 on t1.a=t2.a {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`a` AS `a` from (`t1` left join `t2` on(`t1`.`a` = `t2`.`a`))"
+ "expanded_query": "select t1.a AS a from (t1 left join t2 on(t1.a = t2.a))"
}
]
}
@@ -2202,11 +2142,6 @@ select t1.a from t1 left join t2 on t1.a=t2.a {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -2265,7 +2200,7 @@ explain select * from t1 left join t2 on t2.a=t1.a {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`a` AS `a`,`t2`.`a` AS `a`,`t2`.`b` AS `b` from (`t1` left join `t2` on(`t2`.`a` = `t1`.`a`))"
+ "expanded_query": "select t1.a AS a,t2.a AS a,t2.b AS b from (t1 left join t2 on(t2.a = t1.a))"
}
]
}
@@ -2321,11 +2256,6 @@ explain select * from t1 left join t2 on t2.a=t1.a {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -2410,7 +2340,7 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`a` AS `a` from (`t1` left join (`t2` join `t3` on(`t2`.`b` = `t3`.`b`)) on(`t2`.`a` = `t1`.`a` and `t3`.`a` = `t1`.`a`))"
+ "expanded_query": "select t1.a AS a from (t1 left join (t2 join t3 on(t2.b = t3.b)) on(t2.a = t1.a and t3.a = t1.a))"
}
]
}
@@ -2495,11 +2425,6 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -2602,13 +2527,13 @@ explain extended select * from t1 where a in (select pk from t10) {
}
},
{
- "expanded_query": "/* select#2 */ select `t10`.`pk` from `t10`"
+ "expanded_query": "/* select#2 */ select t10.pk from t10"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` in (/* select#2 */ select `t10`.`pk` from `t10`)"
+ "expanded_query": "/* select#1 */ select t1.a AS a,t1.b AS b from t1 where t1.a in (/* select#2 */ select t10.pk from t10)"
}
]
}
@@ -2755,6 +2680,15 @@ explain extended select * from t1 where a in (select pk from t10) {
}
]
},
+ {
+ "fix_semijoin_strategies_for_picked_join_order": {
+ "sj_materialzation": [
+ {
+ "table": "t10"
+ }
+ ]
+ }
+ },
{
"condition_on_constant_tables": "1"
},
@@ -2824,7 +2758,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `t1`.`pk` AS `pk`,`t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`pk` = 2 and `t1`.`a` = 5 and `t1`.`b` = 1"
+ "expanded_query": "select t1.pk AS pk,t1.a AS a,t1.b AS b from t1 where t1.pk = 2 and t1.a = 5 and t1.b = 1"
}
]
}
@@ -3030,21 +2964,17 @@ explain select * from t1 where pk = 2 and a=5 and b=1 {
"selectivity_for_columns": [
{
"column_name": "a",
- "selectivity_from_histograms": 0.1
+ "selectivity_from_histogram": 0.1
},
{
"column_name": "b",
- "selectivity_from_histograms": 0.1
+ "selectivity_from_histogram": 0.1
}
- ]
+ ],
+ "cond_selectivity": 0.1
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -3152,7 +3082,7 @@ select f1(a) from t1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `f1`(`t1`.`a`) AS `f1(a)` from `t1`"
+ "expanded_query": "select f1(t1.a) AS `f1(a)` from t1"
}
]
}
@@ -3182,11 +3112,6 @@ select f1(a) from t1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -3243,7 +3168,7 @@ select f2(a) from t1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `f2`(`t1`.`a`) AS `f2(a)` from `t1`"
+ "expanded_query": "select f2(t1.a) AS `f2(a)` from t1"
}
]
}
@@ -3273,11 +3198,6 @@ select f2(a) from t1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -3336,7 +3256,7 @@ a
2
select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
length(trace)
-1889
+1754
set optimizer_trace_max_mem_size=100;
select * from t1;
a
@@ -3350,7 +3270,7 @@ select * from t1 {
"join_preparation": {
"select_id": 1,
"steps": [
- 1789 0
+ 1654 0
set optimizer_trace_max_mem_size=0;
select * from t1;
a
@@ -3358,7 +3278,7 @@ a
2
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
-select * from t1 1889 0
+select * from t1 1754 0
drop table t1;
set optimizer_trace='enabled=off';
set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
@@ -3432,6 +3352,7 @@ set optimizer_trace='enabled=off';
#
# MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
#
+set optimizer_trace=1;
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);
@@ -3445,55 +3366,2627 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 5 test.t0.a 1
select * from information_schema.optimizer_trace;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
-explain delete from t0 where t0.a<3 {
+explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"steps": [
{
- "table": "t0",
- "range_analysis": {
- "table_scan": {
- "rows": 10,
- "cost": 6.122
- },
- "potential_range_indexes": [
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
{
- "index": "a",
- "usable": true,
- "key_parts": ["a"]
+ "expanded_query": "select NULL AS `NULL` from t0 join t1 where t0.a = t1.a and t1.a < 3"
}
- ],
- "setup_range_conditions": [],
- "group_index_range": {
- "chosen": false,
- "cause": "no join"
- },
- "analyzing_range_alternatives": {
- "range_scan_alternatives": [
- {
- "index": "a",
- "ranges": ["NULL < a < 3"],
- "rowid_ordered": false,
- "using_mrr": false,
- "index_only": false,
- "rows": 3,
- "cost": 4.61,
- "chosen": true
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t0.a = t1.a and t1.a < 3",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "t1.a < 3 and multiple equal(t0.a, t1.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "t1.a < 3 and multiple equal(t0.a, t1.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "t1.a < 3 and multiple equal(t0.a, t1.a)"
+ }
+ ]
}
- ],
- "analyzing_index_merge_union": []
- },
- "chosen_range_access_summary": {
- "range_access_plan": {
- "type": "range_scan",
- "index": "a",
- "rows": 3,
- "ranges": ["NULL < a < 3"]
},
- "rows_for_plan": 3,
- "cost_for_plan": 4.61,
- "chosen": true
- }
- }
- }
- ]
-} 0 0
-drop table ten,t0,t1;
+ {
+ "table_dependencies": [
+ {
+ "table": "t0",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t0",
+ "field": "a",
+ "equals": "t1.a",
+ "null_rejecting": true
+ },
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "t0.a",
+ "null_rejecting": true
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t0",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 10,
+ "cost": 6.122
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "a",
+ "cost": 3.2061,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not single_table"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "a",
+ "ranges": ["NULL < a < 3"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": true,
+ "rows": 3,
+ "cost": 1.6558,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a",
+ "rows": 3,
+ "ranges": ["NULL < a < 3"]
+ },
+ "rows_for_plan": 3,
+ "cost_for_plan": 1.6558,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "a",
+ "selectivity_from_index": 0.3
+ }
+ ],
+ "selectivity_for_columns": [],
+ "cond_selectivity": 0.3
+ },
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 10,
+ "cost": 6.122
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "a",
+ "cost": 3.2061,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not single_table"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "a",
+ "ranges": ["NULL < a < 3"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": true,
+ "rows": 3,
+ "cost": 1.6558,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a",
+ "rows": 3,
+ "ranges": ["NULL < a < 3"]
+ },
+ "rows_for_plan": 3,
+ "cost_for_plan": 1.6558,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "a",
+ "selectivity_from_index": 0.3
+ }
+ ],
+ "selectivity_for_columns": [],
+ "cond_selectivity": 0.3
+ }
+ ]
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t0",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "resulting_rows": 3,
+ "cost": 1.6558,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t0"],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "a",
+ "used_range_estimates": false,
+ "cause": "not better than ref estimates",
+ "rows": 1,
+ "cost": 3,
+ "chosen": true
+ },
+ {
+ "type": "scan",
+ "chosen": false,
+ "cause": "cost"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "resulting_rows": 3,
+ "cost": 1.6558,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1"],
+ "table": "t0",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "a",
+ "used_range_estimates": false,
+ "cause": "not better than ref estimates",
+ "rows": 2,
+ "cost": 3.0687,
+ "chosen": true
+ },
+ {
+ "type": "scan",
+ "chosen": false,
+ "cause": "cost"
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = t0.a and t0.a < 3",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t0",
+ "attached": "t0.a < 3 and t0.a is not null"
+ },
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+} 0 0
+drop table ten,t0,t1;
+set optimizer_trace='enabled=off';
+#
+# Merged to Materialized for derived tables
+#
+set optimizer_trace=1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+explain select * from (select rand() from t1)q;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+2 DERIVED t1 ALL NULL NULL NULL NULL 3
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+explain select * from (select rand() from t1)q {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "derived": {
+ "table": "q",
+ "select_id": 2,
+ "algorithm": "merged"
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select rand() AS `rand()` from t1"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select rand() AS `rand()` from (/* select#2 */ select rand() AS `rand()` from t1) q"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "derived": {
+ "table": "q",
+ "select_id": 2,
+ "algorithm": "materialized",
+ "cause": "Random function in the select"
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 2,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ }
+ ]
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "<derived2>",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "<derived2>",
+ "table_scan": {
+ "rows": 3,
+ "cost": 3
+ }
+ }
+ ]
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "<derived2>",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 3,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "<derived2>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_execution": {
+ "select_id": 2,
+ "steps": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+} 0 0
+drop table t1;
+set optimizer_trace='enabled=off';
+#
+# Semi-join nest
+#
+set optimizer_trace=1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+create table t2(a int);
+insert into t2 values (1),(2),(3),(1),(2),(3),(1),(2),(3);
+set @save_optimizer_switch= @@optimizer_switch;
+explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_inner_2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t_inner_1 ALL NULL NULL NULL NULL 3
+2 MATERIALIZED t_inner_2 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_inner_2) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#2 */ select t_inner_1.a from t1 t_inner_1 join t1 t_inner_2"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select t1.a AS a from t1 where t1.a in (/* select#2 */ select t_inner_1.a from t1 t_inner_1 join t1 t_inner_2)"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "1 and t1.a = t_inner_1.a",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "1 and multiple equal(t1.a, t_inner_1.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "1 and multiple equal(t1.a, t_inner_1.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(t1.a, t_inner_1.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_1",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_2",
+ "row_may_be_null": false,
+ "map_bit": 2,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_inner_1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_inner_2",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": [
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_inner_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1"],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1", "t_inner_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "fix_semijoin_strategies_for_picked_join_order": {
+ "sj_materialzation": [
+ {
+ "table": "t_inner_1"
+ },
+ {
+ "table": "t_inner_2"
+ }
+ ]
+ }
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ },
+ {
+ "table": "t_inner_1",
+ "attached": null
+ },
+ {
+ "table": "t_inner_2",
+ "attached": null
+ },
+ {
+ "table": "<subquery2>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+} 0 0
+# with Firstmatch, mostly for tracing fix_semijoin_strategies_for_picked_join_order
+set optimizer_switch='materialization=off';
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t_outer_1 ALL NULL NULL NULL NULL 3
+1 PRIMARY t_inner_1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t_inner_2 ALL NULL NULL NULL NULL 9 FirstMatch(t_outer_1); Using join buffer (incremental, BNL join)
+1 PRIMARY t_outer_2 ALL NULL NULL NULL NULL 9 Using join buffer (incremental, BNL join)
+1 PRIMARY t_inner_4 ALL NULL NULL NULL NULL 3 Using join buffer (incremental, BNL join)
+1 PRIMARY t_inner_3 ALL NULL NULL NULL NULL 9 Using where; FirstMatch(t_outer_2); Using join buffer (incremental, BNL join)
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#2 */ select t_inner_1.a from t2 t_inner_2 join t1 t_inner_1"
+ }
+ ]
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 3,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#3 */ select t_inner_3.a from t2 t_inner_3 join t1 t_inner_4"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select t_outer_1.a AS a,t_outer_2.a AS a from t1 t_outer_1 join t2 t_outer_2 where t_outer_1.a in (/* select#2 */ select t_inner_1.a from t2 t_inner_2 join t1 t_inner_1) and t_outer_2.a in (/* select#3 */ select t_inner_3.a from t2 t_inner_3 join t1 t_inner_4)"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "1 and 1 and t_outer_1.a = t_inner_1.a and t_outer_2.a = t_inner_3.a",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "1 and 1 and multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "1 and 1 and multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t_outer_1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_outer_2",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_2",
+ "row_may_be_null": false,
+ "map_bit": 2,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_1",
+ "row_may_be_null": false,
+ "map_bit": 3,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_3",
+ "row_may_be_null": false,
+ "map_bit": 4,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_4",
+ "row_may_be_null": false,
+ "map_bit": 5,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t_outer_1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_outer_2",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_2",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_inner_3",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_4",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t_outer_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2"
+ ],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_inner_4"
+ ],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_inner_4",
+ "t_outer_2"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_outer_2"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_outer_2"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_outer_2"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_4"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_4",
+ "t_outer_2"
+ ],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_4",
+ "t_outer_2"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_4"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_4"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_3"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_3",
+ "t_outer_2"
+ ],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_3",
+ "t_outer_2"
+ ],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_3"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_3",
+ "t_inner_4"
+ ],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_3",
+ "t_inner_4"
+ ],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_3"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "fix_semijoin_strategies_for_picked_join_order": {
+ "first_match_strategy": [
+ {
+ "table": "t_inner_4"
+ },
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 162.42,
+ "chosen": true
+ }
+ ]
+ },
+ {
+ "table": "t_inner_3"
+ },
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 489.74,
+ "chosen": true
+ }
+ ]
+ }
+ ],
+ "first_match_strategy": [
+ {
+ "table": "t_inner_1"
+ },
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 18.046,
+ "chosen": true
+ }
+ ]
+ },
+ {
+ "table": "t_inner_2"
+ },
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 54.415,
+ "chosen": true
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t_inner_1.a = t_outer_1.a and t_inner_3.a = t_outer_2.a",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t_outer_1",
+ "attached": null
+ },
+ {
+ "table": "t_inner_1",
+ "attached": "t_inner_1.a = t_outer_1.a"
+ },
+ {
+ "table": "t_inner_2",
+ "attached": null
+ },
+ {
+ "table": "t_outer_2",
+ "attached": null
+ },
+ {
+ "table": "t_inner_4",
+ "attached": null
+ },
+ {
+ "table": "t_inner_3",
+ "attached": "t_inner_3.a = t_outer_2.a"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+} 0 0
+set optimizer_switch='materialization=on';
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t_outer_1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY t_outer_2 ALL NULL NULL NULL NULL 9 Using join buffer (flat, BNL join)
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t_inner_1 ALL NULL NULL NULL NULL 3
+2 MATERIALIZED t_inner_2 ALL NULL NULL NULL NULL 9 Using join buffer (flat, BNL join)
+3 MATERIALIZED t_inner_4 ALL NULL NULL NULL NULL 3
+3 MATERIALIZED t_inner_3 ALL NULL NULL NULL NULL 9 Using join buffer (flat, BNL join)
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#2 */ select t_inner_1.a from t2 t_inner_2 join t1 t_inner_1"
+ }
+ ]
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 3,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#3 */ select t_inner_3.a from t2 t_inner_3 join t1 t_inner_4"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select t_outer_1.a AS a,t_outer_2.a AS a from t1 t_outer_1 join t2 t_outer_2 where t_outer_1.a in (/* select#2 */ select t_inner_1.a from t2 t_inner_2 join t1 t_inner_1) and t_outer_2.a in (/* select#3 */ select t_inner_3.a from t2 t_inner_3 join t1 t_inner_4)"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 3,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "1 and 1 and t_outer_1.a = t_inner_1.a and t_outer_2.a = t_inner_3.a",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "1 and 1 and multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "1 and 1 and multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(t_outer_1.a, t_inner_1.a) and multiple equal(t_outer_2.a, t_inner_3.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t_outer_1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_outer_2",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_2",
+ "row_may_be_null": false,
+ "map_bit": 2,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_1",
+ "row_may_be_null": false,
+ "map_bit": 3,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_3",
+ "row_may_be_null": false,
+ "map_bit": 4,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t_inner_4",
+ "row_may_be_null": false,
+ "map_bit": 5,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t_outer_1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_outer_2",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_2",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ },
+ {
+ "table": "t_inner_3",
+ "table_scan": {
+ "rows": 9,
+ "cost": 2.0154
+ }
+ },
+ {
+ "table": "t_inner_4",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0051
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": [
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_inner_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_inner_4"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t_outer_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2"
+ ],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_inner_4"
+ ],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1", "t_inner_1"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": ["t_outer_1"],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_outer_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ },
+ {
+ "plan_prefix": [],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "fix_semijoin_strategies_for_picked_join_order": {
+ "sj_materialzation": [
+ {
+ "table": "t_inner_4"
+ },
+ {
+ "table": "t_inner_3"
+ }
+ ],
+ "sj_materialzation": [
+ {
+ "table": "t_inner_1"
+ },
+ {
+ "table": "t_inner_2"
+ }
+ ]
+ }
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t_outer_1",
+ "attached": null
+ },
+ {
+ "table": "t_inner_1",
+ "attached": null
+ },
+ {
+ "table": "t_inner_2",
+ "attached": null
+ },
+ {
+ "table": "<subquery2>",
+ "attached": null
+ },
+ {
+ "table": "t_outer_2",
+ "attached": null
+ },
+ {
+ "table": "t_inner_4",
+ "attached": null
+ },
+ {
+ "table": "t_inner_3",
+ "attached": null
+ },
+ {
+ "table": "<subquery3>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+} 0 0
+set @@optimizer_switch= @save_optimizer_switch;
+drop table t1,t2;
+set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test
index f55cf57b82a..e59a11fbfc3 100644
--- a/mysql-test/main/opt_trace.test
+++ b/mysql-test/main/opt_trace.test
@@ -323,6 +323,7 @@ set optimizer_trace='enabled=off';
--echo # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
--echo #
+set optimizer_trace=1;
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);
@@ -333,3 +334,43 @@ 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 optimizer_trace='enabled=off';
+
+--echo #
+--echo # Merged to Materialized for derived tables
+--echo #
+
+set optimizer_trace=1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+explain select * from (select rand() from t1)q;
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
+set optimizer_trace='enabled=off';
+
+--echo #
+--echo # Semi-join nest
+--echo #
+
+set optimizer_trace=1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+create table t2(a int);
+insert into t2 values (1),(2),(3),(1),(2),(3),(1),(2),(3);
+set @save_optimizer_switch= @@optimizer_switch;
+explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_inner_2);
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+--echo # with Firstmatch, mostly for tracing fix_semijoin_strategies_for_picked_join_order
+
+set optimizer_switch='materialization=off';
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+set optimizer_switch='materialization=on';
+explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
+ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+set @@optimizer_switch= @save_optimizer_switch;
+drop table t1,t2;
+set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_trace_index_merge.result b/mysql-test/main/opt_trace_index_merge.result
index 4c75465f958..6aabf34773a 100644
--- a/mysql-test/main/opt_trace_index_merge.result
+++ b/mysql-test/main/opt_trace_index_merge.result
@@ -24,7 +24,7 @@ explain select * from t1 where a=1 or b=1 {
"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"
+ "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"
}
]
}
@@ -194,15 +194,11 @@ explain select * from t1 where a=1 or b=1 {
},
{
"selectivity_for_indexes": [],
- "selectivity_for_columns": []
+ "selectivity_for_columns": [],
+ "cond_selectivity": 0.002
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
diff --git a/mysql-test/main/opt_trace_index_merge_innodb.result b/mysql-test/main/opt_trace_index_merge_innodb.result
index a0f03e326a3..4a0f4c7f7fd 100644
--- a/mysql-test/main/opt_trace_index_merge_innodb.result
+++ b/mysql-test/main/opt_trace_index_merge_innodb.result
@@ -27,7 +27,7 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"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"
+ "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"
}
]
}
@@ -180,15 +180,11 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"selectivity_from_index": 0.001
}
],
- "selectivity_for_columns": []
+ "selectivity_for_columns": [],
+ "cond_selectivity": 0.001
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result
index 2d66a0a9576..9f5bacd6aa7 100644
--- a/mysql-test/main/opt_trace_security.result
+++ b/mysql-test/main/opt_trace_security.result
@@ -55,7 +55,7 @@ select * from db1.t1 {
"select_id": 1,
"steps": [
{
- "expanded_query": "select `db1`.`t1`.`a` AS `a` from `t1`"
+ "expanded_query": "select db1.t1.a AS a from t1"
}
]
}
@@ -85,11 +85,6 @@ select * from db1.t1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
@@ -157,7 +152,7 @@ select * from db1.v1 {
"view": {
"table": "v1",
"select_id": 2,
- "merged": true
+ "algorithm": "merged"
}
},
{
@@ -165,13 +160,13 @@ select * from db1.v1 {
"select_id": 2,
"steps": [
{
- "expanded_query": "/* select#2 */ select `db1`.`t1`.`a` AS `a` from `t1`"
+ "expanded_query": "/* select#2 */ select db1.t1.a AS a from t1"
}
]
}
},
{
- "expanded_query": "/* select#1 */ select `db1`.`t1`.`a` AS `a` from `v1`"
+ "expanded_query": "/* select#1 */ select db1.t1.a AS a from v1"
}
]
}
@@ -201,11 +196,6 @@ select * from db1.v1 {
}
]
},
- {
- "execution_plan_for_potential_materialization": {
- "steps": []
- }
- },
{
"considered_execution_plans": [
{
diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc
index 7ae0c58bd7d..3755f8d4bcb 100644
--- a/sql/my_json_writer.cc
+++ b/sql/my_json_writer.cc
@@ -219,15 +219,15 @@ void Json_writer::add_str(const String &str)
add_str(str.ptr(), str.length());
}
-Json_writer_object::Json_writer_object(THD *thd) :
+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(THD* thd, const char *str)
- : Json_writer_struct(thd)
+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();
@@ -247,8 +247,8 @@ Json_writer_array::Json_writer_array(THD *thd) :
my_writer->start_array();
}
-Json_writer_array::Json_writer_array(THD *thd, const char *str)
- :Json_writer_struct(thd)
+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();
@@ -263,6 +263,16 @@ Json_writer_array::~Json_writer_array()
}
}
+Json_writer_temp_disable::Json_writer_temp_disable(THD *thd_arg)
+{
+ thd= thd_arg;
+ thd->opt_trace.disable_tracing_if_required();
+}
+Json_writer_temp_disable::~Json_writer_temp_disable()
+{
+ thd->opt_trace.enable_tracing_if_required();
+}
+
bool Single_line_formatting_helper::on_add_member(const char *name)
{
DBUG_ASSERT(state== INACTIVE || state == DISABLED);
diff --git a/sql/my_json_writer.h b/sql/my_json_writer.h
index 3234c748f5d..dbd7cd133e9 100644
--- a/sql/my_json_writer.h
+++ b/sql/my_json_writer.h
@@ -215,12 +215,11 @@ class Json_writer
*/
void set_size_limit(size_t mem_size) { output.set_size_limit(mem_size); }
- // psergey: return how many bytes would be required to store everything
size_t get_truncated_bytes() { return output.get_truncated_bytes(); }
Json_writer() :
indent_level(0), document_start(true), element_started(false),
- first_child(true), allowed_mem_size(0)
+ first_child(true)
{
fmt_helper.init(this);
}
@@ -235,12 +234,6 @@ class Json_writer
bool element_started;
bool first_child;
- /*
- True when we are using the optimizer trace
- FALSE otherwise
- */
- size_t allowed_mem_size;
-
Single_line_formatting_helper fmt_helper;
void append_indent();
@@ -566,6 +559,17 @@ class Json_writer_array : public Json_writer_struct
~Json_writer_array();
};
+/*
+ RAII-based class to disable writing into the JSON document
+*/
+
+class Json_writer_temp_disable
+{
+public:
+ Json_writer_temp_disable(THD *thd_arg);
+ ~Json_writer_temp_disable();
+ THD *thd;
+};
/*
RAII-based helper class to detect incorrect use of Json_writer.
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index c87a0595a7d..8f21881b6e4 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -675,7 +675,7 @@ int SEL_IMERGE::or_sel_tree_with_checks(RANGE_OPT_PARAM *param,
{
bool was_ored= FALSE;
*is_last_check_pass= is_first_check_pass;
- SEL_TREE** or_tree = trees;
+ SEL_TREE** or_tree= trees;
for (uint i= 0; i < n_trees; i++, or_tree++)
{
SEL_TREE *result= 0;
@@ -872,7 +872,7 @@ SEL_IMERGE::SEL_IMERGE(SEL_IMERGE *arg, uint cnt,
trees_next= trees + (cnt ? cnt : arg->trees_next-arg->trees);
trees_end= trees + elements;
- for (SEL_TREE **tree = trees, **arg_tree= arg->trees; tree < trees_next;
+ for (SEL_TREE **tree= trees, **arg_tree= arg->trees; tree < trees_next;
tree++, arg_tree++)
{
if (!(*tree= new SEL_TREE(*arg_tree, TRUE, param)))
@@ -2211,7 +2211,7 @@ class TABLE_READ_PLAN
@param trace_object The optimizer trace object the info is appended to
*/
virtual void trace_basic_info(const PARAM *param,
- Json_writer_object *trace_object) const = 0;
+ Json_writer_object *trace_object) const= 0;
};
@@ -2261,10 +2261,10 @@ void TRP_RANGE::trace_basic_info(const PARAM *param,
Json_writer_object *trace_object) const
{
DBUG_ASSERT(param->using_real_indexes);
- const uint keynr_in_table = param->real_keynr[key_idx];
+ const 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;
+ const KEY &cur_key= param->table->key_info[keynr_in_table];
+ const KEY_PART_INFO *key_part= cur_key.key_part;
trace_object->add("type", "range_scan")
.add("index", cur_key.name)
@@ -2329,7 +2329,7 @@ void TRP_ROR_UNION::trace_basic_info(const PARAM *param,
THD *thd= param->thd;
trace_object->add("type", "index_roworder_union");
Json_writer_array smth_trace(thd, "union_of");
- for (TABLE_READ_PLAN **current = first_ror; current != last_ror; current++)
+ for (TABLE_READ_PLAN **current= first_ror; current != last_ror; current++)
{
Json_writer_object trp_info(thd);
(*current)->trace_basic_info(param, &trp_info);
@@ -2364,7 +2364,7 @@ void TRP_INDEX_INTERSECT::trace_basic_info(const PARAM *param,
THD *thd= param->thd;
trace_object->add("type", "index_sort_intersect");
Json_writer_array smth_trace(thd, "index_sort_intersect_of");
- for (TRP_RANGE **current = range_scans; current != range_scans_end;
+ for (TRP_RANGE **current= range_scans; current != range_scans_end;
current++)
{
Json_writer_object trp_info(thd);
@@ -2466,9 +2466,9 @@ void TRP_GROUP_MIN_MAX::trace_basic_info(const PARAM *param,
trace_object->add("type", "index_group").add("index", index_info->name);
if (min_max_arg_part)
- trace_object->add("group_attribute", min_max_arg_part->field->field_name);
+ trace_object->add("min_max_arg", min_max_arg_part->field->field_name);
else
- trace_object->add_null("group_attribute");
+ trace_object->add_null("min_max_arg");
trace_object->add("min_aggregate", have_min)
.add("max_aggregate", have_max)
@@ -2476,12 +2476,12 @@ void TRP_GROUP_MIN_MAX::trace_basic_info(const PARAM *param,
.add("rows", records)
.add("cost", read_cost);
- const KEY_PART_INFO *key_part = index_info->key_part;
+ const KEY_PART_INFO *key_part= index_info->key_part;
{
Json_writer_array trace_keyparts(thd, "key_parts_used_for_access");
- for (uint partno = 0; partno < used_key_parts; partno++)
+ for (uint partno= 0; partno < used_key_parts; partno++)
{
- const KEY_PART_INFO *cur_key_part = key_part + partno;
+ const KEY_PART_INFO *cur_key_part= key_part + partno;
trace_keyparts.add(cur_key_part->field->field_name);
}
}
@@ -3437,7 +3437,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
{
rows= 0;
table->reginfo.impossible_range= 1;
- selectivity_for_column.add("selectivity_from_histograms", rows);
+ selectivity_for_column.add("selectivity_from_histogram", rows);
selectivity_for_column.add("cause", "impossible range");
goto free_alloc;
}
@@ -3447,7 +3447,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
if (rows != DBL_MAX)
{
key->field->cond_selectivity= rows/table_records;
- selectivity_for_column.add("selectivity_from_histograms",
+ selectivity_for_column.add("selectivity_from_histogram",
key->field->cond_selectivity);
}
}
@@ -3471,6 +3471,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
free_root(&alloc, MYF(0));
}
+ selectivity_for_columns.end();
if (quick && (quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
@@ -3545,7 +3546,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
table->cond_selectivity_sampling_explain= &dt->list;
}
}
-
+ trace_wrapper.add("cond_selectivity", table->cond_selectivity);
DBUG_RETURN(FALSE);
}
@@ -5071,7 +5072,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
trace_idx.add("chosen", false).add("cause", "cost");
continue;
}
- const uint keynr_in_table = param->real_keynr[(*cur_child)->key_idx];
+ const 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;
@@ -5132,7 +5133,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
*/
double rid_comp_cost= static_cast<double>(non_cpk_scan_records) /
TIME_FOR_COMPARE_ROWID;
- imerge_cost += rid_comp_cost;
+ imerge_cost+= rid_comp_cost;
trace_best_disjunct.add("cost_of_mapping_rowid_in_non_clustered_pk_scan",
rid_comp_cost);
}
@@ -5140,7 +5141,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
/* Calculate cost(rowid_to_row_scan) */
{
double sweep_cost= get_sweep_read_cost(param, non_cpk_scan_records);
- imerge_cost += sweep_cost;
+ imerge_cost+= sweep_cost;
trace_best_disjunct.add("cost_sort_rowid_and_read_disk", sweep_cost);
}
DBUG_PRINT("info",("index_merge cost with rowid-to-row scan: %g",
@@ -5167,7 +5168,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
}
{
- const double dup_removal_cost = Unique::get_use_cost(
+ const double dup_removal_cost= Unique::get_use_cost(
param->imerge_cost_buff, (uint)non_cpk_scan_records,
param->table->file->ref_length,
(size_t)param->thd->variables.sortbuff_size,
@@ -6369,11 +6370,11 @@ void TRP_ROR_INTERSECT::trace_basic_info(const PARAM *param,
trace_object->add("clustered_pk_scan", cpk_scan != NULL);
Json_writer_array smth_trace(thd, "intersect_of");
- for (ROR_SCAN_INFO **cur_scan = first_scan; cur_scan != last_scan;
+ for (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;
+ const KEY &cur_key= param->table->key_info[(*cur_scan)->keynr];
+ const KEY_PART_INFO *key_part= cur_key.key_part;
Json_writer_object trace_isect_idx(thd);
trace_isect_idx.add("type", "range_scan");
@@ -6381,15 +6382,15 @@ void TRP_ROR_INTERSECT::trace_basic_info(const PARAM *param,
trace_isect_idx.add("rows", (*cur_scan)->records);
Json_writer_array trace_range(thd, "ranges");
- for (const SEL_ARG *current = (*cur_scan)->sel_arg->first(); current;
- current = current->next)
+ for (const SEL_ARG *current= (*cur_scan)->sel_arg->first(); 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 ? part->next_key_part : nullptr)
+ for (const SEL_ARG *part= current; part;
+ part= part->next_key_part ? part->next_key_part : nullptr)
{
- const KEY_PART_INFO *cur_key_part = key_part + part->part;
+ const KEY_PART_INFO *cur_key_part= key_part + part->part;
append_range(&range_info, cur_key_part, part->min_value,
part->max_value, part->min_flag | part->max_flag);
}
@@ -6814,7 +6815,7 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
*/
const double idx_cost= rows2double(info->index_records) /
TIME_FOR_COMPARE_ROWID;
- info->index_scan_costs += idx_cost;
+ info->index_scan_costs+= idx_cost;
trace_costs->add("index_scan_cost", idx_cost);
}
else
@@ -6838,7 +6839,7 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
{
double sweep_cost= get_sweep_read_cost(info->param,
double2rows(info->out_rows));
- info->total_cost += sweep_cost;
+ info->total_cost+= sweep_cost;
trace_costs->add("disk_sweep_cost", sweep_cost);
DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
}
@@ -7369,8 +7370,8 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
{
Json_writer_array trace_range(thd, "ranges");
- const KEY &cur_key = param->table->key_info[keynr];
- const KEY_PART_INFO *key_part = cur_key.key_part;
+ const KEY &cur_key= param->table->key_info[keynr];
+ const KEY_PART_INFO *key_part= cur_key.key_part;
String range_info;
range_info.set_charset(system_charset_info);
@@ -13377,7 +13378,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field);
if (key_part_nr <= cur_group_key_parts)
{
- cause = "aggregate column not suffix in idx";
+ cause= "aggregate column not suffix in idx";
goto next_index;
}
min_max_arg_part= cur_index_info->key_part + key_part_nr - 1;
@@ -13431,7 +13432,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
&cur_key_infix_len,
&first_non_infix_part))
{
- cause = "nonconst equality gap attribute";
+ cause= "nonconst equality gap attribute";
goto next_index;
}
}
@@ -13442,7 +13443,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
There is a gap but no range tree, thus no predicates at all for the
non-group keyparts.
*/
- cause = "no nongroup keypart predicate";
+ cause= "no nongroup keypart predicate";
goto next_index;
}
else if (first_non_group_part && join->conds)
@@ -13467,7 +13468,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
key_part_range))
{
- cause = "keypart reference from where clause";
+ cause= "keypart reference from where clause";
goto next_index;
}
}
@@ -13485,7 +13486,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
{
if (bitmap_is_set(table->read_set, cur_part->field->field_index))
{
- cause = "keypart after infix in query";
+ cause= "keypart after infix in query";
goto next_index;
}
}
@@ -13504,7 +13505,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
index_range_tree, &cur_range) ||
(cur_range && cur_range->type != SEL_ARG::KEY_RANGE))
{
- cause = "minmax keypart in disjunctive query";
+ cause= "minmax keypart in disjunctive query";
goto next_index;
}
}
@@ -13531,7 +13532,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
{
Json_writer_array trace_range(thd, "ranges");
- const KEY_PART_INFO *key_part = cur_index_info->key_part;
+ const KEY_PART_INFO *key_part= cur_index_info->key_part;
String range_info;
range_info.set_charset(system_charset_info);
@@ -13571,7 +13572,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
if (cause)
{
trace_idx.add("usable", false).add("cause", cause);
- cause = NULL;
+ cause= NULL;
}
}
@@ -15769,9 +15770,9 @@ static void append_range_all_keyparts(Json_writer_array *range_trace,
DBUG_ASSERT(keypart && keypart != &null_element);
// Navigate to first interval in red-black tree
- const KEY_PART_INFO *cur_key_part = key_parts + keypart->part;
- const SEL_ARG *keypart_range = keypart->first();
- const size_t save_range_so_far_length = range_so_far->length();
+ const KEY_PART_INFO *cur_key_part= key_parts + keypart->part;
+ const SEL_ARG *keypart_range= keypart->first();
+ const size_t save_range_so_far_length= range_so_far->length();
while (keypart_range)
@@ -15820,9 +15821,10 @@ static void append_range_all_keyparts(Json_writer_array *range_trace,
static void print_key_value(String *out, const KEY_PART_INFO *key_part,
const uchar *key)
{
- Field *field = key_part->field;
+ Field *field= key_part->field;
- if (field->flags & BLOB_FLAG) {
+ if (field->flags & BLOB_FLAG)
+ {
// Byte 0 of a nullable key is the null-byte. If set, key is NULL.
if (field->real_maybe_null() && *key)
out->append(STRING_WITH_LEN("NULL"));
@@ -15833,7 +15835,7 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
return;
}
- uint store_length = key_part->store_length;
+ uint store_length= key_part->store_length;
if (field->real_maybe_null())
{
@@ -15842,7 +15844,8 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
Otherwise, print the key value starting immediately after the
null-byte
*/
- if (*key) {
+ if (*key)
+ {
out->append(STRING_WITH_LEN("NULL"));
return;
}
@@ -15855,9 +15858,11 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
optimizer trace expects. If the column is binary, the hex
representation is printed to the trace instead.
*/
- if (field->flags & BINARY_FLAG) {
+ if (field->flags & BINARY_FLAG)
+ {
out->append("0x");
- for (uint i = 0; i < store_length; i++) {
+ for (uint i = 0; i < store_length; i++)
+ {
out->append(_dig_vec_lower[*(key + i) >> 4]);
out->append(_dig_vec_lower[*(key + i) & 0x0F]);
}
@@ -15865,7 +15870,7 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
}
StringBuffer<128> tmp(system_charset_info);
- TABLE *table = field->table;
+ TABLE *table= field->table;
my_bitmap_map *old_sets[2];
dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 228fcd0f7e6..bfb608edc47 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -456,6 +456,7 @@ void best_access_path(JOIN *join, JOIN_TAB *s,
table_map remaining_tables, uint idx,
bool disable_jbuf, double record_count,
POSITION *pos, POSITION *loose_scan_pos);
+void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
Item_in_subselect *subq_pred);
@@ -697,9 +698,10 @@ 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,
+ OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
+ select_lex->select_number,
"IN (SELECT)", "semijoin");
- oto1.add("chosen", true);
+ trace_transform.add("chosen", true);
}
}
else
@@ -840,7 +842,7 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
in_subs->types_allow_materialization= FALSE; // Assign default values
in_subs->sjm_scan_allowed= FALSE;
- OPT_TRACE_TRANSFORM(thd, oto0, oto1,
+ OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
in_subs->get_select_lex()->select_number,
"IN (SELECT)", "materialization");
@@ -856,8 +858,8 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
if (!inner->type_handler()->subquery_type_allows_materialization(inner,
outer))
{
- oto1.add("possible", false);
- oto1.add("cause", "types mismatch");
+ trace_transform.add("possible", false);
+ trace_transform.add("cause", "types mismatch");
DBUG_RETURN(FALSE);
}
}
@@ -879,12 +881,12 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
{
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);
+ trace_transform.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);
+ trace_transform.add("possible", false).add("cause", cause);
DBUG_RETURN(FALSE);
}
@@ -1236,29 +1238,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,
+ OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
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");
+ trace_transform.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,
+ OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
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");
+ trace_transform.add("converted_to_semi_join", false);
+ trace_transform.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);
+ trace_transform.add("converted_to_semi_join", true);
}
else
{
@@ -2380,6 +2383,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
THD *thd= join->thd;
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
TABLE_LIST *sj_nest;
+ if (!join->select_lex->sj_nests.elements)
+ DBUG_RETURN(FALSE);
Json_writer_object wrapper(thd);
Json_writer_object trace_semijoin_nest(thd,
"execution_plan_for_potential_materialization");
@@ -2939,6 +2944,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
{
bool sjm_scan;
SJ_MATERIALIZATION_INFO *mat_info;
+ THD *thd= join->thd;
if ((mat_info= at_sjmat_pos(join, remaining_tables,
new_join_tab, idx, &sjm_scan)))
{
@@ -3040,6 +3046,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
POSITION curpos, dummy;
/* Need to re-run best-access-path as we prefix_rec_count has changed */
bool disable_jbuf= (join->thd->variables.join_cache_level == 0);
+ Json_writer_temp_disable trace_semijoin_mat_scan(thd);
for (i= first_tab + mat_info->tables; i <= idx; i++)
{
best_access_path(join, join->positions[i].table, rem_tables, i,
@@ -3082,6 +3089,7 @@ bool LooseScan_picker::check_qep(JOIN *join,
struct st_position *loose_scan_pos)
{
POSITION *first= join->positions + first_loosescan_table;
+ THD *thd= join->thd;
/*
LooseScan strategy can't handle interleaving between tables from the
semi-join that LooseScan is handling and any other tables.
@@ -3173,6 +3181,7 @@ bool Firstmatch_picker::check_qep(JOIN *join,
sj_strategy_enum *strategy,
POSITION *loose_scan_pos)
{
+ THD *thd= join->thd;
if (new_join_tab->emb_sj_nest &&
optimizer_flag(join->thd, OPTIMIZER_SWITCH_FIRSTMATCH) &&
!join->outer_join)
@@ -3590,6 +3599,11 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
table_map handled_tabs= 0;
join->sjm_lookup_tables= 0;
join->sjm_scan_tables= 0;
+ THD *thd= join->thd;
+ if (!join->select_lex->sj_nests.elements)
+ return;
+ Json_writer_object trace_wrapper(thd);
+ Json_writer_object trace_semijoin(thd, "fix_semijoin_strategies_for_picked_join_order");
for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
{
POSITION *pos= join->best_positions + tablenr;
@@ -3614,8 +3628,16 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
first= tablenr - sjm->tables + 1;
join->best_positions[first].n_sj_tables= sjm->tables;
join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE;
+ Json_writer_array semijoin_strategy(thd, "sj_materialzation");
for (uint i= first; i < first+ sjm->tables; i++)
+ {
+ if (unlikely(thd->trace_started()))
+ {
+ Json_writer_object trace_one_table(thd);
+ trace_one_table.add_table_name(join->best_positions[i].table);
+ }
join->sjm_lookup_tables |= join->best_positions[i].table->table->map;
+ }
}
else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
{
@@ -3653,8 +3675,14 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
POSITION dummy;
join->cur_sj_inner_tables= 0;
+ Json_writer_array semijoin_strategy(thd, "sj_materialzation_scan");
for (i= first + sjm->tables; i <= tablenr; i++)
{
+ if (unlikely(thd->trace_started()))
+ {
+ Json_writer_object trace_one_table(thd);
+ trace_one_table.add_table_name(join->best_positions[i].table);
+ }
best_access_path(join, join->best_positions[i].table, rem_tables, i,
FALSE, prefix_rec_count,
join->best_positions + i, &dummy);
@@ -3683,8 +3711,14 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
join buffering
*/
join->cur_sj_inner_tables= 0;
+ Json_writer_array semijoin_strategy(thd, "first_match_strategy");
for (idx= first; idx <= tablenr; idx++)
{
+ if (unlikely(thd->trace_started()))
+ {
+ Json_writer_object trace_one_table(thd);
+ trace_one_table.add_table_name(join->best_positions[idx].table);
+ }
if (join->best_positions[idx].use_join_buffer)
{
best_access_path(join, join->best_positions[idx].table,
@@ -3713,8 +3747,14 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
join buffering
*/
join->cur_sj_inner_tables= 0;
+ Json_writer_array semijoin_strategy(thd, "loosecan_strategy");
for (idx= first; idx <= tablenr; idx++)
{
+ if (unlikely(thd->trace_started()))
+ {
+ Json_writer_object trace_one_table(thd);
+ trace_one_table.add_table_name(join->best_positions[idx].table);
+ }
if (join->best_positions[idx].use_join_buffer || (idx == first))
{
best_access_path(join, join->best_positions[idx].table,
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index 03516146de2..422b21cb541 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -525,7 +525,7 @@ eliminate_tables_for_list(JOIN *join,
table_map tables_in_list,
Item *on_expr,
table_map tables_used_elsewhere,
- Json_writer_array* eliminate_tables);
+ Json_writer_array* trace_eliminate_tables);
static
bool check_func_dependency(JOIN *join,
table_map dep_tables,
@@ -545,7 +545,7 @@ 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,
- Json_writer_array* eliminate_tables);
+ Json_writer_array* trace_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,
@@ -671,12 +671,12 @@ void eliminate_tables(JOIN *join)
}
table_map all_tables= join->all_tables_map();
- Json_writer_array eliminated_tables(thd,"eliminated_tables");
+ Json_writer_array trace_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, &eliminated_tables);
+ used_tables, &trace_eliminated_tables);
}
DBUG_VOID_RETURN;
}
@@ -720,7 +720,7 @@ 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,
- Json_writer_array *eliminate_tables)
+ Json_writer_array *trace_eliminate_tables)
{
TABLE_LIST *tbl;
List_iterator<TABLE_LIST> it(*join_list);
@@ -742,9 +742,10 @@ 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, eliminate_tables))
+ outside_used_tables,
+ trace_eliminate_tables))
{
- mark_as_eliminated(join, tbl, eliminate_tables);
+ mark_as_eliminated(join, tbl, trace_eliminate_tables);
}
else
all_eliminated= FALSE;
@@ -756,7 +757,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, eliminate_tables);
+ mark_as_eliminated(join, tbl, trace_eliminate_tables);
}
else
all_eliminated= FALSE;
@@ -1797,7 +1798,7 @@ Dep_module* Dep_value_field::get_next_unbound_module(Dep_analysis_context *dac,
*/
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
- Json_writer_array* eliminate_tables)
+ Json_writer_array* trace_eliminate_tables)
{
TABLE *table;
/*
@@ -1810,7 +1811,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, eliminate_tables);
+ mark_as_eliminated(join, child, trace_eliminate_tables);
}
else if ((table= tbl->table))
{
@@ -1821,7 +1822,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());
+ trace_eliminate_tables->add(table->alias.c_ptr_safe());
join->const_table_map|= table->map;
set_position(join, join->const_tables++, tab, (KEYUSE*)0);
}
diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc
index ca05f36579a..befc7934a3a 100644
--- a/sql/opt_trace.cc
+++ b/sql/opt_trace.cc
@@ -24,7 +24,7 @@
#include "my_json_writer.h"
#include "sp_head.h"
-const char I_S_table_name[] = "OPTIMIZER_TRACE";
+const char I_S_table_name[]= "OPTIMIZER_TRACE";
/**
Whether a list of tables contains information_schema.OPTIMIZER_TRACE.
@@ -38,7 +38,7 @@ const char I_S_table_name[] = "OPTIMIZER_TRACE";
*/
bool list_has_optimizer_trace_table(const TABLE_LIST *tbl)
{
- for (; tbl; tbl = tbl->next_global)
+ for (; tbl; tbl= tbl->next_global)
{
if (tbl->schema_table &&
0 == strcmp(tbl->schema_table->table_name, I_S_table_name))
@@ -59,14 +59,15 @@ bool sets_var_optimizer_trace(enum enum_sql_command sql_command,
{
List_iterator_fast<set_var_base> it(*set_vars);
const set_var_base *var;
- while ((var = it++))
+ while ((var= it++))
if (var->is_var_optimizer_trace()) return true;
}
return false;
}
-ST_FIELD_INFO optimizer_trace_info[] = {
+ST_FIELD_INFO optimizer_trace_info[]=
+{
/* name, length, type, value, maybe_null, old_name, open_method */
{"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
{"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
@@ -74,12 +75,13 @@ ST_FIELD_INFO optimizer_trace_info[] = {
SKIP_OPEN_TABLE},
{"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL,
SKIP_OPEN_TABLE},
- {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}};
+ {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
+};
/*
TODO: one-line needs to be implemented seperately
*/
-const char *Opt_trace_context::flag_names[] = {"enabled", "default",
+const char *Opt_trace_context::flag_names[]= {"enabled", "default",
NullS};
/*
@@ -105,15 +107,15 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
{
if (!thd->trace_started())
return;
- char buff[1024];
- String str(buff, sizeof(buff), system_charset_info);
- str.length(0);
+ StringBuffer<1024> str(system_charset_info);
+ ulonglong save_option_bits= thd->variables.option_bits;
+ thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
select_lex->print(thd, &str,
enum_query_type(QT_TO_SYSTEM_CHARSET |
QT_SHOW_SELECT_NUMBER |
QT_ITEM_IDENT_SKIP_DB_NAMES |
- QT_VIEW_INTERNAL
- ));
+ QT_VIEW_INTERNAL));
+ thd->variables.option_bits= save_option_bits;
/*
The output is not very pretty lots of back-ticks, the output
is as the one in explain extended , lets try to improved it here.
@@ -141,7 +143,7 @@ void opt_trace_disable_if_no_security_context_access(THD *thd)
*/
return;
}
- Opt_trace_context *const trace = &thd->opt_trace;
+ Opt_trace_context *const trace= &thd->opt_trace;
if (!thd->trace_started())
{
/*
@@ -187,7 +189,6 @@ void opt_trace_disable_if_no_security_context_access(THD *thd)
thd->main_security_ctx.priv_host,
thd->security_context()->priv_host)))
trace->missing_privilege();
- return;
}
void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
@@ -197,17 +198,16 @@ void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
thd->system_thread)
return;
- Opt_trace_context *const trace = &thd->opt_trace;
+ Opt_trace_context *const trace= &thd->opt_trace;
if (!thd->trace_started())
return;
bool full_access;
- Security_context *const backup_thd_sctx = thd->security_context();
+ Security_context *const backup_thd_sctx= thd->security_context();
thd->set_security_context(&thd->main_security_ctx);
- const bool rc = check_show_routine_access(thd, sp, &full_access) || !full_access;
+ const bool rc= check_show_routine_access(thd, sp, &full_access) || !full_access;
thd->set_security_context(backup_thd_sctx);
if (rc)
trace->missing_privilege();
- return;
}
/**
@@ -231,16 +231,16 @@ void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
if (likely(!(thd->variables.optimizer_trace &
Opt_trace_context::FLAG_ENABLED)) || thd->system_thread)
return;
- Opt_trace_context *const trace = &thd->opt_trace;
+ Opt_trace_context *const trace= &thd->opt_trace;
if (!thd->trace_started())
return;
- Security_context *const backup_thd_sctx = thd->security_context();
+ Security_context *const backup_thd_sctx= thd->security_context();
thd->set_security_context(&thd->main_security_ctx);
- const TABLE_LIST *const first_not_own_table = thd->lex->first_not_own_table();
- for (TABLE_LIST *t = tbl; t != NULL && t != first_not_own_table;
- t = t->next_global)
+ const TABLE_LIST *const first_not_own_table= thd->lex->first_not_own_table();
+ for (TABLE_LIST *t= tbl; t != NULL && t != first_not_own_table;
+ t= t->next_global)
{
/*
Anonymous derived tables (as in
@@ -248,9 +248,9 @@ void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
*/
if (!t->is_anonymous_derived_table())
{
- const GRANT_INFO backup_grant_info = t->grant;
- Security_context *const backup_table_sctx = t->security_ctx;
- t->security_ctx = NULL;
+ const GRANT_INFO backup_grant_info= t->grant;
+ Security_context *const backup_table_sctx= t->security_ctx;
+ t->security_ctx= NULL;
/*
(1) check_table_access() fills t->grant.privilege.
(2) Because SELECT privileges can be column-based,
@@ -271,8 +271,8 @@ void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
*/
rc |= check_table_access(thd, SHOW_VIEW_ACL, t, false, 1, true);
}
- t->security_ctx = backup_table_sctx;
- t->grant = backup_grant_info;
+ t->security_ctx= backup_table_sctx;
+ t->grant= backup_grant_info;
if (rc)
{
trace->missing_privilege();
@@ -292,22 +292,22 @@ void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view,
Opt_trace_context::FLAG_ENABLED)) ||
thd->system_thread)
return;
- Opt_trace_context *const trace = &thd->opt_trace;
+ Opt_trace_context *const trace= &thd->opt_trace;
if (!thd->trace_started())
return;
- Security_context *const backup_table_sctx = view->security_ctx;
- Security_context *const backup_thd_sctx = thd->security_context();
- const GRANT_INFO backup_grant_info = view->grant;
+ Security_context *const backup_table_sctx= view->security_ctx;
+ Security_context *const backup_thd_sctx= thd->security_context();
+ const GRANT_INFO backup_grant_info= view->grant;
- view->security_ctx = NULL; // no SUID context for view
+ view->security_ctx= NULL; // no SUID context for view
// no SUID context for THD
thd->set_security_context(&thd->main_security_ctx);
- const int rc = check_table_access(thd, SHOW_VIEW_ACL, view, false, 1, true);
+ const int rc= check_table_access(thd, SHOW_VIEW_ACL, view, false, 1, true);
- view->security_ctx = backup_table_sctx;
+ view->security_ctx= backup_table_sctx;
thd->set_security_context(backup_thd_sctx);
- view->grant = backup_grant_info;
+ view->grant= backup_grant_info;
if (rc)
{
@@ -347,16 +347,13 @@ class Opt_trace_stmt {
~Opt_trace_stmt()
{
delete current_json;
- missing_priv= false;
- ctx= NULL;
- I_S_disabled= 0;
}
void set_query(const char *query_ptr, size_t length, const CHARSET_INFO *charset);
void open_struct(const char *key, char opening_bracket);
void close_struct(const char *saved_key, char closing_bracket);
void fill_info(Opt_trace_info* info);
void add(const char *key, char *opening_bracket, size_t val_length);
- Json_writer* get_current_json(){return current_json;}
+ Json_writer* get_current_json() {return current_json;}
void missing_privilege();
void disable_tracing_for_children();
void enable_tracing_for_children();
@@ -372,6 +369,12 @@ class Opt_trace_stmt {
String query; // store the query sent by the user
Json_writer *current_json; // stores the trace
bool missing_priv; ///< whether user lacks privilege to see this trace
+ /*
+ 0 <=> this trace should be in information_schema.
+ !=0 tracing is disabled, this currently happens when we want to trace a
+ sub-statement. For now traces are only collect for the top statement
+ not for the sub-statments.
+ */
uint I_S_disabled;
};
@@ -440,28 +443,11 @@ bool Opt_trace_context::is_enabled()
Opt_trace_context::Opt_trace_context()
{
current_trace= NULL;
- inited= FALSE;
- traces= NULL;
max_mem_size= 0;
}
Opt_trace_context::~Opt_trace_context()
{
- inited= FALSE;
- /*
- would be nice to move this to a function
- */
- if (traces)
- {
- while (traces->elements())
- {
- Opt_trace_stmt *prev= traces->at(0);
- delete prev;
- traces->del(0);
- }
- delete traces;
- traces= NULL;
- }
- max_mem_size= 0;
+ delete_traces();
}
void Opt_trace_context::set_query(const char *query, size_t length, const CHARSET_INFO *charset)
@@ -487,26 +473,21 @@ void Opt_trace_context::start(THD *thd, TABLE_LIST *tbl,
DBUG_ASSERT(!current_trace);
current_trace= new Opt_trace_stmt(this);
max_mem_size= max_mem_size_arg;
- if (!inited)
- {
- traces= new Dynamic_array<Opt_trace_stmt*>();
- inited= TRUE;
- }
set_allowed_mem_size(remaining_mem_size());
}
void Opt_trace_context::end()
{
if (current_trace)
- traces->push(current_trace);
+ traces.push(current_trace);
- if (!traces->elements())
+ if (!traces.elements())
return;
- if (traces->elements() > 1)
+ if (traces.elements() > 1)
{
- Opt_trace_stmt *prev= traces->at(0);
+ Opt_trace_stmt *prev= traces.at(0);
delete prev;
- traces->del(0);
+ traces.del(0);
}
current_trace= NULL;
}
@@ -522,7 +503,7 @@ Opt_trace_start::Opt_trace_start(THD *thd, TABLE_LIST *tbl,
if optimizer trace is enabled and the statment we have is traceable,
then we start the context.
*/
- const ulonglong var = thd->variables.optimizer_trace;
+ const ulonglong var= thd->variables.optimizer_trace;
traceable= FALSE;
if (unlikely(var & Opt_trace_context::FLAG_ENABLED) &&
sql_command_can_be_traced(sql_command) &&
@@ -554,21 +535,21 @@ Opt_trace_start::~Opt_trace_start()
void Opt_trace_stmt::fill_info(Opt_trace_info* info)
{
- if (unlikely(info->missing_priv = get_missing_priv()))
+ if (unlikely(info->missing_priv= get_missing_priv()))
{
- info->trace_ptr = info->query_ptr = "";
- info->trace_length = info->query_length = 0;
- info->query_charset = &my_charset_bin;
- info->missing_bytes = 0;
+ info->trace_ptr= info->query_ptr= "";
+ info->trace_length= info->query_length= 0;
+ info->query_charset= &my_charset_bin;
+ info->missing_bytes= 0;
}
else
{
- info->trace_ptr = current_json->output.get_string()->ptr();
- info->trace_length = get_length();
- info->query_ptr = query.ptr();
- info->query_length = query.length();
- info->query_charset = query.charset();
- info->missing_bytes = get_truncated_bytes();
+ info->trace_ptr= current_json->output.get_string()->ptr();
+ info->trace_length= get_length();
+ info->query_ptr= query.ptr();
+ info->query_length= query.length();
+ info->query_charset= query.charset();
+ info->missing_bytes= get_truncated_bytes();
info->missing_priv= get_missing_priv();
}
}
@@ -659,9 +640,7 @@ void Json_writer::add_str(Item *item)
if (item)
{
THD *thd= current_thd;
- char buff[256];
- String str(buff, sizeof(buff), system_charset_info);
- str.length(0);
+ StringBuffer<256> str(system_charset_info);
ulonglong save_option_bits= thd->variables.option_bits;
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
@@ -675,26 +654,23 @@ void Json_writer::add_str(Item *item)
add_null();
}
-void Opt_trace_context::flush_optimizer_trace()
+void Opt_trace_context::delete_traces()
{
- inited= false;
- if (traces)
+ if (traces.elements())
{
- while (traces->elements())
+ while (traces.elements())
{
- Opt_trace_stmt *prev= traces->at(0);
+ Opt_trace_stmt *prev= traces.at(0);
delete prev;
- traces->del(0);
+ traces.del(0);
}
- delete traces;
- traces= NULL;
}
}
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *)
{
- TABLE *table = tables->table;
+ TABLE *table= tables->table;
Opt_trace_info info;
/* get_values of trace, query , missing bytes and missing_priv
@@ -703,7 +679,7 @@ int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *)
*/
Opt_trace_context* ctx= &thd->opt_trace;
- if (thd->opt_trace.empty())
+ if (!thd->opt_trace.empty())
{
Opt_trace_stmt *stmt= ctx->get_top_trace();
stmt->fill_info(&info);
diff --git a/sql/opt_trace.h b/sql/opt_trace.h
index 0e2d0146a49..52318bc6b7f 100644
--- a/sql/opt_trace.h
+++ b/sql/opt_trace.h
@@ -193,9 +193,16 @@ void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp);
*/
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *);
-#define OPT_TRACE_TRANSFORM(writer, object_level0, object_level1, \
+#define OPT_TRACE_TRANSFORM(thd, object_level0, object_level1, \
select_number, from, to) \
- Json_writer_object object_level0(writer); \
- Json_writer_object object_level1(writer, "transformation"); \
+ Json_writer_object object_level0(thd); \
+ Json_writer_object object_level1(thd, "transformation"); \
object_level1.add_select_number(select_number).add("from", from).add("to", to);
-#endif
\ No newline at end of file
+
+#define OPT_TRACE_VIEWS_TRANSFORM(thd, object_level0, object_level1, \
+ derived, name, select_number, algorithm) \
+ Json_writer_object trace_wrapper(thd); \
+ Json_writer_object trace_derived(thd, derived); \
+ trace_derived.add("table", name).add_select_number(select_number) \
+ .add("algorithm", algorithm);
+#endif
diff --git a/sql/opt_trace_context.h b/sql/opt_trace_context.h
index 87317f67e22..e5df16b1e3b 100644
--- a/sql/opt_trace_context.h
+++ b/sql/opt_trace_context.h
@@ -19,14 +19,14 @@ class Opt_trace_context
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 delete_traces();
void set_allowed_mem_size(size_t mem_size);
size_t remaining_mem_size();
private:
Opt_trace_stmt* top_trace()
{
- return *(traces->front());
+ return *(traces.front());
}
public:
@@ -39,7 +39,7 @@ class Opt_trace_context
Opt_trace_stmt* get_top_trace()
{
- if (!traces || !traces->elements())
+ if (!traces.elements())
return NULL;
return top_trace();
}
@@ -52,7 +52,7 @@ class Opt_trace_context
bool empty()
{
- return traces && (static_cast<uint>(traces->elements()) != 0);
+ return static_cast<uint>(traces.elements()) == 0;
}
bool is_started()
@@ -79,13 +79,8 @@ class Opt_trace_context
/*
List of traces (currently it stores only 1 trace)
*/
- Dynamic_array<Opt_trace_stmt*> *traces;
+ 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;
};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 97e3bde97dd..33562e47793 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1411,7 +1411,7 @@ void THD::change_user(void)
sp_cache_clear(&sp_func_cache);
sp_cache_clear(&sp_package_spec_cache);
sp_cache_clear(&sp_package_body_cache);
- opt_trace.flush_optimizer_trace();
+ opt_trace.delete_traces();
}
/**
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index a3a53320ac0..6bfcd40f411 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -34,6 +34,7 @@
#include "sql_class.h"
#include "sql_cte.h"
#include "my_json_writer.h"
+#include "opt_trace.h"
typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived);
@@ -384,6 +385,15 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
{
/* There is random function => fall back to materialization. */
cause= "Random function in the select";
+ if (unlikely(thd->trace_started()))
+ {
+ OPT_TRACE_VIEWS_TRANSFORM(thd, trace_wrapper, trace_derived,
+ derived->is_derived() ? "derived" : "view",
+ derived->alias.str ? derived->alias.str : "<NULL>",
+ derived->get_unit()->first_select()->select_number,
+ "materialized");
+ trace_derived.add("cause", cause);
+ }
derived->change_refs_to_fields();
derived->set_materialized_derived();
DBUG_RETURN(FALSE);
@@ -497,19 +507,12 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
if (unlikely(thd->trace_started()))
{
- /*
- Add to the optimizer trace the change in choice for merged
- derived tables/views to materialised ones.
- */
- Json_writer_object trace_wrapper(thd);
- Json_writer_object trace_derived(thd, derived->is_derived() ?
- "derived" : "view");
- trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
- .add_select_number(derived->get_unit()->
- first_select()->select_number)
- .add("initial_choice", "merged")
- .add("final_choice", "materialized")
- .add("cause", cause);
+ OPT_TRACE_VIEWS_TRANSFORM(thd,trace_wrapper, trace_derived,
+ derived->is_derived() ? "derived" : "view",
+ derived->alias.str ? derived->alias.str : "<NULL>",
+ derived->get_unit()->first_select()->select_number,
+ "materialized");
+ trace_derived.add("cause", cause);
}
derived->change_refs_to_fields();
@@ -778,15 +781,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
Add to optimizer trace whether a derived table/view
is merged into the parent select or not.
*/
- Json_writer_object trace_wrapper(thd);
- Json_writer_object trace_derived(thd, derived->is_derived() ?
- "derived" : "view");
- trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
- .add_select_number(derived->get_unit()->first_select()->select_number);
- if (derived->is_materialized_derived())
- trace_derived.add("materialized", true);
- if (derived->is_merged_derived())
- trace_derived.add("merged", true);
+ OPT_TRACE_VIEWS_TRANSFORM(thd, trace_wrapper, trace_derived,
+ derived->is_derived() ? "derived" : "view",
+ derived->alias.str ? derived->alias.str : "<NULL>",
+ derived->get_unit()->first_select()->select_number,
+ derived->is_merged_derived() ? "merged" : "materialized");
}
/*
Above cascade call of prepare is important for PS protocol, but after it
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1f12490b49f..6afcec3c2f2 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -117,6 +117,7 @@ static bool best_extension_by_limited_search(JOIN *join,
double read_time, uint depth,
uint prune_level,
uint use_cond_selectivity);
+void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
static uint determine_search_depth(JOIN* join);
C_MODE_START
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
@@ -298,8 +299,6 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab);
static Item **get_sargable_cond(JOIN *join, TABLE *table);
-static void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
-
#ifndef DBUG_OFF
/*
@@ -355,16 +354,16 @@ static void trace_table_dependencies(THD *thd,
{
Json_writer_object trace_wrapper(thd);
Json_writer_array trace_dep(thd, "table_dependencies");
- for (uint i = 0; i < table_count; i++)
+ for (uint i= 0; i < table_count; i++)
{
- TABLE_LIST *table_ref = join_tabs[i].tab_list;
+ TABLE_LIST *table_ref= join_tabs[i].tab_list;
Json_writer_object trace_one_table(thd);
trace_one_table.add_table_name(&join_tabs[i]);
trace_one_table.add("row_may_be_null",
(bool)table_ref->table->maybe_null);
- const table_map map = table_ref->get_map();
+ const table_map map= table_ref->get_map();
DBUG_ASSERT(map < (1ULL << table_count));
- for (uint j = 0; j < table_count; j++)
+ for (uint j= 0; j < table_count; j++)
{
if (map & (1ULL << j))
{
@@ -373,14 +372,10 @@ static void trace_table_dependencies(THD *thd,
}
}
Json_writer_array depends_on(thd, "depends_on_map_bits");
- static_assert(sizeof(table_ref->get_map()) <= 64,
- "RAND_TABLE_BIT may be in join_tabs[i].dependent, so we test "
- "all 64 bits.");
- for (uint j = 0; j < 64; j++)
- {
- if (join_tabs[i].dependent & (1ULL << j))
- depends_on.add(static_cast<longlong>(j));
- }
+ Table_map_iterator it(join_tabs[i].dependent);
+ uint dep_bit;
+ while ((dep_bit= it++) != Table_map_iterator::BITMAP_END)
+ depends_on.add(static_cast<longlong>(dep_bit));
}
}
@@ -8866,13 +8861,13 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
}
-static void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables)
+void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables)
{
- THD *const thd = join->thd;
+ THD *const thd= join->thd;
Json_writer_array plan_prefix(thd, "plan_prefix");
- for (uint i = 0; i < idx; i++)
+ for (uint i= 0; i < idx; i++)
{
- TABLE_LIST *const tr = join->positions[i].table->tab_list;
+ TABLE_LIST *const tr= join->positions[i].table->tab_list;
if (!(tr->map & remaining_tables))
plan_prefix.add_table_name(join->positions[i].table);
}
@@ -9075,9 +9070,6 @@ best_extension_by_limited_search(JOIN *join,
current_read_time=read_time + position->read_time +
current_record_count / (double) TIME_FOR_COMPARE;
- /*
- TODO add filtering estimates here
- */
advance_sj_state(join, remaining_tables, idx, ¤t_record_count,
¤t_read_time, &loose_scan_pos);
@@ -10881,12 +10873,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->table->intersect_keys.is_set(tab->ref.key))))
{
/* Range uses longer key; Use this instead of ref on key */
-
- /*
- We can trace here, changing ref access to range access here
- have a range that uses longer key.
- Lets take @spetrunia's opinion
- */
Json_writer_object ref_to_range(thd);
ref_to_range.add("ref_to_range", true);
ref_to_range.add("cause", "range uses longer key");
@@ -16183,6 +16169,8 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
double cost, rec_count;
table_map reopt_remaining_tables= last_remaining_tables;
uint i;
+ THD *thd= join->thd;
+ Json_writer_temp_disable trace_wo_join_buffering(thd);
if (first_tab > join->const_tables)
{
@@ -16217,7 +16205,7 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
{
JOIN_TAB *rs= join->positions[i].table;
POSITION pos, loose_scan_pos;
-
+
if ((i == first_tab && first_alt) || join->positions[i].use_join_buffer)
{
/* Find the best access method that would not use join buffering */
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index f247fb10f89..93085251711 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -665,11 +665,11 @@ void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array)
KEYUSE *keyuse= (KEYUSE*)dynamic_array_ptr(keyuse_array, i);
Json_writer_object keyuse_elem(thd);
keyuse_elem.add_table_name(keyuse->table->reginfo.join_tab);
- keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>"
- : (keyuse->is_for_hash_join()
- ? keyuse->table->field[keyuse->keypart]
- ->field_name.str
- : keyuse->table->key_info[keyuse->key]
+ keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>":
+ (keyuse->is_for_hash_join() ?
+ keyuse->table->field[keyuse->keypart]
+ ->field_name.str :
+ keyuse->table->key_info[keyuse->key]
.key_part[keyuse->keypart]
.field->field_name.str));
keyuse_elem.add("equals",keyuse->val);
1
0
[Commits] [PATCH] Implement avg_frequency unsmoothed jacknife estimator
by Vicențiu Ciorbaru 16 Feb '19
by Vicențiu Ciorbaru 16 Feb '19
16 Feb '19
When sampling data through ANALYZE TABLE, use the estimator to get a
better estimation of avg_frequency instead of just using the raw
sampled data.
---
mysql-test/main/statistics.result | 6 +-
sql/sql_statistics.cc | 106 +++++++++++++++++++++++-------
2 files changed, 85 insertions(+), 27 deletions(-)
diff --git a/mysql-test/main/statistics.result b/mysql-
test/main/statistics.result
index 01176b8d6cf..ed31ce94936 100644
--- a/mysql-test/main/statistics.result
+++ b/mysql-test/main/statistics.result
@@ -1810,7 +1810,7 @@ select table_name, column_name, min_value,
max_value, nulls_ratio, avg_length, a
DECODE_HISTOGRAM(hist_type, histogram)
from mysql.column_stats;
table_name column_name min_value max_value nulls_r
atio avg_length avg_frequency DECODE_HISTOGRAM(hist_type,
histogram)
-t1 id 111 17026 0.0000 4.0000 1.0047 0.039,0.098,0.0
55,0.118,0.078,0.157,0.082,0.118,0.094,0.063,0.098
+t1 id 111 17026 0.0000 4.0000 1004.7393 0.039,0
.098,0.055,0.118,0.078,0.157,0.082,0.118,0.094,0.063,0.098
#
# This query will show a better avg_frequency value.
#
@@ -1823,7 +1823,7 @@ select table_name, column_name, min_value,
max_value, nulls_ratio, avg_length, a
DECODE_HISTOGRAM(hist_type, histogram)
from mysql.column_stats;
table_name column_name min_value max_value nulls_r
atio avg_length avg_frequency DECODE_HISTOGRAM(hist_type,
histogram)
-t1 id 1 17384 0.0000 4.0000 3.5736 0.082,0.086,0.0
86,0.082,0.086,0.145,0.086,0.086,0.082,0.086,0.090
+t1 id 1 17384 0.0000 4.0000 14.2943
0.082,0.086,0.086,0.082,0.086,0.145,0.086,0.086,0.082,0.086,0.090
set analyze_sample_percentage=0;
#
# Test self adjusting sampling level.
@@ -1836,7 +1836,7 @@ select table_name, column_name, min_value,
max_value, nulls_ratio, avg_length, a
DECODE_HISTOGRAM(hist_type, histogram)
from mysql.column_stats;
table_name column_name min_value max_value nulls_r
atio avg_length avg_frequency DECODE_HISTOGRAM(hist_type,
histogram)
-t1 id 1 17384 0.0000 4.0000 7.4523 0.082,0.090,0.0
86,0.082,0.086,0.145,0.086,0.082,0.086,0.086,0.086
+t1 id 1 17384 0.0000 4.0000 13.9816
0.082,0.090,0.086,0.082,0.086,0.145,0.086,0.082,0.086,0.086,0.086
#
# Test record estimation is working properly.
#
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 27fab974441..8018c41a192 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -325,7 +325,7 @@ class Column_statistics_collected :public
Column_statistics
inline void init(THD *thd, Field * table_field);
inline bool add();
- inline void finish(ha_rows rows);
+ inline void finish(ha_rows rows, double sample_fraction);
inline void cleanup();
};
@@ -1540,6 +1540,8 @@ class Histogram_builder
uint curr_bucket; /* number of the current bucket to be
built */
ulonglong count; /* number of values
retrieved */
ulonglong count_distinct; /* number of distinct values
retrieved */
+ /* number of distinct values that occured only once */
+ ulonglong count_distinct_single_occurence;
public:
Histogram_builder(Field *col, uint col_len, ha_rows rows)
@@ -1553,14 +1555,21 @@ class Histogram_builder
bucket_capacity= (double) records / (hist_width + 1);
curr_bucket= 0;
count= 0;
- count_distinct= 0;
+ count_distinct= 0;
+ count_distinct_single_occurence= 0;
}
- ulonglong get_count_distinct() { return count_distinct; }
+ ulonglong get_count_distinct() const { return count_distinct; }
+ ulonglong get_count_single_occurence() const
+ {
+ return count_distinct_single_occurence;
+ }
int next(void *elem, element_count elem_cnt)
{
count_distinct++;
+ if (elem_cnt == 1)
+ count_distinct_single_occurence++;
count+= elem_cnt;
if (curr_bucket == hist_width)
return 0;
@@ -1574,7 +1583,7 @@ class Histogram_builder
count > bucket_capacity * (curr_bucket + 1))
{
histogram->set_prev_value(curr_bucket);
- curr_bucket++;
+ curr_bucket++;
}
}
return 0;
@@ -1590,9 +1599,18 @@ int histogram_build_walk(void *elem,
element_count elem_cnt, void *arg)
return hist_builder->next(elem, elem_cnt);
}
-C_MODE_END
+static int count_distinct_single_occurence_walk(void *elem,
+ element_count count,
void *arg)
+{
+ ((ulonglong*)arg)[0]+= 1;
+ if (count == 1)
+ ((ulonglong*)arg)[1]+= 1;
+ return 0;
+}
+
+C_MODE_END
/*
The class Count_distinct_field is a helper class used to calculate
the number of distinct values for a column. The class employs the
@@ -1611,6 +1629,9 @@ class Count_distinct_field: public Sql_alloc
Unique *tree; /* The helper object to contain distinct values
*/
uint tree_key_length; /* The length of the keys for the elements of
'tree */
+ ulonglong distincts;
+ ulonglong distincts_single_occurence;
+
public:
Count_distinct_field() {}
@@ -1662,30 +1683,40 @@ class Count_distinct_field: public Sql_alloc
{
return tree->unique_add(table_field->ptr);
}
-
+
/*
@brief
Calculate the number of elements accumulated in the container of
'tree'
*/
- ulonglong get_value()
- {
- ulonglong count;
- if (tree->elements == 0)
- return (ulonglong) tree->elements_in_tree();
- count= 0;
- tree->walk(table_field->table, count_distinct_walk, (void*)
&count);
- return count;
+ void walk_tree()
+ {
+ ulonglong counts[2] = {0, 0};
+ tree->walk(table_field->table,
+ count_distinct_single_occurence_walk, counts);
+ distincts= counts[0];
+ distincts_single_occurence= counts[1];
}
/*
@brief
- Build the histogram for the elements accumulated in the container
of 'tree'
+ Calculate a histogram of the tree
*/
- ulonglong get_value_with_histogram(ha_rows rows)
+ void walk_tree_with_histogram(ha_rows rows)
{
Histogram_builder hist_builder(table_field, tree_key_length,
rows);
tree->walk(table_field->table, histogram_build_walk, (void *)
&hist_builder);
- return hist_builder.get_count_distinct();
+ distincts= hist_builder.get_count_distinct();
+ distincts_single_occurence=
hist_builder.get_count_single_occurence();
+ }
+
+ ulonglong get_count_distinct()
+ {
+ return distincts;
+ }
+
+ ulonglong get_count_distinct_single_occurence()
+ {
+ return distincts_single_occurence;
}
/*
@@ -2514,7 +2545,7 @@ bool Column_statistics_collected::add()
*/
inline
-void Column_statistics_collected::finish(ha_rows rows)
+void Column_statistics_collected::finish(ha_rows rows, double
sample_fraction)
{
double val;
@@ -2532,16 +2563,43 @@ void
Column_statistics_collected::finish(ha_rows rows)
}
if (count_distinct)
{
- ulonglong distincts;
uint hist_size= count_distinct->get_hist_size();
+
+ /* Compute cardinality statistics and optionally histogram. */
if (hist_size == 0)
- distincts= count_distinct->get_value();
+ count_distinct->walk_tree();
else
- distincts= count_distinct->get_value_with_histogram(rows -
nulls);
+ count_distinct->walk_tree_with_histogram(rows - nulls);
+
+ ulonglong distincts= count_distinct->get_count_distinct();
+ ulonglong distincts_single_occurence=
+ count_distinct->get_count_distinct_single_occurence();
+
if (distincts)
{
- val= (double) (rows - nulls) / distincts;
- set_avg_frequency(val);
+ /*
+ We use the unsmoothed first-order jackknife estimator" to
estimate
+ the number of distinct values.
+ With a sufficient large percentage of rows sampled (80%), we
revert back
+ to computing the avg_frequency off of the raw data.
+ */
+ if (sample_fraction > 0.8)
+ val= (double) (rows - nulls) / distincts;
+ else
+ {
+ if (nulls == 1)
+ distincts_single_occurence+= 1;
+ if (nulls)
+ distincts+= 1;
+ double fraction_single_occurence= distincts_single_occurence /
rows;
+ double total_number_of_rows= rows / sample_fraction;
+ double estimate_total_distincts= total_number_of_rows /
+ (distincts /
+ (1.0 - (1.0 - sample_fraction) *
fraction_single_occurence));
+ val = std::fmax(estimate_total_distincts * (rows - nulls) /
rows, 1.0);
+ }
+
+ set_avg_frequency(val);
set_not_null(COLUMN_STAT_AVG_FREQUENCY);
}
else
@@ -2813,7 +2871,7 @@ int collect_statistics_for_table(THD *thd, TABLE
*table)
continue;
bitmap_set_bit(table->write_set, table_field->field_index);
if (!rc)
- table_field->collected_stats->finish(rows);
+ table_field->collected_stats->finish(rows, sample_fraction);
else
table_field->collected_stats->cleanup();
}
--
2.20.1
1
0
revision-id: dcaabf07fdfb608fe3e6485e392bc10757891ad2 (mariadb-10.3.6-151-gdcaabf07fdf)
parent(s): e17fc72940403293977ae2e5b162cf9e20eb30a7
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-02-15 09:33:49 +0200
message:
MDEV-18109: Galera 4: run galera_sr test suite
Fix some of the galera_sr suite test failures.
Remove tests that are not going to be run because required
feature is not supported.
modified: mysql-test/suite/galera_sr/disabled.def
deleted: mysql-test/suite/galera_sr/r/GCF-574.result
modified: mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
modified: mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
modified: mysql-test/suite/galera_sr/r/galera_sr_load_data.result
deleted: mysql-test/suite/galera_sr/r/galera_sr_sbr.result
modified: mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
deleted: mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result
deleted: mysql-test/suite/galera_sr/t/GCF-574.test
modified: mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
modified: mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
modified: mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
modified: mysql-test/suite/galera_sr/t/galera_sr_load_data.test
deleted: mysql-test/suite/galera_sr/t/galera_sr_sbr.test
modified: mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
deleted: mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test
---
mysql-test/suite/galera_sr/disabled.def | 4 +--
mysql-test/suite/galera_sr/r/GCF-574.result | 11 --------
.../suite/galera_sr/r/galera_sr_cc_slave.result | 2 ++
.../r/galera_sr_kill_all_norecovery.result | 2 ++
.../suite/galera_sr/r/galera_sr_load_data.result | 1 +
mysql-test/suite/galera_sr/r/galera_sr_sbr.result | 16 -----------
.../galera_sr/r/mysql-wsrep-features#148.result | 9 +++----
.../galera_sr/r/mysql-wsrep-features#29.result | 14 ----------
mysql-test/suite/galera_sr/t/GCF-574.test | 27 -------------------
.../suite/galera_sr/t/galera_sr_cc_slave.test | 8 ++++++
.../galera_sr/t/galera_sr_kill_all_norecovery.cnf | 4 +++
.../galera_sr/t/galera_sr_kill_all_norecovery.test | 7 +++++
.../suite/galera_sr/t/galera_sr_load_data.test | 10 +++++++
mysql-test/suite/galera_sr/t/galera_sr_sbr.test | 31 ----------------------
.../galera_sr/t/mysql-wsrep-features#148.test | 6 +++--
.../suite/galera_sr/t/mysql-wsrep-features#29.test | 23 ----------------
16 files changed, 42 insertions(+), 133 deletions(-)
diff --git a/mysql-test/suite/galera_sr/disabled.def b/mysql-test/suite/galera_sr/disabled.def
index 94f328bf31b..8bed54eb5c6 100644
--- a/mysql-test/suite/galera_sr/disabled.def
+++ b/mysql-test/suite/galera_sr/disabled.def
@@ -1,3 +1 @@
-mysql-wsrep-features#29 : binlog_format=STATEMENT not supported with SR
-GCF-574 : CTAS is not supported together with SR
-galera_sr_sbr : binlog_format=STATEMENT not supported with SR
+galera_sr_table_contents : missing file
diff --git a/mysql-test/suite/galera_sr/r/GCF-574.result b/mysql-test/suite/galera_sr/r/GCF-574.result
deleted file mode 100644
index bbf817c8c6c..00000000000
--- a/mysql-test/suite/galera_sr/r/GCF-574.result
+++ /dev/null
@@ -1,11 +0,0 @@
-CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
-INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
-SET SESSION wsrep_trx_fragment_size = 1;
-CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
-wsrep_last_committed_delta
-1
-SELECT COUNT(*) = 10000 FROM t1;
-COUNT(*) = 10000
-1
-DROP TABLE t1;
-DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
index 671745c8686..d439380e2ce 100644
--- a/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
+++ b/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
@@ -1,5 +1,7 @@
connection node_2;
connection node_1;
+connection node_1;
+connection node_2;
connection node_2;
SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
COUNT(*) = 0
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
index 7525cd6d4b7..d9d91b5e3c5 100644
--- a/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
@@ -1,5 +1,7 @@
connection node_2;
connection node_1;
+connection node_1;
+connection node_2;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_trx_fragment_size = 1;
SET AUTOCOMMIT=OFF;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_load_data.result b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result
index 354f9ca718a..99885b42fa0 100644
--- a/mysql-test/suite/galera_sr/r/galera_sr_load_data.result
+++ b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result
@@ -10,4 +10,5 @@ COUNT(*) = 20000
1
wsrep_last_committed_diff
1
+connection node_1;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_sbr.result b/mysql-test/suite/galera_sr/r/galera_sr_sbr.result
deleted file mode 100644
index c83db3d5ea6..00000000000
--- a/mysql-test/suite/galera_sr/r/galera_sr_sbr.result
+++ /dev/null
@@ -1,16 +0,0 @@
-CREATE TABLE t1 (id INT) ENGINE=InnoDB;
-SET SESSION wsrep_trx_fragment_size = 1;
-SET SESSION BINLOG_FORMAT='STATEMENT';
-SET AUTOCOMMIT=OFF;
-START TRANSACTION;
-INSERT INTO t1 VALUES (1);
-INSERT INTO t1 VALUES (2);
-INSERT INTO t1 VALUES (3);
-INSERT INTO t1 VALUES (4);
-INSERT INTO t1 VALUES (5);
-SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-COMMIT;
-SELECT COUNT(*) = 5 FROM t1;
-COUNT(*) = 5
-1
-DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
index a85c0f302d0..98bf13e9d2b 100644
--- a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
@@ -6,9 +6,7 @@ CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t2 VALUES (6),(7),(8),(9),(10),(1);
connection node_2;
SET GLOBAL wsrep_slave_threads = 2;
-SET GLOBAL DEBUG = 'd,sync.wsrep_apply_cb';
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = 'd,sync.wsrep_apply_cb';
connection node_1;
SET SESSION wsrep_trx_fragment_size = 1;
SET AUTOCOMMIT=OFF;
@@ -28,9 +26,7 @@ connection node_1;
Got one of the listed errors
connection node_2;
SET GLOBAL wsrep_slave_threads = 1;
-SET GLOBAL DEBUG = '';
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = '';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
@@ -40,3 +36,4 @@ COUNT(*) = 10
1
DROP TABLE t1;
DROP TABLE t2;
+SET DEBUG_SYNC = RESET;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result
deleted file mode 100644
index 29b17ea07d6..00000000000
--- a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result
+++ /dev/null
@@ -1,14 +0,0 @@
-SET SESSION wsrep_trx_fragment_size = 1;
-SET SESSION binlog_format = STATEMENT;
-create table t1 (id int not null, f_id int not null, f int not null,
-primary key(f_id, id)) engine=innodb;
-create table t2 (id int not null,s_id int not null,s varchar(200),
-primary key(id)) engine=innodb;
-INSERT INTO t1 VALUES (8, 1, 3);
-INSERT INTO t1 VALUES (1, 2, 1);
-INSERT INTO t2 VALUES (1, 0, '');
-INSERT INTO t2 VALUES (8, 1, '');
-DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
-WHERE mm.id IS NULL;
-DROP TABLE t1;
-DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/GCF-574.test b/mysql-test/suite/galera_sr/t/GCF-574.test
deleted file mode 100644
index c9d7c405d14..00000000000
--- a/mysql-test/suite/galera_sr/t/GCF-574.test
+++ /dev/null
@@ -1,27 +0,0 @@
---source include/galera_cluster.inc
---source include/have_innodb.inc
-
-#
-# Test CREATE TABLE ... SELECT with Streaming Replication
-#
-
---connection node_1
-CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
-INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
-
---let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
-
-SET SESSION wsrep_trx_fragment_size = 1;
-CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
-
---let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
---disable_query_log
---eval SELECT ($wsrep_last_committed_after - $wsrep_last_committed_before) > 1 AS wsrep_last_committed_delta;
---enable_query_log
-
---connection node_2
-SELECT COUNT(*) = 10000 FROM t1;
-
---connection node_1
-DROP TABLE t1;
-DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
index 8c790ac7cd2..7ba0f253b4a 100644
--- a/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
+++ b/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
@@ -7,6 +7,11 @@
# leave the cluster.
#
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source ../../galera/include/auto_increment_offset_save.inc
+
# Start with a clean slate
--connection node_2
SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
@@ -95,3 +100,6 @@ SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
DROP TABLE t1;
CALL mtr.add_suppression("points to own listening address, blacklisting");
+
+# Restore original auto_increment_offset values.
+--source ../../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
index 6422d7541ba..82c001e0131 100644
--- a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
@@ -2,3 +2,7 @@
[mysqld.1]
wsrep_provider_options='base_port=(a)mysqld.1.#galera_port;pc.recovery=false'
+auto_increment_offset=1
+
+[mysqld.2]
+auto_increment_offset=2
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
index 042e3d3ef57..5a1f9e7997a 100644
--- a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
@@ -6,6 +6,11 @@
--source include/galera_cluster.inc
--source include/big_test.inc
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source ../../galera/include/auto_increment_offset_save.inc
+
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_trx_fragment_size = 1;
SET AUTOCOMMIT=OFF;
@@ -50,4 +55,6 @@ SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT COUNT(*) = 0 FROM t1;
SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source ../../galera/include/auto_increment_offset_restore.inc
+
DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_load_data.test b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test
index 70f0926ed1b..363443a9e64 100644
--- a/mysql-test/suite/galera_sr/t/galera_sr_load_data.test
+++ b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test
@@ -24,6 +24,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
--connection node_1
--disable_query_log
+--disable_warnings
+set global wsrep_load_data_splitting=ON;
+--enable_warnings
--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/galera_sr_load_data.csv' INTO TABLE t1;
--enable_query_log
@@ -36,4 +39,11 @@ SELECT COUNT(*) = 20000 FROM t1;
--eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before = 3 AS wsrep_last_committed_diff
--enable_query_log
+--connection node_1
+--disable_query_log
+--disable_warnings
+set global wsrep_load_data_splitting=OFF;
+--enable_warnings
+--enable_query_log
+
DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_sbr.test b/mysql-test/suite/galera_sr/t/galera_sr_sbr.test
deleted file mode 100644
index a24a520af60..00000000000
--- a/mysql-test/suite/galera_sr/t/galera_sr_sbr.test
+++ /dev/null
@@ -1,31 +0,0 @@
---source include/galera_cluster.inc
---source include/have_innodb.inc
-
-#
-# Test that SR does not assert in the presence of statement-based replication events
-#
-
---connection node_1
-CREATE TABLE t1 (id INT) ENGINE=InnoDB;
-SET SESSION wsrep_trx_fragment_size = 1;
-SET SESSION BINLOG_FORMAT='STATEMENT';
-SET AUTOCOMMIT=OFF;
-START TRANSACTION;
-INSERT INTO t1 VALUES (1);
-INSERT INTO t1 VALUES (2);
-INSERT INTO t1 VALUES (3);
-INSERT INTO t1 VALUES (4);
-INSERT INTO t1 VALUES (5);
-
---connection node_2
-SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
---let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
---source include/wait_condition.inc
-
---connection node_1
-COMMIT;
-
---connection node_2
-SELECT COUNT(*) = 5 FROM t1;
-
-DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
index 5210b9ce99e..e0a443061df 100644
--- a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
@@ -16,7 +16,7 @@ INSERT INTO t2 VALUES (6),(7),(8),(9),(10),(1);
--connection node_2
SET GLOBAL wsrep_slave_threads = 2;
-SET GLOBAL DEBUG = 'd,sync.wsrep_apply_cb';
+SET GLOBAL debug_dbug = 'd,sync.wsrep_apply_cb';
# Begin SR transaction
--connection node_1
@@ -48,7 +48,7 @@ COMMIT;
--connection node_2
SET GLOBAL wsrep_slave_threads = 1;
-SET GLOBAL DEBUG = '';
+SET GLOBAL debug_dbug = '';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
@@ -58,3 +58,5 @@ SELECT COUNT(*) = 10 FROM t1;
DROP TABLE t1;
DROP TABLE t2;
+
+SET DEBUG_SYNC = RESET;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test
deleted file mode 100644
index 2349fe9979f..00000000000
--- a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# mysql-wsrep-features#29 Unwarranted deadlock error with SR and a single-node cluster
-#
-
-SET SESSION wsrep_trx_fragment_size = 1;
-SET SESSION binlog_format = STATEMENT;
-
-create table t1 (id int not null, f_id int not null, f int not null,
-primary key(f_id, id)) engine=innodb;
-
-create table t2 (id int not null,s_id int not null,s varchar(200),
-primary key(id)) engine=innodb;
-
-INSERT INTO t1 VALUES (8, 1, 3);
-INSERT INTO t1 VALUES (1, 2, 1);
-INSERT INTO t2 VALUES (1, 0, '');
-INSERT INTO t2 VALUES (8, 1, '');
-
-DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
-WHERE mm.id IS NULL;
-
-DROP TABLE t1;
-DROP TABLE t2;
1
0
revision-id: 98d55b1366746a2b4750da9e8781f66b0d01ed85 (mariadb-10.3.6-117-g98d55b1)
parent(s): ccce4d3be9bb5dfce66576f9744bcb927b754cf4 282ba973e748456a829eecf1b49fb352870c6a8f
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-02-14 22:07:33 -0800
message:
Merge branch '10.4' into bb-10.4-mdev16188
client/mysqltest.cc | 9 +-
cmake/build_configurations/mysql_release.cmake | 3 +
cmake/submodules.cmake | 2 +-
cmake/wsrep.cmake | 26 +-
extra/innochecksum.cc | 138 +-
extra/mariabackup/backup_mysql.cc | 2 +-
extra/mariabackup/fil_cur.cc | 32 +-
extra/mariabackup/fil_cur.h | 7 +-
extra/mariabackup/read_filt.cc | 2 +-
extra/mariabackup/read_filt.h | 2 +-
extra/mariabackup/write_filt.cc | 12 +-
extra/mariabackup/xtrabackup.cc | 56 +-
extra/mariabackup/xtrabackup.h | 9 +-
include/mysql/service_wsrep.h | 2 +-
libmariadb | 2 +-
libmysqld/CMakeLists.txt | 4 +-
mysql-test/include/galera_suspend.inc | 14 +
mysql-test/include/mtr_check.sql | 1 +
mysql-test/main/alter_user.result | 2 +-
mysql-test/main/create_select_tmp.result | 21 +
mysql-test/main/create_select_tmp.test | 14 +
mysql-test/main/failed_auth_unixsocket.result | 11 +-
mysql-test/main/failed_auth_unixsocket.test | 6 +-
mysql-test/main/grant5.result | 22 +-
mysql-test/main/grant5.test | 8 -
mysql-test/main/information_schema-big.result | 2 +
mysql-test/main/information_schema.result | 3 +
.../main/information_schema_all_engines.result | 8 +-
mysql-test/main/lock_user.result | 134 +
mysql-test/main/lock_user.test | 142 +
mysql-test/main/lowercase_table.result | 4 +
mysql-test/main/lowercase_table.test | 12 +
mysql-test/main/mysql_upgrade-6984.result | 2 +-
mysql-test/main/mysql_upgrade-6984.test | 2 +-
mysql-test/main/mysql_upgrade.result | 41 +-
mysql-test/main/mysql_upgrade.test | 35 +-
mysql-test/main/mysqld--help.result | 8 +
mysql-test/main/opt_trace.result | 3511 ++++++++++++++++++++
mysql-test/main/opt_trace.test | 335 ++
mysql-test/main/opt_trace_index_merge.result | 249 ++
mysql-test/main/opt_trace_index_merge.test | 21 +
.../main/opt_trace_index_merge_innodb.result | 248 ++
mysql-test/main/opt_trace_index_merge_innodb.test | 45 +
mysql-test/main/opt_trace_security.result | 396 +++
mysql-test/main/opt_trace_security.test | 197 ++
mysql-test/main/plugin_auth.result | 33 +-
mysql-test/main/plugin_auth.test | 38 +-
mysql-test/main/plugin_auth_qa_1.result | 4 +-
mysql-test/main/plugin_auth_qa_1.test | 2 +-
mysql-test/main/reset_connection.result | 20 +
mysql-test/main/reset_connection.test | 15 +
mysql-test/main/system_mysql_db_507.result | 21 +
mysql-test/main/system_mysql_db_507.test | 18 +
mysql-test/main/system_mysql_db_fix40123.result | 76 +-
mysql-test/main/system_mysql_db_fix40123.test | 55 +-
mysql-test/main/system_mysql_db_fix50030.result | 80 +-
mysql-test/main/system_mysql_db_fix50030.test | 62 +-
mysql-test/main/system_mysql_db_fix50117.result | 76 +-
mysql-test/main/system_mysql_db_fix50117.test | 87 +-
mysql-test/main/type_json.result | 67 +-
mysql-test/main/type_json.test | 35 +
mysql-test/main/type_timestamp.result | 9 +
mysql-test/main/type_timestamp.test | 8 +
.../federated/federatedx_create_handlers.result | 312 ++
.../federated/federatedx_create_handlers.test | 161 +
mysql-test/suite/funcs_1/r/is_columns_is.result | 8 +
.../suite/funcs_1/r/is_columns_is_embedded.result | 8 +
.../suite/funcs_1/r/is_routines_embedded.result | 6 +-
mysql-test/suite/funcs_1/r/is_tables_is.result | 50 +
.../suite/funcs_1/r/is_tables_is_embedded.result | 50 +
mysql-test/suite/galera/disabled.def | 2 -
mysql-test/suite/galera/r/galera_defaults.result | 4 +-
.../galera/r/galera_gcache_recover_manytrx.result | 31 +
mysql-test/suite/galera/r/galera_sst_rsync2.result | 2 +
.../galera/r/galera_var_load_data_splitting.result | 10 +-
mysql-test/suite/galera/r/partition.result | 10 +-
.../suite/galera/t/galera_sst_mariabackup.cnf | 2 +-
.../galera/t/galera_sst_mariabackup_data_dir.cnf | 2 +-
.../t/galera_sst_mariabackup_encrypt_with_key.cnf | 2 +-
.../t/galera_sst_mariabackup_table_options.cnf | 2 +-
mysql-test/suite/galera/t/galera_sst_mysqldump.cnf | 2 -
.../galera/t/galera_sst_mysqldump_with_key.cnf | 2 +-
.../galera/t/galera_var_load_data_splitting.test | 3 +
.../suite/galera_3nodes/include/galera_suspend.inc | 14 -
.../r/galera_ist_gcache_rollover.result | 1 +
.../r/galera_safe_to_bootstrap.result | 10 +
mysql-test/suite/galera_3nodes/t/galera_garbd.test | 4 +-
.../galera_3nodes/t/galera_ist_gcache_rollover.cnf | 6 +-
.../t/galera_ist_gcache_rollover.test | 1 +
.../galera_3nodes/t/galera_safe_to_bootstrap.test | 15 +-
.../suite/galera_sr/r/galera_sr_load_data.result | 2 +-
.../r/galera_sr_load_data_splitting.result | 10 +
.../suite/galera_sr/t/galera_sr_load_data.test | 2 +-
.../suite/innodb/r/alter_varchar_change.result | 493 +++
.../suite/innodb/r/instant_alter_bugs.result | 47 +
.../innodb/r/instant_alter_charset,redundant.rdiff | 28 +
.../suite/innodb/r/instant_alter_charset.result | 1812 ++++++++++
.../suite/innodb/r/instant_alter_extend,utf8.rdiff | 29 +
.../suite/innodb/r/instant_alter_extend.result | 235 ++
.../suite/innodb/r/instant_alter_import.result | 72 +
.../suite/innodb/t/alter_varchar_change.test | 360 ++
mysql-test/suite/innodb/t/instant_alter_bugs.test | 49 +
.../suite/innodb/t/instant_alter_charset.test | 538 +++
.../innodb/t/instant_alter_extend.combinations | 5 +
.../suite/innodb/t/instant_alter_extend.test | 210 ++
.../suite/innodb/t/instant_alter_import.test | 84 +
.../innodb_zip/r/prefix_index_liftedlimit.result | 2 +-
.../innodb_zip/t/prefix_index_liftedlimit.test | 2 +-
.../incremental_ddl_before_backup.result | 32 +
.../mariabackup/incremental_ddl_before_backup.test | 50 +
mysql-test/suite/mariabackup/mdev-14447.result | 1 +
mysql-test/suite/mariabackup/mdev-14447.test | 14 +-
mysql-test/suite/plugins/r/auth_ed25519.result | 4 +
mysql-test/suite/plugins/r/multiauth.result | 194 ++
mysql-test/suite/plugins/t/auth_ed25519.test | 4 +
mysql-test/suite/plugins/t/multiauth.test | 197 ++
.../roles/i_s_applicable_roles_is_default.result | 2 +-
.../roles/i_s_applicable_roles_is_default.test | 2 +-
mysql-test/suite/sys_vars/r/sysvars_innodb.result | 28 +
.../sys_vars/r/sysvars_server_embedded,32bit.rdiff | 139 +-
.../sys_vars/r/sysvars_server_embedded.result | 28 +
.../r/sysvars_server_notembedded,32bit.rdiff | 155 +-
.../sys_vars/r/sysvars_server_notembedded.result | 28 +
mysql-test/suite/sys_vars/r/sysvars_wsrep.result | 18 +-
.../suite/sys_vars/r/wsrep_debug_basic.result | 22 +-
.../r/wsrep_load_data_splitting_basic.result | 16 +-
mysql-test/suite/sys_vars/t/wsrep_debug_basic.test | 10 +-
mysql-test/suite/unit/suite.pm | 2 +
.../suite/wsrep/r/wsrep-recover-v25,binlogon.rdiff | 17 +
mysql-test/suite/wsrep/r/wsrep-recover-v25.result | 28 +
mysql-test/suite/wsrep/t/wsrep-recover-v25.cnf | 7 +
.../suite/wsrep/t/wsrep-recover-v25.combinations | 4 +
mysql-test/suite/wsrep/t/wsrep-recover-v25.test | 121 +
mysys/my_fopen.c | 5 +-
plugin/auth_ed25519/CMakeLists.txt | 4 +-
plugin/auth_ed25519/server_ed25519.c | 9 +-
plugin/auth_gssapi/gssapi_server.cc | 20 +-
.../mysql-test/auth_gssapi/multiauth.result | 34 +
.../mysql-test/auth_gssapi/multiauth.test | 36 +
plugin/auth_gssapi/server_plugin.cc | 34 +-
plugin/auth_gssapi/server_plugin.h | 2 +-
plugin/auth_gssapi/sspi_server.cc | 17 +-
plugin/auth_pam/auth_pam.c | 32 +-
plugin/auth_pam/auth_pam_base.c | 9 +-
plugin/auth_pam/auth_pam_tool.c | 14 +-
plugin/auth_pam/auth_pam_v1.c | 31 +-
.../mysql-test/user_variables/basic.result | 2 +-
plugin/user_variables/user_variables.cc | 2 +-
scripts/mysql_install_db.sh | 29 +-
scripts/mysql_secure_installation.sh | 59 +-
scripts/mysql_system_tables_data.sql | 9 +-
scripts/mysql_system_tables_fix.sql | 6 +-
scripts/wsrep_sst_mariabackup.sh | 4 +-
scripts/wsrep_sst_rsync.sh | 23 +-
sql/CMakeLists.txt | 3 +-
sql/derived_handler.cc | 127 +
sql/derived_handler.h | 85 +
sql/field.cc | 123 +-
sql/field.h | 2 +-
sql/ha_sequence.cc | 2 +-
sql/handler.cc | 5 +-
sql/handler.h | 46 +-
sql/item_cmpfunc.cc | 9 +-
sql/item_subselect.cc | 6 +-
sql/lex.h | 1 +
sql/my_json_writer.cc | 75 +-
sql/my_json_writer.h | 425 ++-
sql/mysqld.cc | 11 +-
sql/mysqld.h | 5 +-
sql/opt_range.cc | 846 ++++-
sql/opt_range.h | 2 +-
sql/opt_subselect.cc | 66 +-
sql/opt_table_elimination.cc | 30 +-
sql/opt_trace.cc | 722 ++++
sql/opt_trace.h | 201 ++
sql/opt_trace_context.h | 92 +
sql/select_handler.cc | 188 ++
sql/select_handler.h | 72 +
sql/set_var.h | 9 +
sql/share/errmsg-utf8.txt | 3 +
sql/sp_head.cc | 13 +
sql/sp_head.h | 1 +
sql/sql_acl.cc | 998 +++---
sql/sql_class.cc | 19 +-
sql/sql_class.h | 22 +-
sql/sql_connect.cc | 1 +
sql/sql_db.cc | 8 +-
sql/sql_derived.cc | 168 +-
sql/sql_explain.cc | 28 +-
sql/sql_explain.h | 2 +
sql/sql_insert.cc | 6 +-
sql/sql_lex.cc | 30 +-
sql/sql_lex.h | 49 +-
sql/sql_load.cc | 64 +-
sql/sql_parse.cc | 23 +-
sql/sql_parse.h | 2 +-
sql/sql_prepare.cc | 12 +
sql/sql_priv.h | 14 +-
sql/sql_select.cc | 743 ++++-
sql/sql_select.h | 46 +-
sql/sql_show.cc | 7 +
sql/sql_table.cc | 69 +-
sql/sql_test.cc | 27 +-
sql/sql_test.h | 2 +
sql/sql_type.cc | 47 +
sql/sql_type.h | 27 +-
sql/sql_view.cc | 10 +
sql/sql_yacc.yy | 180 +-
sql/sql_yacc_ora.yy | 178 +-
sql/structs.h | 23 +-
sql/sys_vars.cc | 85 +-
sql/sys_vars.ic | 2 +-
sql/table.cc | 27 +-
sql/table.h | 14 +
sql/wsrep_mysqld.cc | 69 +-
sql/wsrep_mysqld.h | 15 +-
sql/wsrep_schema.cc | 79 +-
sql/wsrep_schema.h | 19 +-
sql/wsrep_server_state.cc | 1 +
sql/wsrep_sst.cc | 17 +-
sql/wsrep_var.cc | 6 +
sql/wsrep_var.h | 2 +
storage/federatedx/federatedx_pushdown.cc | 293 ++
storage/federatedx/federatedx_pushdown.h | 63 +
storage/federatedx/ha_federatedx.cc | 21 +-
storage/federatedx/ha_federatedx.h | 9 +
storage/innobase/btr/btr0btr.cc | 119 +-
storage/innobase/btr/btr0bulk.cc | 13 +-
storage/innobase/btr/btr0cur.cc | 189 +-
storage/innobase/btr/btr0defragment.cc | 18 +-
storage/innobase/btr/btr0pcur.cc | 2 +-
storage/innobase/btr/btr0scrub.cc | 22 +-
storage/innobase/btr/btr0sea.cc | 2 +-
storage/innobase/buf/buf0buf.cc | 173 +-
storage/innobase/buf/buf0dblwr.cc | 82 +-
storage/innobase/buf/buf0dump.cc | 8 +-
storage/innobase/buf/buf0flu.cc | 11 +-
storage/innobase/buf/buf0lru.cc | 68 +-
storage/innobase/buf/buf0rea.cc | 99 +-
storage/innobase/data/data0data.cc | 8 +-
storage/innobase/data/data0type.cc | 21 +-
storage/innobase/dict/dict0boot.cc | 2 +-
storage/innobase/dict/dict0crea.cc | 24 +-
storage/innobase/dict/dict0dict.cc | 64 +-
storage/innobase/dict/dict0stats.cc | 4 +-
storage/innobase/fil/fil0crypt.cc | 103 +-
storage/innobase/fil/fil0fil.cc | 142 +-
storage/innobase/fil/fil0pagecompress.cc | 3 +-
storage/innobase/fsp/fsp0file.cc | 43 +-
storage/innobase/fsp/fsp0fsp.cc | 441 +--
storage/innobase/fts/fts0fts.cc | 4 +-
storage/innobase/fts/fts0que.cc | 8 +-
storage/innobase/fut/fut0lst.cc | 64 +-
storage/innobase/gis/gis0rtree.cc | 8 +-
storage/innobase/gis/gis0sea.cc | 11 +-
storage/innobase/handler/ha_innodb.cc | 111 +-
storage/innobase/handler/handler0alter.cc | 363 +-
storage/innobase/handler/i_s.cc | 13 +-
storage/innobase/ibuf/ibuf0ibuf.cc | 346 +-
storage/innobase/include/btr0btr.h | 57 +-
storage/innobase/include/btr0btr.ic | 14 +-
storage/innobase/include/btr0cur.h | 16 +-
storage/innobase/include/btr0types.h | 10 +-
storage/innobase/include/buf0buf.h | 56 +-
storage/innobase/include/buf0rea.h | 37 +-
storage/innobase/include/data0type.ic | 22 +-
storage/innobase/include/dict0dict.h | 34 +-
storage/innobase/include/dict0dict.ic | 22 -
storage/innobase/include/dict0mem.h | 50 +-
storage/innobase/include/fil0crypt.h | 41 +-
storage/innobase/include/fil0fil.h | 59 +-
storage/innobase/include/fsp0file.h | 19 +
storage/innobase/include/fsp0fsp.h | 106 +-
storage/innobase/include/fsp0fsp.ic | 69 +-
storage/innobase/include/fut0fut.h | 28 +-
storage/innobase/include/fut0fut.ic | 68 -
storage/innobase/include/ibuf0ibuf.h | 75 +-
storage/innobase/include/ibuf0ibuf.ic | 49 +-
storage/innobase/include/mem0mem.ic | 4 +-
storage/innobase/include/mtr0types.h | 9 +-
storage/innobase/include/os0file.h | 2 +-
storage/innobase/include/page0size.h | 197 --
storage/innobase/include/page0zip.h | 15 +-
storage/innobase/include/page0zip.ic | 21 +-
storage/innobase/include/row0ext.h | 9 +-
storage/innobase/include/trx0rseg.ic | 5 +-
storage/innobase/include/trx0sys.h | 2 +-
storage/innobase/include/trx0undo.ic | 8 +-
storage/innobase/lock/lock0lock.cc | 2 +-
storage/innobase/log/log0log.cc | 8 +-
storage/innobase/log/log0recv.cc | 62 +-
storage/innobase/mtr/mtr0mtr.cc | 2 +-
storage/innobase/os/os0file.cc | 2 -
storage/innobase/page/page0zip.cc | 17 +-
storage/innobase/rem/rem0rec.cc | 8 +-
storage/innobase/row/row0ext.cc | 32 +-
storage/innobase/row/row0ftsort.cc | 4 +-
storage/innobase/row/row0import.cc | 119 +-
storage/innobase/row/row0log.cc | 18 +-
storage/innobase/row/row0merge.cc | 22 +-
storage/innobase/row/row0mysql.cc | 25 +-
storage/innobase/row/row0purge.cc | 2 +-
storage/innobase/row/row0row.cc | 4 +-
storage/innobase/row/row0sel.cc | 26 +-
storage/innobase/row/row0upd.cc | 39 +-
storage/innobase/srv/srv0srv.cc | 2 -
storage/innobase/srv/srv0start.cc | 13 +-
storage/innobase/trx/trx0rec.cc | 34 +-
storage/innobase/trx/trx0rseg.cc | 20 +-
storage/innobase/trx/trx0undo.cc | 8 +-
storage/spider/CMakeLists.txt | 2 +-
.../checksum_table_with_quick_mode_3_deinit.inc | 14 +
.../checksum_table_with_quick_mode_3_init.inc | 29 +
.../include/direct_sql_with_tmp_table_deinit.inc | 7 +
.../include/direct_sql_with_tmp_table_init.inc | 9 +
.../spider/bugfix/include/quick_mode_0_deinit.inc | 19 +
.../spider/bugfix/include/quick_mode_0_init.inc | 51 +
.../spider/bugfix/include/quick_mode_1_deinit.inc | 19 +
.../spider/bugfix/include/quick_mode_1_init.inc | 51 +
.../spider/bugfix/include/quick_mode_2_deinit.inc | 19 +
.../spider/bugfix/include/quick_mode_2_init.inc | 51 +
.../spider/bugfix/include/quick_mode_3_deinit.inc | 19 +
.../spider/bugfix/include/quick_mode_3_init.inc | 51 +
.../bugfix/include/slave_trx_isolation_deinit.inc | 15 +
.../bugfix/include/slave_trx_isolation_init.inc | 35 +
.../bugfix/include/wrapper_mariadb_deinit.inc | 11 +
.../spider/bugfix/include/wrapper_mariadb_init.inc | 24 +
storage/spider/mysql-test/spider/bugfix/my.cnf | 2 +
storage/spider/mysql-test/spider/bugfix/my_1_1.cnf | 44 +
storage/spider/mysql-test/spider/bugfix/my_2_1.cnf | 56 +
storage/spider/mysql-test/spider/bugfix/my_2_2.cnf | 38 +
storage/spider/mysql-test/spider/bugfix/my_2_3.cnf | 8 +
storage/spider/mysql-test/spider/bugfix/my_3_1.cnf | 11 +
storage/spider/mysql-test/spider/bugfix/my_3_2.cnf | 9 +
storage/spider/mysql-test/spider/bugfix/my_3_3.cnf | 9 +
storage/spider/mysql-test/spider/bugfix/my_4_1.cnf | 9 +
.../r/checksum_table_with_quick_mode_3.result | 100 +
.../bugfix/r/direct_sql_with_tmp_table.result | 33 +
.../mysql-test/spider/bugfix/r/quick_mode_0.result | 504 +++
.../mysql-test/spider/bugfix/r/quick_mode_1.result | 504 +++
.../mysql-test/spider/bugfix/r/quick_mode_2.result | 504 +++
.../mysql-test/spider/bugfix/r/quick_mode_3.result | 504 +++
.../spider/bugfix/r/slave_trx_isolation.result | 99 +
.../spider/bugfix/r/wrapper_mariadb.result | 78 +
storage/spider/mysql-test/spider/bugfix/suite.opt | 1 +
storage/spider/mysql-test/spider/bugfix/suite.pm | 12 +
.../bugfix/t/checksum_table_with_quick_mode_3.cnf | 3 +
.../bugfix/t/checksum_table_with_quick_mode_3.test | 72 +
.../spider/bugfix/t/direct_sql_with_tmp_table.cnf | 3 +
.../spider/bugfix/t/direct_sql_with_tmp_table.test | 35 +
.../mysql-test/spider/bugfix/t/quick_mode_0.cnf | 4 +
.../mysql-test/spider/bugfix/t/quick_mode_0.test | 156 +
.../mysql-test/spider/bugfix/t/quick_mode_1.cnf | 4 +
.../mysql-test/spider/bugfix/t/quick_mode_1.test | 156 +
.../mysql-test/spider/bugfix/t/quick_mode_2.cnf | 4 +
.../mysql-test/spider/bugfix/t/quick_mode_2.test | 156 +
.../mysql-test/spider/bugfix/t/quick_mode_3.cnf | 4 +
.../mysql-test/spider/bugfix/t/quick_mode_3.test | 157 +
.../spider/bugfix/t/slave_trx_isolation.cnf | 4 +
.../spider/bugfix/t/slave_trx_isolation.test | 95 +
.../mysql-test/spider/bugfix/t/wrapper_mariadb.cnf | 3 +
.../spider/bugfix/t/wrapper_mariadb.test | 69 +
.../checksum_table_with_quick_mode_3_deinit.inc | 3 +-
.../checksum_table_with_quick_mode_3_init.inc | 2 +
.../r/checksum_table_with_quick_mode_3.result | 8 +-
.../spider/mysql-test/spider/r/quick_mode_0.result | 7 -
.../spider/mysql-test/spider/r/quick_mode_1.result | 7 -
.../spider/mysql-test/spider/r/quick_mode_2.result | 7 -
.../spider/mysql-test/spider/r/quick_mode_3.result | 7 -
.../mysql-test/spider/r/slave_trx_isolation.result | 9 +-
.../spider/t/checksum_table_with_quick_mode_3.test | 10 +-
.../spider/mysql-test/spider/t/quick_mode_0.test | 15 -
.../spider/mysql-test/spider/t/quick_mode_1.test | 15 -
.../spider/mysql-test/spider/t/quick_mode_2.test | 15 -
.../spider/mysql-test/spider/t/quick_mode_3.test | 15 -
.../mysql-test/spider/t/slave_trx_isolation.test | 18 -
storage/spider/spd_db_handlersocket.cc | 7 +-
storage/spider/spd_db_include.cc | 51 +
storage/spider/spd_db_include.h | 23 +-
storage/spider/spd_db_mysql.cc | 2067 +++++++-----
storage/spider/spd_db_mysql.h | 196 +-
storage/spider/spd_db_oracle.cc | 9 +-
storage/spider/spd_direct_sql.cc | 2 +-
storage/spider/spd_include.h | 4 +-
storage/spider/spd_sys_table.cc | 17 +
storage/spider/spd_sys_table.h | 5 +
storage/spider/spd_table.cc | 8 +
unittest/strings/json-t.c | 133 +-
388 files changed, 24683 insertions(+), 5424 deletions(-)
diff --cc libmysqld/CMakeLists.txt
index bf277e9,3146529..43b7fa8
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@@ -121,8 -122,8 +122,9 @@@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc
../sql/proxy_protocol.cc ../sql/backup.cc
../sql/sql_tvc.cc ../sql/sql_tvc.h
../sql/opt_split.cc
+ ../sql/rowid_filter.cc ../sql/rowid_filter.h
../sql/item_vers.cc
+ ../sql/opt_trace.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
diff --cc mysql-test/main/mysqld--help.result
index 1619f69,47ebfa7..f83bf1b
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@@ -694,7 -692,13 +694,13 @@@ The following specify which files/extr
optimize_join_buffer_size, table_elimination,
extended_keys, exists_to_in, orderby_uses_equalities,
condition_pushdown_for_derived, split_materialized,
- condition_pushdown_for_subquery
+ condition_pushdown_for_subquery, rowid_filter
+ --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
@@@ -1565,7 -1568,9 +1571,9 @@@ old-style-user-limits FALS
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-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,rowid_filter=on
+ optimizer-trace
+ optimizer-trace-max-mem-size 1048576
optimizer-use-condition-selectivity 4
performance-schema FALSE
performance-schema-accounts-size -1
diff --cc mysql-test/main/opt_trace.result
index 0000000,22cde92..57ed163
mode 000000,100644..100644
--- a/mysql-test/main/opt_trace.result
+++ b/mysql-test/main/opt_trace.result
@@@ -1,0 -1,3499 +1,3511 @@@
+ SELECT table_name, column_name FROM information_schema.columns where table_name="OPTIMIZER_TRACE";
+ table_name column_name
+ OPTIMIZER_TRACE QUERY
+ OPTIMIZER_TRACE TRACE
+ OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+ OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES
+ show variables like 'optimizer_trace';
+ Variable_name Value
+ optimizer_trace enabled=off
+ set optimizer_trace="enabled=on";
+ show variables like 'optimizer_trace';
+ Variable_name Value
+ optimizer_trace enabled=on
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ analyze table t2;
+ Table Op Msg_type Msg_text
+ test.t2 analyze status Engine-independent statistics collected
+ test.t2 analyze status OK
+ 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";
+ # Mergeable views/derived tables
+ select * from v1;
+ a b
+ 1 2
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select * from v1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "view": {
+ "table": "v1",
+ "select_id": 2,
+ "merged": true
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `v1`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = 1",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "selectivity_for_indexes": [],
+ "selectivity_for_columns": [
+ {
+ "column_name": "a",
+ "selectivity_from_histograms": 0.5
+ }
+ ]
+ },
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 2,
+ "cost": 2.0044
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 1,
+ "cost": 2.2044,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = 1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.a = 1"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ select * from (select * from t1 where t1.a=1)q;
+ a b
+ 1 2
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select * from (select * from t1 where t1.a=1)q {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "derived": {
+ "table": "q",
+ "select_id": 2,
+ "merged": true
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from (/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1) `q`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = 1",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "selectivity_for_indexes": [],
+ "selectivity_for_columns": [
+ {
+ "column_name": "a",
+ "selectivity_from_histograms": 0.5
+ }
+ ]
+ },
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 2,
+ "cost": 2.0044
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 1,
+ "cost": 2.2044,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = 1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.a = 1"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ # Non-Mergeable views
+ select * from v2;
+ a b
+ 1 2
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select * from v2 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "view": {
+ "table": "v2",
+ "select_id": 2,
+ "materialized": true
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` = 1 group by `t1`.`b`"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `v2`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_optimization": {
+ "select_id": 2,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = 1",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(1, t1.a)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "selectivity_for_indexes": [],
+ "selectivity_for_columns": [
+ {
+ "column_name": "a",
+ "selectivity_from_histograms": 0.5
+ }
+ ]
+ },
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 2,
+ "cost": 2.0044
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 1,
+ "cost": 2.2044,
+ "chosen": true,
+ "use_tmp_table": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = 1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.a = 1"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "<derived2>",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "<derived2>",
+ "table_scan": {
+ "rows": 2,
+ "cost": 2
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "<derived2>",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 2,
+ "cost": 2,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "<derived2>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_execution": {
+ "select_id": 2,
+ "steps": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ } 0 0
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ ANALYZE TABLE t2;
+ Table Op Msg_type Msg_text
+ test.t2 analyze status Engine-independent statistics collected
+ test.t2 analyze status OK
+ create view v1 as select a from t1 group by b;
+ create view v2 as select a from t2;
+ # Mergeable view
+ explain select * from v2 ;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t2 ALL NULL NULL NULL NULL 10
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from v2 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "view": {
+ "table": "v2",
+ "select_id": 2,
+ "merged": true
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `t2`.`a` AS `a` from `t2`"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `t2`.`a` AS `a` from `v2`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t2",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t2",
+ "table_scan": {
+ "rows": 10,
+ "cost": 2.022
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 2.022,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t2",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ # Non-Mergeable view
+ explain select * from v1 ;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 10
+ 2 DERIVED t1 ALL NULL NULL NULL NULL 10 Using temporary; Using filesort
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from v1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "view": {
+ "table": "v1",
+ "select_id": 2,
+ "materialized": true
+ }
+ },
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `t1`.`a` AS `a` from `t1` group by `t1`.`b`"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `v1`.`a` AS `a` from `v1`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_optimization": {
+ "select_id": 2,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 10,
+ "cost": 2.022
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 2.022,
+ "chosen": true,
+ "use_tmp_table": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "<derived2>",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "<derived2>",
+ "table_scan": {
+ "rows": 10,
+ "cost": 10
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "<derived2>",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 10,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "<derived2>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_execution": {
+ "select_id": 2,
+ "steps": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ } 0 0
+ drop table t1,t2;
+ drop view v1,v2;
+ #
+ # print ref-keyues array
+ #
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status Table is already up to date
+ analyze table t2;
+ Table Op Msg_type Msg_text
+ test.t2 analyze status Engine-independent statistics collected
+ test.t2 analyze status Table is already up to date
+ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 ALL a NULL NULL NULL 100 Using where
+ 1 SIMPLE t2 ref a a 5 test.t1.b 1 Using where
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t2`.`a` AS `a`,`t2`.`b` AS `b`,`t2`.`c` AS `c` from `t1` join `t2` where `t1`.`a` = `t2`.`b` + 2 and `t2`.`a` = `t1`.`b`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = t2.b + 2 and t2.a = t1.b",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "t1.a = t2.b + 2 and multiple equal(t2.a, t1.b)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "t1.a = t2.b + 2 and multiple equal(t2.a, t1.b)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "t1.a = t2.b + 2 and multiple equal(t2.a, t1.b)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t2",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "t2.b + 2",
+ "null_rejecting": false
+ },
+ {
+ "table": "t2",
+ "field": "a",
+ "equals": "t1.b",
+ "null_rejecting": true
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 100,
+ "cost": 2.3174
+ }
+ },
+ {
+ "table": "t2",
+ "table_scan": {
+ "rows": 100,
+ "cost": 2.3174
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 100,
+ "cost": 2.3174,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1"],
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "a",
+ "used_range_estimates": false,
+ "cause": "not available",
+ "rows": 1,
+ "cost": 200,
+ "chosen": true
+ },
+ {
+ "access_type": "scan",
+ "resulting_rows": 100,
+ "cost": 2.3174,
+ "chosen": false
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 100,
+ "cost": 2.3174,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t2"],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "a",
+ "used_range_estimates": false,
+ "cause": "not available",
+ "rows": 1,
+ "cost": 200,
+ "chosen": true
+ },
+ {
+ "access_type": "scan",
+ "resulting_rows": 100,
+ "cost": 2.3174,
+ "chosen": false
+ }
+ ]
+ },
+ "pruned_by_cost": true
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t2.a = t1.b and t1.a = t2.b + 2",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.b is not null"
+ },
+ {
+ "table": "t2",
+ "attached": "t1.a = t2.b + 2"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t1,t2,t0;
+ #
+ # group_by min max optimization
+ #
+ CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT NOT NULL, KEY(a));
+ analyze table t1;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ EXPLAIN SELECT DISTINCT a FROM t1;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 range NULL a 4 NULL 5 Using index for group-by
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ EXPLAIN SELECT DISTINCT a FROM t1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select distinct `t1`.`a` AS `a` from `t1`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 65536,
+ "cost": 13255
+ },
+ "potential_range_indexes": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not applicable"
+ },
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "a",
- "cost": 14627,
- "chosen": false,
- "cause": "cost"
++ "cost": 4812.5,
++ "chosen": true
+ },
+ "group_index_range": {
+ "distinct_query": true,
+ "potential_group_range_indexes": [
+ {
+ "index": "a",
+ "covering": true,
+ "rows": 5,
- "cost": 7.5
++ "cost": 6.75
+ }
+ ]
+ },
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "a",
+ "group_attribute": null,
+ "min_aggregate": false,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "rows": 5,
- "cost": 7.5,
++ "cost": 6.75,
+ "key_parts_used_for_access": ["a"],
+ "ranges": [],
+ "chosen": true
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "index_group",
+ "index": "a",
+ "group_attribute": null,
+ "min_aggregate": false,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "rows": 5,
- "cost": 7.5,
++ "cost": 6.75,
+ "key_parts_used_for_access": ["a"],
+ "ranges": []
+ },
+ "rows_for_plan": 5,
- "cost_for_plan": 7.5,
++ "cost_for_plan": 6.75,
+ "chosen": true
+ }
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "range",
+ "resulting_rows": 5,
- "cost": 7.5,
++ "cost": 6.75,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t1;
+ #
+ # With group by , where clause and MIN/MAX function
+ #
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 index NULL a 20 NULL 7 Using where; Using index
+ select * from information_schema.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select min(`t1`.`d`) AS `MIN(d)` from `t1` where `t1`.`b` = 2 and `t1`.`c` = 3 group by `t1`.`a`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.b = 2 and t1.c = 3",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(2, t1.b) and multiple equal(3, t1.c)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(2, t1.b) and multiple equal(3, t1.c)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(2, t1.b) and multiple equal(3, t1.c)"
+ }
+ ]
+ }
+ },
+ {
+ "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": 7,
+ "cost": 5.5291
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a", "b", "c", "d"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "a",
- "cost": 2.7006,
++ "cost": 1.3869,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "potential_group_range_indexes": [
+ {
+ "index": "a",
+ "covering": true,
+ "ranges": ["2 <= b <= 2 AND 3 <= c <= 3"],
+ "rows": 8,
- "cost": 3.4
++ "cost": 2.2
+ }
+ ]
+ },
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "a",
+ "group_attribute": "d",
+ "min_aggregate": true,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "rows": 8,
- "cost": 3.4,
++ "cost": 2.2,
+ "key_parts_used_for_access": ["a", "b", "c"],
+ "ranges": ["2 <= b <= 2 AND 3 <= c <= 3"],
+ "chosen": false,
+ "cause": "cost"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [],
+ "selectivity_for_columns": [
+ {
+ "column_name": "b",
+ "selectivity_from_histograms": 0.1667
+ },
+ {
+ "column_name": "c",
+ "selectivity_from_histograms": 0.25
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 0.2917,
+ "cost": 3.3707,
+ "chosen": true,
+ "use_tmp_table": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.b = 2 and t1.c = 3",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.b = 2 and t1.c = 3"
+ }
+ ]
+ }
+ },
+ {
+ "reconsidering_access_paths_for_index_ordering": {
+ "clause": "GROUP BY",
+ "fanout": 1,
+ "read_time": 3.3717,
+ "table": "t1",
+ "rows_estimation": 7,
+ "possible_keys": [
+ {
+ "index": "a",
+ "can_resolve_order": true,
+ "updated_limit": 7,
+ "index_scan_time": 7,
+ "records": 7,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ 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;
+ id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
++1 SIMPLE t1 index NULL id 8 NULL 16 Using where; Using index
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`id` AS `id`,min(`t1`.`a`) AS `MIN(a)`,max(`t1`.`a`) AS `MAX(a)` from `t1` where `t1`.`a` >= 20010104e0 group by `t1`.`id`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a >= 20010104e0",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "t1.a >= 20010104e0"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "t1.a >= 20010104e0"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "t1.a >= 20010104e0"
+ }
+ ]
+ }
+ },
+ {
+ "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": 16,
+ "cost": 7.3313
+ },
+ "potential_range_indexes": [
+ {
+ "index": "id",
+ "usable": true,
+ "key_parts": ["id", "a"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "id",
- "cost": 4.6269,
++ "cost": 1.8468,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "potential_group_range_indexes": [
+ {
+ "index": "id",
+ "covering": true,
+ "ranges": ["0x24a20f <= a"],
+ "rows": 9,
- "cost": 3.7
++ "cost": 2.35
+ }
+ ]
+ },
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "id",
+ "group_attribute": "a",
+ "min_aggregate": true,
+ "max_aggregate": true,
+ "distinct_aggregate": false,
+ "rows": 9,
- "cost": 3.7,
++ "cost": 2.35,
+ "key_parts_used_for_access": ["id"],
+ "ranges": ["0x24a20f <= a"],
- "chosen": true
++ "chosen": false,
++ "cause": "cost"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
- },
- "chosen_range_access_summary": {
- "range_access_plan": {
- "type": "index_group",
- "index": "id",
- "group_attribute": "a",
- "min_aggregate": true,
- "max_aggregate": true,
- "distinct_aggregate": false,
- "rows": 9,
- "cost": 3.7,
- "key_parts_used_for_access": ["id"],
- "ranges": ["0x24a20f <= a"]
- },
- "rows_for_plan": 9,
- "cost_for_plan": 3.7,
- "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": 9,
- "cost": 3.7,
++ "access_type": "scan",
++ "resulting_rows": 16,
++ "cost": 2.0312,
+ "chosen": true,
+ "use_tmp_table": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a >= 20010104e0",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.a >= 20010104e0"
+ }
+ ]
+ }
++ },
++ {
++ "reconsidering_access_paths_for_index_ordering": {
++ "clause": "GROUP BY",
++ "fanout": 1,
++ "read_time": 2.0322,
++ "table": "t1",
++ "rows_estimation": 9,
++ "possible_keys": [
++ {
++ "index": "id",
++ "can_resolve_order": true,
++ "updated_limit": 16,
++ "index_scan_time": 16,
++ "records": 16,
++ "chosen": true
++ }
++ ]
++ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id;
+ id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
++1 SIMPLE t1 index NULL id 8 NULL 16 Using where; Using index
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`id` AS `id`,`t1`.`a` AS `a` from `t1` where `t1`.`a` = 20010104e0 group by `t1`.`id`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = 20010104e0",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "t1.a = 20010104e0"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "t1.a = 20010104e0"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "t1.a = 20010104e0"
+ }
+ ]
+ }
+ },
+ {
+ "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": 16,
+ "cost": 7.3313
+ },
+ "potential_range_indexes": [
+ {
+ "index": "id",
+ "usable": true,
+ "key_parts": ["id", "a"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "id",
- "cost": 4.6269,
++ "cost": 1.8468,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "potential_group_range_indexes": [
+ {
+ "index": "id",
+ "covering": true,
+ "ranges": ["0x24a20f <= a <= 0x24a20f"],
+ "rows": 9,
- "cost": 3.7
++ "cost": 2.35
+ }
+ ]
+ },
+ "best_group_range_summary": {
+ "type": "index_group",
+ "index": "id",
+ "group_attribute": null,
+ "min_aggregate": false,
+ "max_aggregate": false,
+ "distinct_aggregate": false,
+ "rows": 9,
- "cost": 3.7,
++ "cost": 2.35,
+ "key_parts_used_for_access": ["id", "a"],
+ "ranges": ["0x24a20f <= a <= 0x24a20f"],
- "chosen": true
++ "chosen": false,
++ "cause": "cost"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
- },
- "chosen_range_access_summary": {
- "range_access_plan": {
- "type": "index_group",
- "index": "id",
- "group_attribute": null,
- "min_aggregate": false,
- "max_aggregate": false,
- "distinct_aggregate": false,
- "rows": 9,
- "cost": 3.7,
- "key_parts_used_for_access": ["id", "a"],
- "ranges": ["0x24a20f <= a <= 0x24a20f"]
- },
- "rows_for_plan": 9,
- "cost_for_plan": 3.7,
- "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": 9,
- "cost": 3.7,
++ "access_type": "scan",
++ "resulting_rows": 16,
++ "cost": 2.0312,
+ "chosen": true,
+ "use_tmp_table": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = 20010104e0",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.a = 20010104e0"
+ }
+ ]
+ }
++ },
++ {
++ "reconsidering_access_paths_for_index_ordering": {
++ "clause": "GROUP BY",
++ "fanout": 1,
++ "read_time": 2.0322,
++ "table": "t1",
++ "rows_estimation": 9,
++ "possible_keys": [
++ {
++ "index": "id",
++ "can_resolve_order": true,
++ "updated_limit": 16,
++ "index_scan_time": 16,
++ "records": 16,
++ "chosen": true
++ }
++ ]
++ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t1;
+ #
+ # Late ORDER BY optimization
+ #
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ set optimizer_trace='enabled=on';
+ explain select * from t1 where a=1 and b=2 order by c limit 1;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 range a_c,a_b a_c 5 NULL 180 Using where
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from t1 where a=1 and b=2 order by c limit 1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`pk` AS `pk`,`t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t1`.`filler` AS `filler` from `t1` where `t1`.`a` = 1 and `t1`.`b` = 2 order by `t1`.`c` limit 1"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.a = 1 and t1.b = 2",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(1, t1.a) and multiple equal(2, t1.b)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(1, t1.a) and multiple equal(2, t1.b)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(1, t1.a) and multiple equal(2, t1.b)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "1",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "1",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "b",
+ "equals": "2",
+ "null_rejecting": false
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 1000,
+ "cost": 232.66
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a_a",
+ "usable": false,
+ "cause": "not applicable"
+ },
+ {
+ "index": "a_c",
+ "usable": true,
+ "key_parts": ["a", "c"]
+ },
+ {
+ "index": "a_b",
+ "usable": true,
+ "key_parts": ["a", "b"]
+ }
+ ],
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no group by or distinct"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "a_c",
+ "ranges": ["1 <= a <= 1"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 180,
- "cost": 217.01,
++ "cost": 231.72,
+ "chosen": true
+ },
+ {
+ "index": "a_b",
+ "ranges": ["1 <= a <= 1 AND 2 <= b <= 2"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 21,
- "cost": 26.21,
++ "cost": 27.445,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a_b",
+ "rows": 21,
+ "ranges": ["1 <= a <= 1 AND 2 <= b <= 2"]
+ },
+ "rows_for_plan": 21,
- "cost_for_plan": 26.21,
++ "cost_for_plan": 27.445,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "a_b",
+ "selectivity_from_index": 0.021
+ }
+ ],
+ "selectivity_for_columns": [
+ {
+ "column_name": "a",
+ "selectivity_from_histograms": 0.0012
+ },
+ {
+ "column_name": "b",
+ "selectivity_from_histograms": 0.001
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "a_c",
+ "used_range_estimates": true,
+ "rows": 180,
+ "cost": 92,
+ "chosen": true
+ },
+ {
+ "access_type": "ref",
+ "index": "a_b",
+ "used_range_estimates": true,
+ "rows": 21,
+ "cost": 22,
+ "chosen": true
+ },
+ {
+ "type": "scan",
+ "chosen": false,
+ "cause": "cost"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.a = 1 and t1.b = 2",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ },
+ {
+ "reconsidering_access_paths_for_index_ordering": {
+ "clause": "ORDER BY",
+ "fanout": 1,
+ "read_time": 22.001,
+ "table": "t1",
+ "rows_estimation": 21,
+ "possible_keys": [
+ {
+ "index": "a_a",
+ "can_resolve_order": true,
+ "updated_limit": 47,
+ "index_scan_time": 47,
+ "usable": false,
+ "cause": "cost"
+ },
+ {
+ "index": "a_c",
+ "can_resolve_order": true,
+ "updated_limit": 47,
+ "range_scan_time": 4.324,
+ "index_scan_time": 4.324,
+ "records": 180,
+ "chosen": true
+ },
+ {
+ "index": "a_b",
+ "can_resolve_order": false,
+ "cause": "not usable index for the query"
+ }
+ ]
+ }
+ },
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 1000,
+ "cost": 1202
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a_a",
+ "usable": false,
+ "cause": "not applicable"
+ },
+ {
+ "index": "a_c",
+ "usable": true,
+ "key_parts": ["a", "c"]
+ },
+ {
+ "index": "a_b",
+ "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": "a_c",
+ "ranges": ["1 <= a <= 1"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 180,
- "cost": 217.01,
++ "cost": 231.72,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a_c",
+ "rows": 180,
+ "ranges": ["1 <= a <= 1"]
+ },
+ "rows_for_plan": 180,
- "cost_for_plan": 217.01,
++ "cost_for_plan": 231.72,
+ "chosen": true
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t1,ten,one_k;
+ #
+ # TABLE ELIMINATION
+ #
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ analyze table t2;
+ Table Op Msg_type Msg_text
+ test.t2 analyze status Engine-independent statistics collected
+ test.t2 analyze status OK
+ analyze table t3;
+ Table Op Msg_type Msg_text
+ test.t3 analyze status Engine-independent statistics collected
+ test.t3 analyze status OK
+ # table t2 should be eliminated
+ explain
+ select t1.a from t1 left join t2 on t1.a=t2.a;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 ALL NULL NULL NULL NULL 4
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain
+ select t1.a from t1 left join t2 on t1.a=t2.a {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`a` AS `a` from (`t1` left join `t2` on(`t1`.`a` = `t2`.`a`))"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t2",
+ "row_may_be_null": true,
+ "map_bit": 1,
+ "depends_on_map_bits": ["0"]
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t2",
+ "field": "a",
+ "equals": "t1.a",
+ "null_rejecting": true
+ }
+ ]
+ },
+ {
+ "eliminated_tables": ["t2"]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 4,
+ "cost": 2.0068
+ }
+ },
+ {
+ "table": "t2",
+ "rows": 1,
+ "cost": 1,
+ "table_type": "const"
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": ["t2"],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ # no tables should be eliminated
+ explain select * from t1 left join t2 on t2.a=t1.a;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 ALL NULL NULL NULL NULL 4
+ 1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from t1 left join t2 on t2.a=t1.a {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`a` AS `a`,`t2`.`a` AS `a`,`t2`.`b` AS `b` from (`t1` left join `t2` on(`t2`.`a` = `t1`.`a`))"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t2",
+ "row_may_be_null": true,
+ "map_bit": 1,
+ "depends_on_map_bits": ["0"]
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t2",
+ "field": "a",
+ "equals": "t1.a",
+ "null_rejecting": true
+ }
+ ]
+ },
+ {
+ "eliminated_tables": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 4,
+ "cost": 2.0068
+ }
+ },
+ {
+ "table": "t2",
+ "table_scan": {
+ "rows": 2,
+ "cost": 2.0044
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1"],
+ "table": "t2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "eq_ref",
+ "index": "PRIMARY",
+ "rows": 1,
+ "cost": 4,
+ "chosen": true
+ },
+ {
+ "access_type": "scan",
+ "resulting_rows": 2,
+ "cost": 8.0176,
+ "chosen": false
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ },
+ {
+ "table": "t2",
+ "attached": "trigcond(trigcond(t1.a is not null))"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ # 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;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 ALL NULL NULL NULL NULL 4
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ 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 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`a` AS `a` from (`t1` left join (`t2` join `t3` on(`t2`.`b` = `t3`.`b`)) on(`t2`.`a` = `t1`.`a` and `t3`.`a` = `t1`.`a`))"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t2",
+ "row_may_be_null": true,
+ "map_bit": 1,
+ "depends_on_map_bits": ["0"]
+ },
+ {
+ "table": "t3",
+ "row_may_be_null": true,
+ "map_bit": 2,
+ "depends_on_map_bits": ["0"]
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t2",
+ "field": "a",
+ "equals": "t1.a",
+ "null_rejecting": true
+ },
+ {
+ "table": "t2",
+ "field": "a",
+ "equals": "t3.a",
+ "null_rejecting": true
+ },
+ {
+ "table": "t3",
+ "field": "a",
+ "equals": "t2.a",
+ "null_rejecting": true
+ },
+ {
+ "table": "t3",
+ "field": "a",
+ "equals": "t1.a",
+ "null_rejecting": true
+ }
+ ]
+ },
+ {
+ "eliminated_tables": ["t3", "t2"]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 4,
+ "cost": 2.0068
+ }
+ },
+ {
+ "table": "t2",
+ "rows": 1,
+ "cost": 1,
+ "table_type": "const"
+ },
+ {
+ "table": "t3",
+ "rows": 1,
+ "cost": 1,
+ "table_type": "const"
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": ["t3", "t2"],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t0, t1, t2, t3;
+ #
+ # IN subquery to sem-join is traced
+ #
+ 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;
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status OK
+ test.t10 analyze status Engine-independent statistics collected
+ test.t10 analyze status OK
+ set optimizer_trace='enabled=on';
+ explain extended select * from t1 where a in (select pk from t10);
+ id select_type table type possible_keys key key_len ref rows filtered Extra
+ 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00
+ 1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
+ 2 MATERIALIZED t10 ALL NULL NULL NULL NULL 10 100.00
+ Warnings:
+ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join (`test`.`t10`) where 1
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain extended select * from t1 where a in (select pk from t10) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 2,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "materialization",
+ "sjm_scan_allowed": true,
+ "possible": true
+ }
+ },
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ }
+ },
+ {
+ "expanded_query": "/* select#2 */ select `t10`.`pk` from `t10`"
+ }
+ ]
+ }
+ },
+ {
+ "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`a` in (/* select#2 */ select `t10`.`pk` from `t10`)"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "transformation": {
+ "select_id": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "converted_to_semi_join": true
+ }
+ },
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "1 and t1.a = t10.pk",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "1 and multiple equal(t1.a, t10.pk)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "1 and multiple equal(t1.a, t10.pk)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(t1.a, t10.pk)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ },
+ {
+ "table": "t10",
+ "row_may_be_null": false,
+ "map_bit": 1,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": []
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 3,
+ "cost": 2.0066
+ }
+ },
+ {
+ "table": "t10",
+ "table_scan": {
+ "rows": 10,
+ "cost": 2.022
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": [
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t10",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 2.022,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0066,
+ "chosen": true
+ }
+ ]
+ },
+ "rest_of_plan": [
+ {
+ "plan_prefix": ["t1"],
+ "table": "t10",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 2.022,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "plan_prefix": [],
+ "table": "t10",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 10,
+ "cost": 2.022,
+ "chosen": true
+ }
+ ]
+ },
+ "pruned_by_heuristic": true
+ }
+ ]
+ },
+ {
+ "condition_on_constant_tables": "1"
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ },
+ {
+ "table": "t10",
+ "attached": null
+ },
+ {
+ "table": "<subquery2>",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t0,t1,t11,t10,t12,t2;
+ #
+ # Selectivities for columns and indexes.
+ #
+ 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 ();
+ Table Op Msg_type Msg_text
+ test.t1 analyze status Engine-independent statistics collected
+ test.t1 analyze status Table is already up to date
+ 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;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t1 ref pk,pk_a,pk_a_b pk_a_b 15 const,const,const 1 Using index
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain select * from t1 where pk = 2 and a=5 and b=1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `t1`.`pk` AS `pk`,`t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where `t1`.`pk` = 2 and `t1`.`a` = 5 and `t1`.`b` = 1"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.pk = 2 and t1.a = 5 and t1.b = 1",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal(2, t1.pk) and multiple equal(5, t1.a) and multiple equal(1, t1.b)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal(2, t1.pk) and multiple equal(5, t1.a) and multiple equal(1, t1.b)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal(2, t1.pk) and multiple equal(5, t1.a) and 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": [
+ {
+ "table": "t1",
+ "field": "pk",
+ "equals": "2",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "pk",
+ "equals": "2",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "5",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "pk",
+ "equals": "2",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "a",
+ "equals": "5",
+ "null_rejecting": false
+ },
+ {
+ "table": "t1",
+ "field": "b",
+ "equals": "1",
+ "null_rejecting": false
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 10,
+ "cost": 6.1317
+ },
+ "potential_range_indexes": [
+ {
+ "index": "pk",
+ "usable": true,
+ "key_parts": ["pk"]
+ },
+ {
+ "index": "pk_a",
+ "usable": true,
+ "key_parts": ["pk", "a"]
+ },
+ {
+ "index": "pk_a_b",
+ "usable": true,
+ "key_parts": ["pk", "a", "b"]
+ }
+ ],
+ "best_covering_index_scan": {
+ "index": "pk_a_b",
- "cost": 3.3708,
++ "cost": 1.5429,
+ "chosen": true
+ },
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no group by or distinct"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "pk",
+ "ranges": ["2 <= pk <= 2"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
- "cost": 2.21,
- "chosen": true
++ "cost": 2.3773,
++ "chosen": false,
++ "cause": "cost"
+ },
+ {
+ "index": "pk_a",
+ "ranges": ["2 <= pk <= 2 AND 5 <= a <= 5"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
- "cost": 2.21,
++ "cost": 2.3783,
+ "chosen": false,
+ "cause": "cost"
+ },
+ {
+ "index": "pk_a_b",
+ "ranges": ["2 <= pk <= 2 AND 5 <= a <= 5 AND 1 <= b <= 1"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": true,
+ "rows": 1,
- "cost": 2.21,
- "chosen": false,
- "cause": "cost"
++ "cost": 1.1793,
++ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "intersecting_indexes": [
+ {
+ "index": "pk",
- "index_scan_cost": 1,
- "cumulateed_index_scan_cost": 1,
++ "index_scan_cost": 1.0023,
++ "cumulateed_index_scan_cost": 1.0023,
+ "disk_sweep_cost": 0.9008,
- "cumulative_total_cost": 1.9008,
++ "cumulative_total_cost": 1.9031,
+ "usable": true,
+ "matching_rows_now": 1,
+ "intersect_covering_with_this_index": false,
+ "chosen": true
+ },
+ {
+ "index": "pk_a",
+ "usable": false,
+ "cause": "does not reduce cost of intersect"
+ },
+ {
+ "index": "pk_a_b",
+ "usable": false,
+ "cause": "does not reduce cost of intersect"
+ }
+ ],
+ "clustered_pk": {
+ "clustered_pk_added_to_intersect": false,
+ "cause": "no clustered pk index"
+ },
+ "chosen": false,
- "cause": "too few indexes to merge"
++ "cause": "cost"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
- "index": "pk",
++ "index": "pk_a_b",
+ "rows": 1,
- "ranges": ["2 <= pk <= 2"]
++ "ranges": ["2 <= pk <= 2 AND 5 <= a <= 5 AND 1 <= b <= 1"]
+ },
+ "rows_for_plan": 1,
- "cost_for_plan": 2.21,
++ "cost_for_plan": 1.1793,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "pk_a_b",
+ "selectivity_from_index": 0.1
+ }
+ ],
+ "selectivity_for_columns": [
+ {
+ "column_name": "a",
+ "selectivity_from_histograms": 0.1
+ },
+ {
+ "column_name": "b",
+ "selectivity_from_histograms": 0.1
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "pk",
+ "used_range_estimates": true,
+ "rows": 1,
+ "cost": 2,
+ "chosen": true
+ },
+ {
+ "access_type": "ref",
+ "index": "pk_a",
+ "used_range_estimates": true,
+ "rows": 1,
+ "cost": 2,
+ "chosen": false,
+ "cause": "cost"
+ },
+ {
+ "access_type": "ref",
+ "index": "pk_a_b",
+ "used_range_estimates": true,
+ "rows": 1,
- "cost": 1,
++ "cost": 1.0043,
+ "chosen": true
+ },
+ {
- "access_type": "range",
- "resulting_rows": 1,
- "cost": 2.21,
- "chosen": false
++ "type": "scan",
++ "chosen": false,
++ "cause": "cost"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.pk = 2 and t1.a = 5 and t1.b = 1",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ 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";
+ #
+ # Tests added to show that sub-statements are not traced
+ #
+ 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);
+ 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|
+ Warnings:
+ Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead
+ set optimizer_trace='enabled=on';
+ select f1(a) from t1;
+ f1(a)
+ 4
+ 4
+ 4
+ 4
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select f1(a) from t1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `f1`(`t1`.`a`) AS `f1(a)` from `t1`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 4,
+ "cost": 2.0068
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ select f2(a) from t1;
+ f2(a)
+ 4
+ 4
+ 4
+ 4
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select f2(a) from t1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select `f2`(`t1`.`a`) AS `f2(a)` from `t1`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "table_scan": {
+ "rows": 4,
+ "cost": 2.0068
+ }
+ }
+ ]
+ },
+ {
+ "execution_plan_for_potential_materialization": {
+ "steps": []
+ }
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+ } 0 0
+ drop table t1,t2;
+ drop function f1;
+ drop function f2;
+ set optimizer_trace='enabled=off';
+ #
+ # MDEV-18489: Limit the memory used by the optimizer trace
+ #
+ 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;
+ a
+ 1
+ 2
+ select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ length(trace)
+ 1889
+ set optimizer_trace_max_mem_size=100;
+ select * from t1;
+ a
+ 1
+ 2
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select * from t1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ 1789 0
+ set optimizer_trace_max_mem_size=0;
+ select * from t1;
+ a
+ 1
+ 2
+ select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ select * from t1 1889 0
+ drop table t1;
+ set optimizer_trace='enabled=off';
+ set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
+ #
+ # MDEV-18527: Optimizer trace for DELETE query shows table:null
+ #
+ 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;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t0 range a a 5 NULL 3 Using where
+ select * from information_schema.optimizer_trace;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain delete from t0 where t0.a<3 {
+ "steps": [
+ {
+ "table": "t0",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 10,
+ "cost": 6.122
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a"]
+ }
+ ],
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no join"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "a",
+ "ranges": ["NULL < a < 3"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 3,
- "cost": 4.61,
++ "cost": 5.007,
+ "chosen": true
+ }
+ ],
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a",
+ "rows": 3,
+ "ranges": ["NULL < a < 3"]
+ },
+ "rows_for_plan": 3,
- "cost_for_plan": 4.61,
++ "cost_for_plan": 5.007,
+ "chosen": true
+ }
+ }
+ }
+ ]
+ } 0 0
+ drop table ten,t0;
+ set optimizer_trace='enabled=off';
+ #
+ # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
+ #
+ 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;
+ id select_type table type possible_keys key key_len ref rows Extra
+ 1 SIMPLE t0 range a a 5 NULL 3 Using where
+ 1 SIMPLE t1 ref a a 5 test.t0.a 1
+ select * from information_schema.optimizer_trace;
+ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ explain delete from t0 where t0.a<3 {
+ "steps": [
+ {
+ "table": "t0",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 10,
+ "cost": 6.122
+ },
+ "potential_range_indexes": [
+ {
+ "index": "a",
+ "usable": true,
+ "key_parts": ["a"]
+ }
+ ],
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no join"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "a",
+ "ranges": ["NULL < a < 3"],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 3,
- "cost": 4.61,
++ "cost": 5.007,
+ "chosen": true
+ }
+ ],
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "a",
+ "rows": 3,
+ "ranges": ["NULL < a < 3"]
+ },
+ "rows_for_plan": 3,
- "cost_for_plan": 4.61,
++ "cost_for_plan": 5.007,
+ "chosen": true
+ }
+ }
+ }
+ ]
+ } 0 0
+ drop table ten,t0,t1;
diff --cc mysql-test/main/opt_trace_index_merge.result
index 0000000,4c75465..855a725
mode 000000,100644..100644
--- a/mysql-test/main/opt_trace_index_merge.result
+++ b/mysql-test/main/opt_trace_index_merge.result
@@@ -1,0 -1,249 +1,249 @@@
+ 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,
++ "cost": 1.1773,
+ "chosen": true
+ }
+ ],
+ "index_to_merge": "a",
- "cumulated_cost": 2.21
++ "cumulated_cost": 1.1773
+ },
+ {
+ "range_scan_alternatives": [
+ {
+ "index": "b",
+ "ranges": ["1 <= b <= 1"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": true,
+ "rows": 1,
- "cost": 2.21,
++ "cost": 1.1773,
+ "chosen": true
+ }
+ ],
+ "index_to_merge": "b",
- "cumulated_cost": 4.42
++ "cumulated_cost": 2.3547
+ }
+ ],
- "cost_of_reading_ranges": 4.42,
++ "cost_of_reading_ranges": 2.3547,
+ "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,
++ "index_roworder_union_cost": 4.1484,
+ "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,
++ "cost_for_plan": 4.1484,
+ "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,
++ "cost": 4.1484,
+ "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;
diff --cc mysql-test/main/opt_trace_index_merge_innodb.result
index 0000000,a0f03e3..43c9462
mode 000000,100644..100644
--- a/mysql-test/main/opt_trace_index_merge_innodb.result
+++ b/mysql-test/main/opt_trace_index_merge_innodb.result
@@@ -1,0 -1,242 +1,248 @@@
++set @innodb_stats_persistent_save= @@innodb_stats_persistent;
++set @innodb_stats_persistent_sample_pages_save=
++@@innodb_stats_persistent_sample_pages;
++set global innodb_stats_persistent= 1;
++set global innodb_stats_persistent_sample_pages=100;
+ 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
++ "rows": 1000,
++ "cost": 206.39,
++ "chosen": false,
++ "cause": "cost"
+ },
+ {
+ "index": "key1",
+ "ranges": ["1 <= key1 <= 1"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
- "cost": 2.21,
++ "cost": 2.3751,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "intersecting_indexes": [
+ {
+ "index": "key1",
- "index_scan_cost": 1,
- "cumulateed_index_scan_cost": 1,
++ "index_scan_cost": 1.0001,
++ "cumulateed_index_scan_cost": 1.0001,
+ "disk_sweep_cost": 1.0014,
- "cumulative_total_cost": 2.0014,
++ "cumulative_total_cost": 2.0015,
+ "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,
++ "cost_for_plan": 2.3751,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "PRIMARY",
- "selectivity_from_index": 1.001
++ "selectivity_from_index": 1
+ },
+ {
+ "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";
++set global innodb_stats_persistent= @innodb_stats_persistent_save;
++set global innodb_stats_persistent_sample_pages=
++@innodb_stats_persistent_sample_pages_save;
diff --cc mysql-test/main/opt_trace_index_merge_innodb.test
index 0000000,5e18185..199c45b
mode 000000,100644..100644
--- a/mysql-test/main/opt_trace_index_merge_innodb.test
+++ b/mysql-test/main/opt_trace_index_merge_innodb.test
@@@ -1,0 -1,31 +1,45 @@@
+ --source include/not_embedded.inc
+ --source include/have_innodb.inc
++
++set @innodb_stats_persistent_save= @@innodb_stats_persistent;
++set @innodb_stats_persistent_sample_pages_save=
++ @@innodb_stats_persistent_sample_pages;
++
++set global innodb_stats_persistent= 1;
++set global innodb_stats_persistent_sample_pages=100;
++
+ 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";
++
++
++set global innodb_stats_persistent= @innodb_stats_persistent_save;
++set global innodb_stats_persistent_sample_pages=
++ @innodb_stats_persistent_sample_pages_save;
++
diff --cc mysql-test/suite/sys_vars/r/sysvars_server_embedded,32bit.rdiff
index 3bb4494,4ec990d..36254fa
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded,32bit.rdiff
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded,32bit.rdiff
@@@ -694,7 -685,20 +694,20 @@@
VARIABLE_COMMENT Controls number of record samples to check condition selectivity
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 4294967295
- @@ -2762,7 +2762,7 @@
+ @@ -2762,10 +2762,10 @@
+ GLOBAL_VALUE_ORIGIN COMPILE-TIME
+ DEFAULT_VALUE 1048576
+ VARIABLE_SCOPE SESSION
+ -VARIABLE_TYPE BIGINT UNSIGNED
+ +VARIABLE_TYPE INT UNSIGNED
+ VARIABLE_COMMENT Maximum allowed size of an optimizer trace
+ NUMERIC_MIN_VALUE 0
+ -NUMERIC_MAX_VALUE 18446744073709551615
+ +NUMERIC_MAX_VALUE 4294967295
+ NUMERIC_BLOCK_SIZE 1
+ ENUM_VALUE_LIST NULL
+ READ_ONLY NO
-@@ -2776,7 +2776,7 @@
++@@ -2790,7 +2790,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4
VARIABLE_SCOPE SESSION
@@@ -703,7 -707,7 +716,7 @@@
VARIABLE_COMMENT Controls selectivity of which conditions the optimizer takes into account to calculate cardinality of a partial join when it searches for the best execution plan Meaning: 1 - use selectivity of index backed range conditions to calculate the cardinality of a partial join if the last joined table is accessed by full table scan or an index scan, 2 - use selectivity of index backed range conditions to calculate the cardinality of a partial join in any case, 3 - additionally always use selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join, 4 - use histograms to calculate selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join.5 - additionally use selectivity of certain non-range predicates calculated on record samples
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 5
- @@ -2790,7 +2790,7 @@
-@@ -2804,7 +2804,7 @@
++@@ -2818,7 +2818,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -712,7 -716,7 +725,7 @@@
VARIABLE_COMMENT Maximum number of instrumented user@host accounts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2804,7 +2804,7 @@
-@@ -2818,7 +2818,7 @@
++@@ -2832,7 +2832,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -721,7 -725,7 +734,7 @@@
VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 200
- @@ -2818,7 +2818,7 @@
-@@ -2832,7 +2832,7 @@
++@@ -2846,7 +2846,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -730,7 -734,7 +743,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_STAGES_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2832,7 +2832,7 @@
-@@ -2846,7 +2846,7 @@
++@@ -2860,7 +2860,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -739,7 -743,7 +752,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STAGES_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -2846,7 +2846,7 @@
-@@ -2860,7 +2860,7 @@
++@@ -2874,7 +2874,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -748,7 -752,7 +761,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_STATEMENTS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2860,7 +2860,7 @@
-@@ -2874,7 +2874,7 @@
++@@ -2898,7 +2898,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -757,7 -761,7 +770,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STATEMENTS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -2874,7 +2874,7 @@
-@@ -2888,7 +2888,7 @@
++@@ -2902,7 +2902,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -766,7 -770,7 +779,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_WAITS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2888,7 +2888,7 @@
-@@ -2902,7 +2902,7 @@
++@@ -2916,7 +2916,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -775,7 -779,7 +788,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_WAITS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -2902,7 +2902,7 @@
-@@ -2916,7 +2916,7 @@
++@@ -2930,7 +2930,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -784,7 -788,7 +797,7 @@@
VARIABLE_COMMENT Maximum number of instrumented hosts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2916,7 +2916,7 @@
-@@ -2930,7 +2930,7 @@
++@@ -2944,7 +2944,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 80
VARIABLE_SCOPE GLOBAL
@@@ -793,7 -797,7 +806,7 @@@
VARIABLE_COMMENT Maximum number of condition instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -2930,7 +2930,7 @@
-@@ -2944,7 +2944,7 @@
++@@ -2958,7 +2958,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -802,7 -806,7 +815,7 @@@
VARIABLE_COMMENT Maximum number of instrumented condition objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -2944,7 +2944,7 @@
-@@ -2958,7 +2958,7 @@
++@@ -2972,7 +2972,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
@@@ -811,7 -815,7 +824,7 @@@
VARIABLE_COMMENT Maximum length considered for digest text, when stored in performance_schema tables.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
- @@ -2958,7 +2958,7 @@
-@@ -2972,7 +2972,7 @@
++@@ -2986,7 +2986,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@@@ -820,7 -824,7 +833,7 @@@
VARIABLE_COMMENT Maximum number of file instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -2972,7 +2972,7 @@
-@@ -2986,7 +2986,7 @@
++@@ -3000,7 +3000,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32768
VARIABLE_SCOPE GLOBAL
@@@ -829,7 -833,7 +842,7 @@@
VARIABLE_COMMENT Maximum number of opened instrumented files.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
- @@ -2986,7 +2986,7 @@
-@@ -3000,7 +3000,7 @@
++@@ -3014,7 +3014,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -838,7 -842,7 +851,7 @@@
VARIABLE_COMMENT Maximum number of instrumented files. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3000,7 +3000,7 @@
-@@ -3014,7 +3014,7 @@
++@@ -3028,7 +3028,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL
@@@ -847,7 -851,7 +860,7 @@@
VARIABLE_COMMENT Maximum number of mutex instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3014,7 +3014,7 @@
-@@ -3028,7 +3028,7 @@
++@@ -3042,7 +3042,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -856,7 -860,7 +869,7 @@@
VARIABLE_COMMENT Maximum number of instrumented MUTEX objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
- @@ -3028,7 +3028,7 @@
-@@ -3042,7 +3042,7 @@
++@@ -3056,7 +3056,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 40
VARIABLE_SCOPE GLOBAL
@@@ -865,7 -869,7 +878,7 @@@
VARIABLE_COMMENT Maximum number of rwlock instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3042,7 +3042,7 @@
-@@ -3056,7 +3056,7 @@
++@@ -3070,7 +3070,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -874,7 -878,7 +887,7 @@@
VARIABLE_COMMENT Maximum number of instrumented RWLOCK objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
- @@ -3056,7 +3056,7 @@
-@@ -3070,7 +3070,7 @@
++@@ -3084,7 +3084,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@@@ -883,7 -887,7 +896,7 @@@
VARIABLE_COMMENT Maximum number of socket instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3070,7 +3070,7 @@
-@@ -3084,7 +3084,7 @@
++@@ -3098,7 +3098,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -892,7 -896,7 +905,7 @@@
VARIABLE_COMMENT Maximum number of opened instrumented sockets. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3084,7 +3084,7 @@
-@@ -3098,7 +3098,7 @@
++@@ -3112,7 +3112,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 160
VARIABLE_SCOPE GLOBAL
@@@ -901,7 -905,7 +914,7 @@@
VARIABLE_COMMENT Maximum number of stage instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3098,7 +3098,7 @@
-@@ -3112,7 +3112,7 @@
++@@ -3126,7 +3126,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 202
VARIABLE_SCOPE GLOBAL
@@@ -910,7 -914,7 +923,7 @@@
VARIABLE_COMMENT Maximum number of statement instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3112,7 +3112,7 @@
-@@ -3126,7 +3126,7 @@
++@@ -3140,7 +3140,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -919,7 -923,7 +932,7 @@@
VARIABLE_COMMENT Maximum number of opened instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3126,7 +3126,7 @@
-@@ -3140,7 +3140,7 @@
++@@ -3154,7 +3154,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -928,7 -932,7 +941,7 @@@
VARIABLE_COMMENT Maximum number of instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3140,7 +3140,7 @@
-@@ -3154,7 +3154,7 @@
++@@ -3168,7 +3168,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@@@ -937,7 -941,7 +950,7 @@@
VARIABLE_COMMENT Maximum number of thread instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3154,7 +3154,7 @@
-@@ -3168,7 +3168,7 @@
++@@ -3182,7 +3182,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -946,7 -950,7 +959,7 @@@
VARIABLE_COMMENT Maximum number of instrumented threads. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3168,7 +3168,7 @@
-@@ -3182,7 +3182,7 @@
++@@ -3196,7 +3196,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -955,7 -959,7 +968,7 @@@
VARIABLE_COMMENT Size of session attribute string buffer per thread. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3182,7 +3182,7 @@
-@@ -3196,7 +3196,7 @@
++@@ -3210,7 +3210,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@@@ -964,7 -968,7 +977,7 @@@
VARIABLE_COMMENT Maximum number of rows in SETUP_ACTORS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1024
- @@ -3196,7 +3196,7 @@
-@@ -3210,7 +3210,7 @@
++@@ -3224,7 +3224,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@@@ -973,7 -977,7 +986,7 @@@
VARIABLE_COMMENT Maximum number of rows in SETUP_OBJECTS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
- @@ -3210,7 +3210,7 @@
-@@ -3224,7 +3224,7 @@
++@@ -3238,7 +3238,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -982,7 -986,7 +995,7 @@@
VARIABLE_COMMENT Maximum number of instrumented users. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3266,7 +3266,7 @@
-@@ -3280,7 +3280,7 @@
++@@ -3294,7 +3294,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32768
VARIABLE_SCOPE SESSION
@@@ -991,7 -995,7 +1004,7 @@@
VARIABLE_COMMENT The size of the buffer that is allocated when preloading indexes
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
- @@ -3294,7 +3294,7 @@
-@@ -3308,7 +3308,7 @@
++@@ -3322,7 +3322,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 15
VARIABLE_SCOPE SESSION
@@@ -1000,7 -1004,7 +1013,7 @@@
VARIABLE_COMMENT Number of statements about which profiling information is maintained. If set to 0, no profiles are stored. See SHOW PROFILES.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
- @@ -3308,7 +3308,7 @@
-@@ -3322,7 +3322,7 @@
++@@ -3336,7 +3336,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 5
VARIABLE_SCOPE SESSION
@@@ -1009,7 -1013,7 +1022,7 @@@
VARIABLE_COMMENT Seconds between sending progress reports to the client for time-consuming statements. Set to 0 to disable progress reporting.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3392,7 +3392,7 @@
-@@ -3406,7 +3406,7 @@
++@@ -3420,7 +3420,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 16384
VARIABLE_SCOPE SESSION
@@@ -1018,7 -1022,7 +1031,7 @@@
VARIABLE_COMMENT Allocation block size for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
- @@ -3406,7 +3406,7 @@
-@@ -3420,7 +3420,7 @@
++@@ -3434,7 +3434,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1048576
VARIABLE_SCOPE GLOBAL
@@@ -1027,7 -1031,7 +1040,7 @@@
VARIABLE_COMMENT Don't cache results that are bigger than this
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3420,7 +3420,7 @@
-@@ -3434,7 +3434,7 @@
++@@ -3458,7 +3458,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE GLOBAL
@@@ -1036,7 -1040,7 +1049,7 @@@
VARIABLE_COMMENT The minimum size for blocks allocated by the query cache
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3437,7 +3437,7 @@
-@@ -3451,7 +3451,7 @@
++@@ -3465,7 +3465,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The memory allocated to store results from old queries
NUMERIC_MIN_VALUE 0
@@@ -1045,7 -1049,7 +1058,7 @@@
NUMERIC_BLOCK_SIZE 1024
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -3490,7 +3490,7 @@
-@@ -3504,7 +3504,7 @@
++@@ -3518,7 +3518,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 24576
VARIABLE_SCOPE SESSION
@@@ -1054,7 -1058,7 +1067,7 @@@
VARIABLE_COMMENT Persistent buffer for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
- @@ -3504,7 +3504,7 @@
-@@ -3518,7 +3518,7 @@
++@@ -3532,7 +3532,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@@@ -1063,7 -1067,7 +1076,7 @@@
VARIABLE_COMMENT Allocation block size for storing ranges during optimization
NUMERIC_MIN_VALUE 4096
NUMERIC_MAX_VALUE 4294967295
- @@ -3518,7 +3518,7 @@
-@@ -3532,7 +3532,7 @@
++@@ -3546,7 +3546,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 131072
VARIABLE_SCOPE SESSION
@@@ -1072,7 -1076,7 +1085,7 @@@
VARIABLE_COMMENT Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value
NUMERIC_MIN_VALUE 8192
NUMERIC_MAX_VALUE 2147483647
- @@ -3546,7 +3546,7 @@
-@@ -3560,7 +3560,7 @@
++@@ -3574,7 +3574,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 262144
VARIABLE_SCOPE SESSION
@@@ -1081,7 -1085,7 +1094,7 @@@
VARIABLE_COMMENT When reading rows in sorted order after a sort, the rows are read through this buffer to avoid a disk seeks
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 2147483647
- @@ -3560,10 +3560,10 @@
-@@ -3574,10 +3574,10 @@
++@@ -3598,10 +3598,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8388608
VARIABLE_SCOPE SESSION
@@@ -1094,7 -1098,7 +1107,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -3616,7 +3616,7 @@
-@@ -3630,7 +3630,7 @@
++@@ -3644,7 +3644,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
@@@ -1103,7 -1107,7 +1116,7 @@@
VARIABLE_COMMENT Uniquely identifies the server instance in the community of replication partners
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
- @@ -3714,7 +3714,7 @@
-@@ -3728,7 +3728,7 @@
++@@ -3742,7 +3742,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1073741824
VARIABLE_SCOPE GLOBAL
@@@ -1112,7 -1116,7 +1125,7 @@@
VARIABLE_COMMENT The maximum packet length to sent successfully from the master to slave.
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
- @@ -3728,7 +3728,7 @@
-@@ -3742,7 +3742,7 @@
++@@ -3756,7 +3756,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 2
VARIABLE_SCOPE GLOBAL
@@@ -1121,7 -1125,7 +1134,7 @@@
VARIABLE_COMMENT If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
- @@ -3787,7 +3787,7 @@
-@@ -3801,7 +3801,7 @@
++@@ -3715,7 +3715,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Each thread that needs to do a sort allocates a buffer of this size
NUMERIC_MIN_VALUE 1024
@@@ -1130,7 -1134,7 +1143,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4078,7 +4078,7 @@
-@@ -4092,7 +4092,7 @@
++@@ -4106,7 +4106,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@@@ -1139,7 -1143,7 +1152,7 @@@
VARIABLE_COMMENT The soft upper limit for number of cached stored routines for one connection.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 524288
- @@ -4176,7 +4176,7 @@
-@@ -4190,7 +4190,7 @@
++@@ -4204,7 +4204,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 400
VARIABLE_SCOPE GLOBAL
@@@ -1148,7 -1152,7 +1161,7 @@@
VARIABLE_COMMENT The number of cached table definitions
NUMERIC_MIN_VALUE 400
NUMERIC_MAX_VALUE 2097152
- @@ -4190,7 +4190,7 @@
-@@ -4204,7 +4204,7 @@
++@@ -4218,7 +4218,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 2000
VARIABLE_SCOPE GLOBAL
@@@ -1157,7 -1161,7 +1170,7 @@@
VARIABLE_COMMENT The number of cached open tables
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 1048576
- @@ -4274,7 +4274,7 @@
-@@ -4288,7 +4288,7 @@
++@@ -4302,7 +4302,7 @@
GLOBAL_VALUE_ORIGIN AUTO
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@@@ -1166,7 -1170,7 +1179,7 @@@
VARIABLE_COMMENT How many threads we should keep in a cache for reuse. These are freed after 5 minutes of idle time
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16384
- @@ -4288,7 +4288,7 @@
-@@ -4302,7 +4302,7 @@
++@@ -4316,7 +4316,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@@@ -1175,7 -1179,7 +1188,7 @@@
VARIABLE_COMMENT Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.This variable has no effect, and is deprecated. It will be removed in a future release.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 512
- @@ -4395,15 +4395,15 @@
-@@ -4409,15 +4409,15 @@
++@@ -4423,15 +4423,15 @@
READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME TMP_DISK_TABLE_SIZE
@@@ -1195,7 -1199,7 +1208,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4417,7 +4417,7 @@
-@@ -4431,7 +4431,7 @@
++@@ -4445,7 +4445,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT If an internal in-memory temporary table exceeds this size, MariaDB will automatically convert it to an on-disk MyISAM or Aria table. Same as tmp_table_size.
NUMERIC_MIN_VALUE 1024
@@@ -1204,7 -1208,7 +1217,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4431,7 +4431,7 @@
-@@ -4445,7 +4445,7 @@
++@@ -4459,7 +4459,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Alias for tmp_memory_table_size. If an internal in-memory temporary table exceeds this size, MariaDB will automatically convert it to an on-disk MyISAM or Aria table.
NUMERIC_MIN_VALUE 1024
@@@ -1213,7 -1217,7 +1226,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4442,7 +4442,7 @@
-@@ -4456,7 +4456,7 @@
++@@ -4470,7 +4470,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8192
VARIABLE_SCOPE SESSION
@@@ -1222,7 -1226,7 +1235,7 @@@
VARIABLE_COMMENT Allocation block size for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
- @@ -4456,7 +4456,7 @@
-@@ -4470,7 +4470,7 @@
++@@ -4484,7 +4484,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@@@ -1231,7 -1235,7 +1244,7 @@@
VARIABLE_COMMENT Persistent buffer for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
- @@ -4554,7 +4554,7 @@
-@@ -4568,7 +4568,7 @@
++@@ -4582,7 +4582,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 28800
VARIABLE_SCOPE SESSION
@@@ -1240,7 -1244,7 +1253,7 @@@
VARIABLE_COMMENT The number of seconds the server waits for activity on a connection before closing it
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 31536000
- @@ -4659,7 +4659,7 @@
-@@ -4673,7 +4673,7 @@
++@@ -4687,7 +4687,7 @@
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME OPEN_FILES_LIMIT
VARIABLE_SCOPE GLOBAL
@@@ -1249,7 -1253,7 +1262,7 @@@
VARIABLE_COMMENT If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 or autoset then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of file descriptors
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -4672,7 +4672,7 @@
-@@ -4686,7 +4686,7 @@
++@@ -4700,7 +4700,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@@@ -1258,7 -1262,7 +1271,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4682,7 +4682,7 @@
-@@ -4696,7 +4696,7 @@
++@@ -4710,7 +4710,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@@@ -1267,7 -1271,7 +1280,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4777,7 +4777,7 @@
-@@ -4791,7 +4791,7 @@
++@@ -4805,7 +4805,7 @@
VARIABLE_NAME LOG_TC_SIZE
GLOBAL_VALUE_ORIGIN AUTO
VARIABLE_SCOPE GLOBAL
diff --cc mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index ddaa495,c896df1..628ba00
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@@ -2753,9 -2739,37 +2753,37 @@@ VARIABLE_COMMENT Fine-tune the optimize
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
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
+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,rowid_filter,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
diff --cc mysql-test/suite/sys_vars/r/sysvars_server_notembedded,32bit.rdiff
index f51f1a1,53a74f9..13f9c78
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded,32bit.rdiff
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded,32bit.rdiff
@@@ -694,7 -685,20 +694,20 @@@
VARIABLE_COMMENT Controls number of record samples to check condition selectivity
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 4294967295
- @@ -2986,7 +2986,7 @@
+ @@ -2986,10 +2986,10 @@
+ GLOBAL_VALUE_ORIGIN COMPILE-TIME
+ DEFAULT_VALUE 1048576
+ VARIABLE_SCOPE SESSION
+ -VARIABLE_TYPE BIGINT UNSIGNED
+ +VARIABLE_TYPE INT UNSIGNED
+ VARIABLE_COMMENT Maximum allowed size of an optimizer trace
+ NUMERIC_MIN_VALUE 0
+ -NUMERIC_MAX_VALUE 18446744073709551615
+ +NUMERIC_MAX_VALUE 4294967295
+ NUMERIC_BLOCK_SIZE 1
+ ENUM_VALUE_LIST NULL
+ READ_ONLY NO
-@@ -3000,7 +3000,7 @@
++@@ -2996,7 +2996,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4
VARIABLE_SCOPE SESSION
@@@ -703,7 -707,7 +716,7 @@@
VARIABLE_COMMENT Controls selectivity of which conditions the optimizer takes into account to calculate cardinality of a partial join when it searches for the best execution plan Meaning: 1 - use selectivity of index backed range conditions to calculate the cardinality of a partial join if the last joined table is accessed by full table scan or an index scan, 2 - use selectivity of index backed range conditions to calculate the cardinality of a partial join in any case, 3 - additionally always use selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join, 4 - use histograms to calculate selectivity of range conditions that are not backed by any index to calculate the cardinality of a partial join.5 - additionally use selectivity of certain non-range predicates calculated on record samples
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 5
- @@ -3014,7 +3014,7 @@
-@@ -3028,7 +3028,7 @@
++@@ -3042,7 +3042,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -712,7 -716,7 +725,7 @@@
VARIABLE_COMMENT Maximum number of instrumented user@host accounts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3028,7 +3028,7 @@
-@@ -3042,7 +3042,7 @@
++@@ -3056,7 +3056,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -721,7 -725,7 +734,7 @@@
VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 200
- @@ -3042,7 +3042,7 @@
-@@ -3056,7 +3056,7 @@
++@@ -3070,7 +3070,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -730,7 -734,7 +743,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_STAGES_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3056,7 +3056,7 @@
-@@ -3070,7 +3070,7 @@
++@@ -3084,7 +3084,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -739,7 -743,7 +752,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STAGES_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -3070,7 +3070,7 @@
-@@ -3084,7 +3084,7 @@
++@@ -3098,7 +3098,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -748,7 -752,7 +761,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_STATEMENTS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3084,7 +3084,7 @@
-@@ -3098,7 +3098,7 @@
++@@ -3112,7 +3112,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -757,7 -761,7 +770,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_STATEMENTS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -3098,7 +3098,7 @@
-@@ -3112,7 +3112,7 @@
++@@ -3126,7 +3126,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -766,7 -770,7 +779,7 @@@
VARIABLE_COMMENT Number of rows in EVENTS_WAITS_HISTORY_LONG. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3112,7 +3112,7 @@
-@@ -3126,7 +3126,7 @@
++@@ -3140,7 +3140,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -775,7 -779,7 +788,7 @@@
VARIABLE_COMMENT Number of rows per thread in EVENTS_WAITS_HISTORY. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1024
- @@ -3126,7 +3126,7 @@
-@@ -3140,7 +3140,7 @@
++@@ -3154,7 +3154,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -784,7 -788,7 +797,7 @@@
VARIABLE_COMMENT Maximum number of instrumented hosts. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3140,7 +3140,7 @@
-@@ -3154,7 +3154,7 @@
++@@ -3168,7 +3168,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 80
VARIABLE_SCOPE GLOBAL
@@@ -793,7 -797,7 +806,7 @@@
VARIABLE_COMMENT Maximum number of condition instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3154,7 +3154,7 @@
-@@ -3168,7 +3168,7 @@
++@@ -3182,7 +3182,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -802,7 -806,7 +815,7 @@@
VARIABLE_COMMENT Maximum number of instrumented condition objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3168,7 +3168,7 @@
-@@ -3182,7 +3182,7 @@
++@@ -3196,7 +3196,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1024
VARIABLE_SCOPE GLOBAL
@@@ -811,7 -815,7 +824,7 @@@
VARIABLE_COMMENT Maximum length considered for digest text, when stored in performance_schema tables.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
- @@ -3182,7 +3182,7 @@
-@@ -3196,7 +3196,7 @@
++@@ -3210,7 +3210,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@@@ -838,7 -842,7 +851,7 @@@
VARIABLE_COMMENT Maximum number of instrumented files. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3224,7 +3224,7 @@
-@@ -3238,7 +3238,7 @@
++@@ -3252,7 +3252,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL
@@@ -847,7 -851,7 +860,7 @@@
VARIABLE_COMMENT Maximum number of mutex instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3238,7 +3238,7 @@
-@@ -3252,7 +3252,7 @@
++@@ -3266,7 +3266,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -856,7 -860,7 +869,7 @@@
VARIABLE_COMMENT Maximum number of instrumented MUTEX objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
- @@ -3252,7 +3252,7 @@
-@@ -3266,7 +3266,7 @@
++@@ -3280,7 +3280,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 40
VARIABLE_SCOPE GLOBAL
@@@ -865,7 -869,7 +878,7 @@@
VARIABLE_COMMENT Maximum number of rwlock instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3266,7 +3266,7 @@
-@@ -3280,7 +3280,7 @@
++@@ -3294,7 +3294,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -874,7 -878,7 +887,7 @@@
VARIABLE_COMMENT Maximum number of instrumented RWLOCK objects. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 104857600
- @@ -3280,7 +3280,7 @@
-@@ -3294,7 +3294,7 @@
++@@ -3308,7 +3308,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@@@ -883,7 -887,7 +896,7 @@@
VARIABLE_COMMENT Maximum number of socket instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3294,7 +3294,7 @@
-@@ -3308,7 +3308,7 @@
++@@ -3322,7 +3322,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -892,7 -896,7 +905,7 @@@
VARIABLE_COMMENT Maximum number of opened instrumented sockets. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3308,7 +3308,7 @@
-@@ -3322,7 +3322,7 @@
++@@ -3336,7 +3336,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 160
VARIABLE_SCOPE GLOBAL
@@@ -901,7 -905,7 +914,7 @@@
VARIABLE_COMMENT Maximum number of stage instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3322,7 +3322,7 @@
-@@ -3336,7 +3336,7 @@
++@@ -3350,7 +3350,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 202
VARIABLE_SCOPE GLOBAL
@@@ -910,7 -914,7 +923,7 @@@
VARIABLE_COMMENT Maximum number of statement instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3336,7 +3336,7 @@
-@@ -3350,7 +3350,7 @@
++@@ -3364,7 +3364,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -919,7 -923,7 +932,7 @@@
VARIABLE_COMMENT Maximum number of opened instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3350,7 +3350,7 @@
-@@ -3364,7 +3364,7 @@
++@@ -3378,7 +3378,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -928,7 -932,7 +941,7 @@@
VARIABLE_COMMENT Maximum number of instrumented tables. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3364,7 +3364,7 @@
-@@ -3378,7 +3378,7 @@
++@@ -3392,7 +3392,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@@@ -937,7 -941,7 +950,7 @@@
VARIABLE_COMMENT Maximum number of thread instruments.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 256
- @@ -3378,7 +3378,7 @@
-@@ -3392,7 +3392,7 @@
++@@ -3406,7 +3406,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -946,7 -950,7 +959,7 @@@
VARIABLE_COMMENT Maximum number of instrumented threads. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3392,7 +3392,7 @@
-@@ -3406,7 +3406,7 @@
++@@ -3420,7 +3420,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -955,7 -959,7 +968,7 @@@
VARIABLE_COMMENT Size of session attribute string buffer per thread. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3406,7 +3406,7 @@
-@@ -3420,7 +3420,7 @@
++@@ -3434,7 +3434,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@@@ -964,7 -968,7 +977,7 @@@
VARIABLE_COMMENT Maximum number of rows in SETUP_ACTORS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1024
- @@ -3420,7 +3420,7 @@
-@@ -3434,7 +3434,7 @@
++@@ -3448,7 +3448,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 100
VARIABLE_SCOPE GLOBAL
@@@ -973,7 -977,7 +986,7 @@@
VARIABLE_COMMENT Maximum number of rows in SETUP_OBJECTS.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1048576
- @@ -3434,7 +3434,7 @@
-@@ -3448,7 +3448,7 @@
++@@ -3462,7 +3462,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE -1
VARIABLE_SCOPE GLOBAL
@@@ -982,7 -986,7 +995,7 @@@
VARIABLE_COMMENT Maximum number of instrumented users. Use 0 to disable, -1 for automated sizing.
NUMERIC_MIN_VALUE -1
NUMERIC_MAX_VALUE 1048576
- @@ -3490,7 +3490,7 @@
-@@ -3504,7 +3504,7 @@
++@@ -3518,7 +3518,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32768
VARIABLE_SCOPE SESSION
@@@ -991,7 -995,7 +1004,7 @@@
VARIABLE_COMMENT The size of the buffer that is allocated when preloading indexes
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
- @@ -3518,7 +3518,7 @@
-@@ -3532,7 +3532,7 @@
++@@ -3546,7 +3546,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 15
VARIABLE_SCOPE SESSION
@@@ -1000,7 -1004,7 +1013,7 @@@
VARIABLE_COMMENT Number of statements about which profiling information is maintained. If set to 0, no profiles are stored. See SHOW PROFILES.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
- @@ -3532,7 +3532,7 @@
-@@ -3546,7 +3546,7 @@
++@@ -3560,7 +3560,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 5
VARIABLE_SCOPE SESSION
@@@ -1009,7 -1013,7 +1022,7 @@@
VARIABLE_COMMENT Seconds between sending progress reports to the client for time-consuming statements. Set to 0 to disable progress reporting.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3616,7 +3616,7 @@
-@@ -3630,7 +3630,7 @@
++@@ -3644,7 +3644,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 16384
VARIABLE_SCOPE SESSION
@@@ -1018,7 -1022,7 +1031,7 @@@
VARIABLE_COMMENT Allocation block size for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
- @@ -3630,7 +3630,7 @@
-@@ -3644,7 +3644,7 @@
++@@ -3658,7 +3658,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1048576
VARIABLE_SCOPE GLOBAL
@@@ -1027,7 -1031,7 +1040,7 @@@
VARIABLE_COMMENT Don't cache results that are bigger than this
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3644,7 +3644,7 @@
-@@ -3658,7 +3658,7 @@
++@@ -3672,7 +3672,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE GLOBAL
@@@ -1036,7 -1040,7 +1049,7 @@@
VARIABLE_COMMENT The minimum size for blocks allocated by the query cache
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -3661,7 +3661,7 @@
-@@ -3675,7 +3675,7 @@
++@@ -3689,7 +3689,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The memory allocated to store results from old queries
NUMERIC_MIN_VALUE 0
@@@ -1045,7 -1049,7 +1058,7 @@@
NUMERIC_BLOCK_SIZE 1024
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -3714,7 +3714,7 @@
-@@ -3728,7 +3728,7 @@
++@@ -3742,7 +3742,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 24576
VARIABLE_SCOPE SESSION
@@@ -1054,7 -1058,7 +1067,7 @@@
VARIABLE_COMMENT Persistent buffer for query parsing and execution
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 4294967295
- @@ -3728,7 +3728,7 @@
-@@ -3742,7 +3742,7 @@
++@@ -3756,7 +3756,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@@@ -1063,7 -1067,7 +1076,7 @@@
VARIABLE_COMMENT Allocation block size for storing ranges during optimization
NUMERIC_MIN_VALUE 4096
NUMERIC_MAX_VALUE 4294967295
- @@ -3745,7 +3745,7 @@
-@@ -3759,7 +3759,7 @@
++@@ -3773,7 +3773,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum speed(KB/s) to read binlog from master (0 = no limit)
NUMERIC_MIN_VALUE 0
@@@ -1072,7 -1076,7 +1085,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -3756,7 +3756,7 @@
-@@ -3770,7 +3770,7 @@
++@@ -3784,7 +3784,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 131072
VARIABLE_SCOPE SESSION
@@@ -1081,7 -1085,7 +1094,7 @@@
VARIABLE_COMMENT Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value
NUMERIC_MIN_VALUE 8192
NUMERIC_MAX_VALUE 2147483647
- @@ -3784,7 +3784,7 @@
-@@ -3798,7 +3798,7 @@
++@@ -3812,7 +3812,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 262144
VARIABLE_SCOPE SESSION
@@@ -1090,7 -1094,7 +1103,7 @@@
VARIABLE_COMMENT When reading rows in sorted order after a sort, the rows are read through this buffer to avoid a disk seeks
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 2147483647
- @@ -4064,10 +4064,10 @@
-@@ -4078,10 +4078,10 @@
++@@ -4092,10 +4092,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8388608
VARIABLE_SCOPE SESSION
@@@ -1103,7 -1107,7 +1116,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4092,10 +4092,10 @@
-@@ -4106,10 +4106,10 @@
++@@ -4120,10 +4120,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10000
VARIABLE_SCOPE GLOBAL
@@@ -1116,7 -1120,7 +1129,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4106,10 +4106,10 @@
-@@ -4120,10 +4120,10 @@
++@@ -4134,10 +4134,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32
VARIABLE_SCOPE GLOBAL
@@@ -1129,7 -1133,7 +1142,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4190,10 +4190,10 @@
-@@ -4204,10 +4204,10 @@
++@@ -4218,10 +4218,10 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 32
VARIABLE_SCOPE GLOBAL
@@@ -1142,7 -1146,7 +1155,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -4246,7 +4246,7 @@
-@@ -4260,7 +4260,7 @@
++@@ -4274,7 +4274,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 1
VARIABLE_SCOPE SESSION
@@@ -1151,7 -1155,7 +1164,7 @@@
VARIABLE_COMMENT Uniquely identifies the server instance in the community of replication partners
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
- @@ -4428,7 +4428,7 @@
-@@ -4442,7 +4442,7 @@
++@@ -4456,7 +4456,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@@@ -1160,7 -1164,7 +1173,7 @@@
VARIABLE_COMMENT Maximum number of parallel threads to use on slave for events in a single replication domain. When using multiple domains, this can be used to limit a single domain from grabbing all threads and thus stalling other domains. The default of 0 means to allow a domain to grab as many threads as it wants, up to the value of slave_parallel_threads.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
- @@ -4470,7 +4470,7 @@
-@@ -4484,7 +4484,7 @@
++@@ -4498,7 +4498,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1073741824
VARIABLE_SCOPE GLOBAL
@@@ -1169,7 -1173,7 +1182,7 @@@
VARIABLE_COMMENT The maximum packet length to sent successfully from the master to slave.
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 1073741824
- @@ -4498,7 +4498,7 @@
-@@ -4512,7 +4512,7 @@
++@@ -4526,7 +4526,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 131072
VARIABLE_SCOPE GLOBAL
@@@ -1178,7 -1182,7 +1191,7 @@@
VARIABLE_COMMENT Limit on how much memory SQL threads should use per parallel replication thread when reading ahead in the relay log looking for opportunities for parallel replication. Only used when --slave-parallel-threads > 0.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 2147483647
- @@ -4526,7 +4526,7 @@
-@@ -4540,7 +4540,7 @@
++@@ -4554,7 +4554,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@@@ -1187,7 -1191,7 +1200,7 @@@
VARIABLE_COMMENT If non-zero, number of threads to spawn to apply in parallel events on the slave that were group-committed on the master or were logged with GTID in different replication domains. Note that these threads are in addition to the IO and SQL threads, which are always created by a replication slave
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
- @@ -4540,7 +4540,7 @@
-@@ -4554,7 +4554,7 @@
++@@ -4568,7 +4568,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@@@ -1196,7 -1200,7 +1209,7 @@@
VARIABLE_COMMENT Alias for slave_parallel_threads
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16383
- @@ -4596,7 +4596,7 @@
-@@ -4610,7 +4610,7 @@
++@@ -4624,7 +4624,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@@@ -1205,7 -1209,7 +1218,7 @@@
VARIABLE_COMMENT Number of times the slave SQL thread will retry a transaction in case it failed with a deadlock, elapsed lock wait timeout or listed in slave_transaction_retry_errors, before giving up and stopping
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -4624,7 +4624,7 @@
-@@ -4638,7 +4638,7 @@
++@@ -4652,7 +4652,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@@@ -1214,7 -1218,7 +1227,7 @@@
VARIABLE_COMMENT Interval of the slave SQL thread will retry a transaction in case it failed with a deadlock or elapsed lock wait timeout or listed in slave_transaction_retry_errors
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 3600
- @@ -4652,7 +4652,7 @@
-@@ -4666,7 +4666,7 @@
++@@ -4680,7 +4680,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 2
VARIABLE_SCOPE GLOBAL
@@@ -1223,7 -1227,7 +1236,7 @@@
VARIABLE_COMMENT If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
- @@ -4711,7 +4711,7 @@
-@@ -4725,7 +4725,7 @@
++@@ -4739,7 +4739,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Each thread that needs to do a sort allocates a buffer of this size
NUMERIC_MIN_VALUE 1024
@@@ -1232,7 -1236,7 +1245,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5016,7 +5016,7 @@
-@@ -5030,7 +5030,7 @@
++@@ -5044,7 +5044,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@@@ -1241,7 -1245,7 +1254,7 @@@
VARIABLE_COMMENT The soft upper limit for number of cached stored routines for one connection.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 524288
- @@ -5142,7 +5142,7 @@
-@@ -5156,7 +5156,7 @@
++@@ -5170,7 +5170,7 @@
GLOBAL_VALUE_ORIGIN AUTO
DEFAULT_VALUE 400
VARIABLE_SCOPE GLOBAL
@@@ -1250,7 -1254,7 +1263,7 @@@
VARIABLE_COMMENT The number of cached table definitions
NUMERIC_MIN_VALUE 400
NUMERIC_MAX_VALUE 2097152
- @@ -5156,7 +5156,7 @@
-@@ -5170,7 +5170,7 @@
++@@ -5184,7 +5184,7 @@
GLOBAL_VALUE_ORIGIN CONFIG
DEFAULT_VALUE 2000
VARIABLE_SCOPE GLOBAL
@@@ -1259,7 -1263,7 +1272,7 @@@
VARIABLE_COMMENT The number of cached open tables
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 1048576
- @@ -5240,7 +5240,7 @@
-@@ -5254,7 +5254,7 @@
++@@ -5268,7 +5268,7 @@
GLOBAL_VALUE_ORIGIN AUTO
DEFAULT_VALUE 256
VARIABLE_SCOPE GLOBAL
@@@ -1268,7 -1272,7 +1281,7 @@@
VARIABLE_COMMENT How many threads we should keep in a cache for reuse. These are freed after 5 minutes of idle time
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16384
- @@ -5254,7 +5254,7 @@
-@@ -5268,7 +5268,7 @@
++@@ -5282,7 +5282,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 10
VARIABLE_SCOPE GLOBAL
@@@ -1277,7 -1281,7 +1290,7 @@@
VARIABLE_COMMENT Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.This variable has no effect, and is deprecated. It will be removed in a future release.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 512
- @@ -5459,15 +5459,15 @@
-@@ -5473,15 +5473,15 @@
++@@ -5487,15 +5487,15 @@
READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME TMP_DISK_TABLE_SIZE
@@@ -1297,7 -1301,7 +1310,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5481,7 +5481,7 @@
-@@ -5495,7 +5495,7 @@
++@@ -5509,7 +5509,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT If an internal in-memory temporary table exceeds this size, MariaDB will automatically convert it to an on-disk MyISAM or Aria table. Same as tmp_table_size.
NUMERIC_MIN_VALUE 1024
@@@ -1306,7 -1310,7 +1319,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5495,7 +5495,7 @@
-@@ -5509,7 +5509,7 @@
++@@ -5523,7 +5523,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Alias for tmp_memory_table_size. If an internal in-memory temporary table exceeds this size, MariaDB will automatically convert it to an on-disk MyISAM or Aria table.
NUMERIC_MIN_VALUE 1024
@@@ -1315,7 -1319,7 +1328,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5506,7 +5506,7 @@
-@@ -5520,7 +5520,7 @@
++@@ -5534,7 +5534,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 8192
VARIABLE_SCOPE SESSION
@@@ -1324,7 -1328,7 +1337,7 @@@
VARIABLE_COMMENT Allocation block size for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
- @@ -5520,7 +5520,7 @@
-@@ -5534,7 +5534,7 @@
++@@ -5548,7 +5548,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 4096
VARIABLE_SCOPE SESSION
@@@ -1333,7 -1337,7 +1346,7 @@@
VARIABLE_COMMENT Persistent buffer for transactions to be stored in binary log
NUMERIC_MIN_VALUE 1024
NUMERIC_MAX_VALUE 134217728
- @@ -5618,7 +5618,7 @@
-@@ -5632,7 +5632,7 @@
++@@ -5646,7 +5646,7 @@
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 28800
VARIABLE_SCOPE SESSION
@@@ -1342,7 -1346,7 +1355,7 @@@
VARIABLE_COMMENT The number of seconds the server waits for activity on a connection before closing it
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 31536000
- @@ -5723,7 +5723,7 @@
-@@ -5737,7 +5737,7 @@
++@@ -5751,7 +5751,7 @@
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME OPEN_FILES_LIMIT
VARIABLE_SCOPE GLOBAL
@@@ -1351,7 -1355,7 +1364,7 @@@
VARIABLE_COMMENT If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 or autoset then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of file descriptors
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
- @@ -5736,7 +5736,7 @@
-@@ -5750,7 +5750,7 @@
++@@ -5764,7 +5764,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@@@ -1360,7 -1364,7 +1373,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5746,7 +5746,7 @@
-@@ -5760,7 +5760,7 @@
++@@ -5774,7 +5774,7 @@
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Sets the internal state of the RAND() generator for replication purposes
NUMERIC_MIN_VALUE 0
@@@ -1369,7 -1373,7 +1382,7 @@@
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
- @@ -5841,7 +5841,7 @@
-@@ -5855,7 +5855,7 @@
++@@ -5869,7 +5869,7 @@
VARIABLE_NAME LOG_TC_SIZE
GLOBAL_VALUE_ORIGIN AUTO
VARIABLE_SCOPE GLOBAL
diff --cc mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 6c57061,631b75b..da7790f
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@@ -2977,9 -2963,37 +2977,37 @@@ VARIABLE_COMMENT Fine-tune the optimize
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
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
+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,rowid_filter,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
diff --cc sql/CMakeLists.txt
index 6cb78f4,0befcd2..ebc0579
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@@ -139,7 -139,7 +139,8 @@@ SET (SQL_SOURC
sql_sequence.cc sql_sequence.h ha_sequence.h
sql_tvc.cc sql_tvc.h
opt_split.cc
+ rowid_filter.cc rowid_filter.h
+ opt_trace.cc
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc backup.cc
diff --cc sql/opt_range.cc
index c9dc56d,c87a059..468d16c
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@@ -2641,12 -2804,22 +2805,22 @@@ int SQL_SELECT::test_quick_select(THD *
if (!force_quick_range && !head->covering_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->covering_keys);
- double key_read_time= head->file->keyread_time(key_for_use, 1, records) +
- (double) records / TIME_FOR_COMPARE;
+ double key_read_time= head->file->key_scan_time(key_for_use) +
+ (double) records / TIME_FOR_COMPARE_IDX;
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
"read time %g", key_for_use, key_read_time));
+
+ Json_writer_object trace_cov(thd, "best_covering_index_scan");
+ bool chosen= FALSE;
if (key_read_time < read_time)
+ {
read_time= key_read_time;
+ chosen= TRUE;
+ }
+ trace_cov.add("index", head->key_info[key_for_use].name)
+ .add("cost", key_read_time).add("chosen", chosen);
+ if (!chosen)
+ trace_cov.add("cause", "cost");
}
TABLE_READ_PLAN *best_trp= NULL;
@@@ -4791,8 -5015,8 +5016,9 @@@ TABLE_READ_PLAN *get_best_disjunct_quic
double roru_index_costs;
ha_rows roru_total_records;
double roru_intersect_part= 1.0;
+ double limit_read_time= read_time;
size_t n_child_scans;
+ THD *thd= param->thd;
DBUG_ENTER("get_best_disjunct_quick");
DBUG_PRINT("info", ("Full table scan cost: %g", read_time));
@@@ -5399,22 -5673,38 +5675,38 @@@ bool prepare_search_best_index_intersec
bzero(common->search_scans, sizeof(INDEX_SCAN_INFO *) * i);
INDEX_SCAN_INFO **selected_index_scans= common->search_scans;
-
+ Json_writer_array potential_idx_scans(thd, "potential_index_scans");
for (i=0, index_scan= tree->index_scans; i < n_index_scans; i++, index_scan++)
{
+ Json_writer_object idx_scan(thd);
uint used_key_parts= (*index_scan)->used_key_parts;
KEY *key_info= (*index_scan)->key_info;
+ idx_scan.add("index", key_info->name);
if (*index_scan == cpk_scan)
+ {
+ idx_scan.add("chosen", "false")
+ .add("cause", "clustered index used for filtering");
continue;
+ }
if (cpk_scan && cpk_scan->used_key_parts >= used_key_parts &&
same_index_prefix(cpk_scan->key_info, key_info, used_key_parts))
+ {
+ idx_scan.add("chosen", "false")
+ .add("cause", "clustered index used for filtering");
continue;
+ }
- cost= table->file->keyread_time((*index_scan)->keynr,
- (*index_scan)->range_count,
- (*index_scan)->records);
+ cost= table->quick_index_only_costs[(*index_scan)->keynr];
+
+ idx_scan.add("cost", cost);
++
if (cost >= cutoff_cost)
+ {
+ idx_scan.add("chosen", false);
+ idx_scan.add("cause", "cost");
continue;
+ }
for (scan_ptr= selected_index_scans; *scan_ptr ; scan_ptr++)
{
diff --cc sql/sql_select.cc
index cec5ff7,1f12490..3670eff
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@@ -64,7 -64,9 +64,10 @@@
#include "sys_vars_shared.h"
#include "sp_head.h"
#include "sp_rcontext.h"
+#include "rowid_filter.h"
+ #include "select_handler.h"
+ #include "my_json_writer.h"
+ #include "opt_trace.h"
/*
A key part number that means we're using a fulltext scan.
@@@ -5081,146 -5064,160 +5184,163 @@@ make_join_statistics(JOIN *join, List<T
/* Calc how many (possible) matched records in each table */
- for (s=stat ; s < stat_end ; s++)
+ /*
+ Todo: add a function so that we can add these Json_writer_objects
+ easily.
+ Another way would be to enclose them in a scope {};
+ */
{
- s->startup_cost= 0;
- if (s->type == JT_SYSTEM || s->type == JT_CONST)
- {
- /* Only one matching row */
- s->found_records= s->records= 1;
- s->read_time=1.0;
- s->worst_seeks=1.0;
- continue;
- }
- /* Approximate found rows and time to read them */
- if (s->table->is_filled_at_execution())
- {
- get_delayed_table_estimates(s->table, &s->records, &s->read_time,
- &s->startup_cost);
- s->found_records= s->records;
- table->quick_condition_rows=s->records;
- }
- else
- {
- s->scan_time();
- }
+ Json_writer_object rows_estimation_wrapper(thd);
+ Json_writer_array rows_estimation(thd, "rows_estimation");
+ for (s=stat ; s < stat_end ; s++)
+ {
+ s->startup_cost= 0;
+ if (s->type == JT_SYSTEM || s->type == JT_CONST)
+ {
+
+ Json_writer_object table_records(thd);
+ /* Only one matching row */
+ s->found_records= s->records= 1;
+ s->read_time=1.0;
+ s->worst_seeks=1.0;
+ table_records.add_table_name(s)
+ .add("rows", s->found_records)
+ .add("cost", s->read_time)
+ .add("table_type", s->type == JT_CONST ?
+ "const" :
+ "system");
+ continue;
+ }
+ /* Approximate found rows and time to read them */
+ if (s->table->is_filled_at_execution())
+ {
+ get_delayed_table_estimates(s->table, &s->records, &s->read_time,
+ &s->startup_cost);
+ s->found_records= s->records;
+ table->quick_condition_rows=s->records;
+ }
+ else
+ s->scan_time();
- if (s->table->is_splittable())
- s->add_keyuses_for_splitting();
+ if (s->table->is_splittable())
+ s->add_keyuses_for_splitting();
- /*
- Set a max range of how many seeks we can expect when using keys
- This is can't be to high as otherwise we are likely to use
- table scan.
- */
- s->worst_seeks= MY_MIN((double) s->found_records / 10,
- (double) s->read_time*3);
- if (s->worst_seeks < 2.0) // Fix for small tables
- s->worst_seeks=2.0;
+ /*
+ Set a max range of how many seeks we can expect when using keys
+ This is can't be to high as otherwise we are likely to use
+ table scan.
+ */
+ s->worst_seeks= MY_MIN((double) s->found_records / 10,
+ (double) s->read_time*3);
+ if (s->worst_seeks < 2.0) // Fix for small tables
+ s->worst_seeks=2.0;
- /*
- Add to stat->const_keys those indexes for which all group fields or
- all select distinct fields participate in one index.
- */
- add_group_and_distinct_keys(join, s);
+ /*
+ Add to stat->const_keys those indexes for which all group fields or
+ all select distinct fields participate in one index.
+ */
+ add_group_and_distinct_keys(join, s);
- s->table->cond_selectivity= 1.0;
-
- /*
- Perform range analysis if there are keys it could use (1).
- Don't do range analysis for materialized subqueries (2).
- Don't do range analysis for materialized derived tables (3)
- */
- if ((!s->const_keys.is_clear_all() ||
- !bitmap_is_clear_all(&s->table->cond_set)) && // (1)
- !s->table->is_filled_at_execution() && // (2)
- !(s->table->pos_in_table_list->derived && // (3)
- s->table->pos_in_table_list->is_materialized_derived())) // (3)
- {
- bool impossible_range= FALSE;
- ha_rows records= HA_POS_ERROR;
- SQL_SELECT *select= 0;
- Item **sargable_cond= NULL;
- if (!s->const_keys.is_clear_all())
- {
- sargable_cond= get_sargable_cond(join, s->table);
-
- select= make_select(s->table, found_const_table_map,
- found_const_table_map,
- *sargable_cond,
- (SORT_INFO*) 0,
- 1, &error);
- if (!select)
- goto error;
- records= get_quick_record_count(join->thd, select, s->table,
- &s->const_keys, join->row_limit);
+ s->table->cond_selectivity= 1.0;
- /*
- Range analyzer might have modified the condition. Put it the new
- condition to where we got it from.
- */
- *sargable_cond= select->cond;
-
- s->quick=select->quick;
- s->needed_reg=select->needed_reg;
- select->quick=0;
- impossible_range= records == 0 && s->table->reginfo.impossible_range;
- if (join->thd->lex->sql_command == SQLCOM_SELECT &&
- optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER))
- s->table->init_cost_info_for_usable_range_rowid_filters(join->thd);
- }
- if (!impossible_range)
- {
- if (!sargable_cond)
+ /*
+ Perform range analysis if there are keys it could use (1).
+ Don't do range analysis for materialized subqueries (2).
+ Don't do range analysis for materialized derived tables (3)
+ */
+ if ((!s->const_keys.is_clear_all() ||
+ !bitmap_is_clear_all(&s->table->cond_set)) && // (1)
+ !s->table->is_filled_at_execution() && // (2)
+ !(s->table->pos_in_table_list->derived && // (3)
+ s->table->pos_in_table_list->is_materialized_derived())) // (3)
+ {
+ bool impossible_range= FALSE;
+ ha_rows records= HA_POS_ERROR;
+ SQL_SELECT *select= 0;
+ Item **sargable_cond= NULL;
+ if (!s->const_keys.is_clear_all())
+ {
sargable_cond= get_sargable_cond(join, s->table);
- if (join->thd->variables.optimizer_use_condition_selectivity > 1)
- calculate_cond_selectivity_for_table(join->thd, s->table,
- sargable_cond);
- if (s->table->reginfo.impossible_range)
- {
- impossible_range= TRUE;
- records= 0;
+
+ select= make_select(s->table, found_const_table_map,
+ found_const_table_map,
+ *sargable_cond,
+ (SORT_INFO*) 0, 1, &error);
+ if (!select)
+ goto error;
+ records= get_quick_record_count(join->thd, select, s->table,
- &s->const_keys, join->row_limit);
++ &s->const_keys, join->row_limit);
+
+ /*
+ Range analyzer might have modified the condition. Put it the new
+ condition to where we got it from.
+ */
+ *sargable_cond= select->cond;
+
+ s->quick=select->quick;
+ s->needed_reg=select->needed_reg;
+ select->quick=0;
+ impossible_range= records == 0 && s->table->reginfo.impossible_range;
++ if (join->thd->lex->sql_command == SQLCOM_SELECT &&
++ optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER))
++ s->table->init_cost_info_for_usable_range_rowid_filters(join->thd);
}
- }
- if (impossible_range)
- {
- /*
- Impossible WHERE or ON expression
- In case of ON, we mark that the we match one empty NULL row.
- In case of WHERE, don't set found_const_table_map to get the
- caller to abort with a zero row result.
- */
- TABLE_LIST *emb= s->table->pos_in_table_list->embedding;
- if (emb && !emb->sj_on_expr)
+ if (!impossible_range)
{
- /* Mark all tables in a multi-table join nest as const */
- mark_join_nest_as_const(join, emb, &found_const_table_map,
- &const_count);
+ if (!sargable_cond)
+ sargable_cond= get_sargable_cond(join, s->table);
+ if (join->thd->variables.optimizer_use_condition_selectivity > 1)
+ calculate_cond_selectivity_for_table(join->thd, s->table,
+ sargable_cond);
+ if (s->table->reginfo.impossible_range)
+ {
+ impossible_range= TRUE;
+ records= 0;
+ }
}
- else
+ if (impossible_range)
{
- join->const_table_map|= s->table->map;
- set_position(join,const_count++,s,(KEYUSE*) 0);
- s->type= JT_CONST;
- s->table->const_table= 1;
- if (*s->on_expr_ref)
+ /*
+ Impossible WHERE or ON expression
+ In case of ON, we mark that the we match one empty NULL row.
+ In case of WHERE, don't set found_const_table_map to get the
+ caller to abort with a zero row result.
+ */
+ TABLE_LIST *emb= s->table->pos_in_table_list->embedding;
+ if (emb && !emb->sj_on_expr)
+ {
+ /* Mark all tables in a multi-table join nest as const */
+ mark_join_nest_as_const(join, emb, &found_const_table_map,
+ &const_count);
+ }
+ else
{
- /* Generate empty row */
- s->info= ET_IMPOSSIBLE_ON_CONDITION;
- found_const_table_map|= s->table->map;
- mark_as_null_row(s->table); // All fields are NULL
+ join->const_table_map|= s->table->map;
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ s->type= JT_CONST;
+ s->table->const_table= 1;
+ if (*s->on_expr_ref)
+ {
+ /* Generate empty row */
+ s->info= ET_IMPOSSIBLE_ON_CONDITION;
+ found_const_table_map|= s->table->map;
+ mark_as_null_row(s->table); // All fields are NULL
+ }
}
}
+ if (records != HA_POS_ERROR)
+ {
+ s->found_records=records;
+ s->read_time= s->quick ? s->quick->read_time : 0.0;
+ }
+ if (select)
+ delete select;
+ else
+ add_table_scan_values_to_trace(thd, s);
}
- if (records != HA_POS_ERROR)
- {
- s->found_records=records;
- s->read_time= s->quick ? s->quick->read_time : 0.0;
- }
- if (select)
- delete select;
+ else
+ add_table_scan_values_to_trace(thd, s);
}
-
}
if (pull_out_semijoin_tables(join))
@@@ -6980,8 -6976,7 +7100,8 @@@ best_access_path(JOIN *join
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
KEYUSE *hj_start_key= 0;
SplM_plan_info *spl_plan= 0;
+ Range_rowid_filter_cost_info *filter= 0;
- double filter_cmp_gain= 0;
+ const char* cause= NULL;
disable_jbuf= disable_jbuf || idx == join->const_tables;
@@@ -7374,20 -7419,7 +7545,21 @@@
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
} /* not ft_key */
+ if (records < DBL_MAX)
+ {
+ double rows= record_count * records;
+ double access_cost_factor= MY_MIN(tmp / rows, 1.0);
+ filter=
+ table->best_range_rowid_filter_for_partial_join(start_key->key, rows,
+ access_cost_factor);
+ if (filter)
+ {
+ filter->get_cmp_gain(rows);
+ tmp-= filter->get_adjusted_gain(rows) - filter->get_cmp_gain(rows);
+ DBUG_ASSERT(tmp >= 0);
+ }
+ }
+ trace_access_idx.add("rows", records).add("cost", tmp);
if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE)
{
@@@ -7397,8 -7430,13 +7570,14 @@@
best_key= start_key;
best_max_key_part= max_key_part;
best_ref_depends_map= found_ref;
+ best_filter= filter;
}
+ else
+ {
+ trace_access_idx.add("chosen", false)
+ .add("cause", cause ? cause : "cost");
+ }
+ cause= NULL;
} /* for each key */
records= best_records;
}
@@@ -7439,8 -7478,12 +7619,13 @@@
best_key= hj_start_key;
best_ref_depends_map= 0;
best_uses_jbuf= TRUE;
+ best_filter= 0;
- }
+ trace_access_hash.add("type", "hash");
+ trace_access_hash.add("index", "hj-key");
+ trace_access_hash.add("cost", rnd_records);
+ trace_access_hash.add("cost", best);
+ trace_access_hash.add("chosen", true);
+ }
/*
Don't test table scan if it can't be better.
@@@ -7492,9 -7536,12 +7678,13 @@@
Here we estimate its cost.
*/
+ filter= 0;
if (s->quick)
{
+ trace_access_scan.add("access_type", "range");
+ /*
+ should have some info about all the different QUICK_SELECT
+ */
/*
For each record we:
- read record range through 'quick'
@@@ -7572,13 -7604,8 +7763,15 @@@
as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
tmp give us total cost of using TABLE SCAN
*/
+
+ double best_filter_cmp_gain= 0;
+ if (best_filter)
+ {
+ best_filter_cmp_gain= best_filter->get_cmp_gain(record_count * records);
+ }
+ trace_access_scan.add("resulting_rows", rnd_records);
+ trace_access_scan.add("cost", tmp);
+
if (best == DBL_MAX ||
(tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records <
(best_key->is_for_hash_join() ? best_time :
@@@ -7592,13 -7618,6 +7785,9 @@@
best= tmp;
records= rnd_records;
best_key= 0;
+ best_filter= 0;
- if (s->quick && s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE &&
- filter)
- {
++ if (s->quick && s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
+ best_filter= filter;
- best_filter_cmp_gain= filter_cmp_gain;
- }
/* range/index_merge/ALL/index access method are "independent", so: */
best_ref_depends_map= 0;
best_uses_jbuf= MY_TEST(!disable_jbuf && !((s->table->map &
@@@ -8099,22 -8132,20 +8303,28 @@@ optimize_straight_join(JOIN *join, tabl
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
+ POSITION *position= join->positions + idx;
- /* Find the best access method from 's' to the current partial plan */
+ Json_writer_object trace_one_table(thd);
+ if (unlikely(thd->trace_started()))
+ {
+ trace_plan_prefix(join, idx, join_tables);
+ trace_one_table.add_table_name(s);
+ }
+ /* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, join_tables, idx, disable_jbuf, record_count,
- join->positions + idx, &loose_scan_pos);
+ position, &loose_scan_pos);
/* compute the cost of the new plan extended with 's' */
- record_count*= join->positions[idx].records_read;
- read_time+= join->positions[idx].read_time +
- record_count / (double) TIME_FOR_COMPARE;
+ record_count*= position->records_read;
+ double filter_cmp_gain= 0;
+ if (position->range_rowid_filter_info)
+ {
+ filter_cmp_gain=
+ position->range_rowid_filter_info->get_cmp_gain(record_count);
+ }
+ read_time+= position->read_time +
+ record_count / (double) TIME_FOR_COMPARE -
+ filter_cmp_gain;
advance_sj_state(join, join_tables, idx, &record_count, &read_time,
&loose_scan_pos);
@@@ -9022,16 -9072,12 +9251,19 @@@ best_extension_by_limited_search(JOI
current_record_count= record_count * position->records_read;
else
current_record_count= DBL_MAX;
+ double filter_cmp_gain= 0;
+ if (position->range_rowid_filter_info)
+ {
+ filter_cmp_gain=
+ position->range_rowid_filter_info->get_cmp_gain(current_record_count);
+ }
current_read_time=read_time + position->read_time +
- current_record_count / (double) TIME_FOR_COMPARE;
+ current_record_count / (double) TIME_FOR_COMPARE -
+ filter_cmp_gain;
+ /*
+ TODO add filtering estimates here
+ */
advance_sj_state(join, remaining_tables, idx, ¤t_record_count,
¤t_read_time, &loose_scan_pos);
diff --cc sql/table.h
index af38082,40dd752..914f4dc
--- a/sql/table.h
+++ b/sql/table.h
@@@ -55,7 -55,8 +55,9 @@@ class Virtual_column_info
class Table_triggers_list;
class TMP_TABLE_PARAM;
class SEQUENCE;
+class Range_rowid_filter_cost_info;
+ class derived_handler;
+ class Pushdown_derived;
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
1
0
14 Feb '19
revision-id: 88b311e62ff0f977943984fd1bf6e33421267550 (mariadb-10.4.1-163-g88b311e62ff)
parent(s): 3c305d3f1951f1667f84e48ddd98674c6318c39d
author: Vicențiu Ciorbaru
committer: Vicențiu Ciorbaru
timestamp: 2019-02-14 23:03:53 +0200
message:
Simplify column data adding method
The add method does not need to provide the row order number. It was
only used to detect if the minimum/maximum value was populated once or not, so
as to force an update for the first encounter of a value.
---
sql/sql_statistics.cc | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index db214a1fe28..f903ce143a4 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -324,7 +324,7 @@ class Column_statistics_collected :public Column_statistics
public:
inline void init(THD *thd, Field * table_field);
- inline bool add(ha_rows rowno);
+ inline bool add();
inline void finish(ha_rows rows);
inline void cleanup();
};
@@ -2483,7 +2483,7 @@ void Column_statistics_collected::init(THD *thd, Field *table_field)
*/
inline
-bool Column_statistics_collected::add(ha_rows rowno)
+bool Column_statistics_collected::add()
{
bool err= 0;
@@ -2492,9 +2492,11 @@ bool Column_statistics_collected::add(ha_rows rowno)
else
{
column_total_length+= column->value_length();
- if (min_value && column->update_min(min_value, rowno == nulls))
+ if (min_value && column->update_min(min_value,
+ is_null(COLUMN_STAT_MIN_VALUE)))
set_not_null(COLUMN_STAT_MIN_VALUE);
- if (max_value && column->update_max(max_value, rowno == nulls))
+ if (max_value && column->update_max(max_value,
+ is_null(COLUMN_STAT_MAX_VALUE)))
set_not_null(COLUMN_STAT_MAX_VALUE);
if (count_distinct)
err= count_distinct->add();
@@ -2761,7 +2763,7 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
table_field= *field_ptr;
if (!bitmap_is_set(table->read_set, table_field->field_index))
continue;
- if ((rc= table_field->collected_stats->add(rows)))
+ if ((rc= table_field->collected_stats->add()))
break;
}
if (rc)
1
0
[Commits] fd66f77c856: Introduce analyze_sample_percentage variable
by vicentiu@mariadb.org 14 Feb '19
by vicentiu@mariadb.org 14 Feb '19
14 Feb '19
revision-id: fd66f77c856c0e9ef25e1c677c4cc2ea0efec8c7 (mariadb-10.4.1-164-gfd66f77c856)
parent(s): 88b311e62ff0f977943984fd1bf6e33421267550
author: Vicențiu Ciorbaru
committer: Vicențiu Ciorbaru
timestamp: 2019-02-15 01:23:00 +0200
message:
Introduce analyze_sample_percentage variable
The variable controls the amount of sampling analyze table performs.
If ANALYZE table with histogram collection is too slow, one can reduce the
time taken by setting analyze_sample_percentage to a lower value of the
total number of rows.
Setting it to 0 will use a formula to compute how many rows to sample:
The number of rows collected is capped to a minimum of 50000 and
increases logarithmically with a coffecient of 4096. The coffecient is
chosen so that we expect an error of less than 3% in our estimations
according to the paper:
"Random Sampling for Histogram Construction: How much is enough?”
– Surajit Chaudhuri, Rajeev Motwani, Vivek Narasayya, ACM SIGMOD, 1998.
The drawback of sampling is that avg_frequency number is computed
imprecisely and will yeild a smaller number than the real one.
---
mysql-test/main/statistics.result | 104 +++++++++++++++++++++
mysql-test/main/statistics.test | 88 +++++++++++++++++
.../sys_vars/r/sysvars_server_embedded.result | 14 +++
.../sys_vars/r/sysvars_server_notembedded.result | 14 +++
sql/sql_class.h | 1 +
sql/sql_statistics.cc | 40 ++++++--
sql/sys_vars.cc | 9 ++
7 files changed, 260 insertions(+), 10 deletions(-)
diff --git a/mysql-test/main/statistics.result b/mysql-test/main/statistics.result
index 34a17cf049c..01176b8d6cf 100644
--- a/mysql-test/main/statistics.result
+++ b/mysql-test/main/statistics.result
@@ -1757,3 +1757,107 @@ DROP TABLE t1;
#
# End of 10.2 tests
#
+#
+# Start of 10.4 tests
+#
+#
+# Test analyze_sample_percentage system variable.
+#
+set @save_use_stat_tables=@@use_stat_tables;
+set @save_analyze_sample_percentage=@@analyze_sample_percentage;
+set session rand_seed1=42;
+set session rand_seed2=62;
+set use_stat_tables=PREFERABLY;
+set histogram_size=10;
+CREATE TABLE t1 (id int);
+INSERT INTO t1 (id) VALUES (1), (1), (1), (1), (1), (1), (1);
+INSERT INTO t1 (id) SELECT id FROM t1;
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+9192 FROM t1;
+#
+# This query will should show a full table scan analysis.
+#
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+table_name column_name min_value max_value nulls_ratio avg_length avg_frequency DECODE_HISTOGRAM(hist_type, histogram)
+t1 id 1 17384 0.0000 4.0000 14.0000 0.082,0.086,0.086,0.086,0.086,0.141,0.086,0.086,0.086,0.086,0.086
+set analyze_sample_percentage=0.1;
+#
+# This query will show an innacurate avg_frequency value.
+#
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status Table is already up to date
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+table_name column_name min_value max_value nulls_ratio avg_length avg_frequency DECODE_HISTOGRAM(hist_type, histogram)
+t1 id 111 17026 0.0000 4.0000 1.0047 0.039,0.098,0.055,0.118,0.078,0.157,0.082,0.118,0.094,0.063,0.098
+#
+# This query will show a better avg_frequency value.
+#
+set analyze_sample_percentage=25;
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status Table is already up to date
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+table_name column_name min_value max_value nulls_ratio avg_length avg_frequency DECODE_HISTOGRAM(hist_type, histogram)
+t1 id 1 17384 0.0000 4.0000 3.5736 0.082,0.086,0.086,0.082,0.086,0.145,0.086,0.086,0.082,0.086,0.090
+set analyze_sample_percentage=0;
+#
+# Test self adjusting sampling level.
+#
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status Table is already up to date
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+table_name column_name min_value max_value nulls_ratio avg_length avg_frequency DECODE_HISTOGRAM(hist_type, histogram)
+t1 id 1 17384 0.0000 4.0000 7.4523 0.082,0.090,0.086,0.082,0.086,0.145,0.086,0.082,0.086,0.086,0.086
+#
+# Test record estimation is working properly.
+#
+select count(*) from t1;
+count(*)
+229376
+explain select * from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 229060
+set analyze_sample_percentage=100;
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status Table is already up to date
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+table_name column_name min_value max_value nulls_ratio avg_length avg_frequency DECODE_HISTOGRAM(hist_type, histogram)
+t1 id 1 17384 0.0000 4.0000 14.0000 0.082,0.086,0.086,0.086,0.086,0.141,0.086,0.086,0.086,0.086,0.086
+explain select * from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 229376
+set use_stat_tables=@save_use_stat_tables;
+drop table t1;
diff --git a/mysql-test/main/statistics.test b/mysql-test/main/statistics.test
index b2e544064b0..2b799c9c4b9 100644
--- a/mysql-test/main/statistics.test
+++ b/mysql-test/main/statistics.test
@@ -898,3 +898,91 @@ DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #
+
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+--echo #
+--echo # Test analyze_sample_percentage system variable.
+--echo #
+set @save_use_stat_tables=@@use_stat_tables;
+set @save_analyze_sample_percentage=@@analyze_sample_percentage;
+
+set session rand_seed1=42;
+set session rand_seed2=62;
+
+set use_stat_tables=PREFERABLY;
+set histogram_size=10;
+
+CREATE TABLE t1 (id int);
+INSERT INTO t1 (id) VALUES (1), (1), (1), (1), (1), (1), (1);
+INSERT INTO t1 (id) SELECT id FROM t1;
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+9192 FROM t1;
+
+--echo #
+--echo # This query will should show a full table scan analysis.
+--echo #
+ANALYZE TABLE t1;
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+ DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+
+set analyze_sample_percentage=0.1;
+
+--echo #
+--echo # This query will show an innacurate avg_frequency value.
+--echo #
+ANALYZE TABLE t1;
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+ DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+
+--echo #
+--echo # This query will show a better avg_frequency value.
+--echo #
+set analyze_sample_percentage=25;
+ANALYZE TABLE t1;
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+ DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+
+
+set analyze_sample_percentage=0;
+--echo #
+--echo # Test self adjusting sampling level.
+--echo #
+ANALYZE TABLE t1;
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+ DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+-- echo #
+-- echo # Test record estimation is working properly.
+-- echo #
+select count(*) from t1;
+explain select * from t1;
+
+set analyze_sample_percentage=100;
+ANALYZE TABLE t1;
+select table_name, column_name, min_value, max_value, nulls_ratio, avg_length, avg_frequency,
+ DECODE_HISTOGRAM(hist_type, histogram)
+from mysql.column_stats;
+explain select * from t1;
+
+set use_stat_tables=@save_use_stat_tables;
+
+drop table t1;
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index 926ac8b2668..08b3f7ae938 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@ -40,6 +40,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST DEFAULT,COPY,INPLACE,NOCOPY,INSTANT
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME ANALYZE_SAMPLE_PERCENTAGE
+SESSION_VALUE 100.000000
+GLOBAL_VALUE 100.000000
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE 100.000000
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE DOUBLE
+VARIABLE_COMMENT Percentage of rows from the table ANALYZE TABLE will sample to collect table statistics. Set to 0 to let MariaDB decide what percentage of rows to sample.
+NUMERIC_MIN_VALUE 0
+NUMERIC_MAX_VALUE 100
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST NULL
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME AUTOCOMMIT
SESSION_VALUE ON
GLOBAL_VALUE ON
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 219b550d83e..2f70f26ab71 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -40,6 +40,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST DEFAULT,COPY,INPLACE,NOCOPY,INSTANT
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME ANALYZE_SAMPLE_PERCENTAGE
+SESSION_VALUE 100.000000
+GLOBAL_VALUE 100.000000
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE 100.000000
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE DOUBLE
+VARIABLE_COMMENT Percentage of rows from the table ANALYZE TABLE will sample to collect table statistics. Set to 0 to let MariaDB decide what percentage of rows to sample.
+NUMERIC_MIN_VALUE 0
+NUMERIC_MAX_VALUE 100
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST NULL
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME AUTOCOMMIT
SESSION_VALUE ON
GLOBAL_VALUE ON
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 402a114aadd..a16e078edc7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -619,6 +619,7 @@ typedef struct system_variables
ulong optimizer_selectivity_sampling_limit;
ulong optimizer_use_condition_selectivity;
ulong use_stat_tables;
+ double sample_percentage;
ulong histogram_size;
ulong histogram_type;
ulong preload_buff_size;
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index f903ce143a4..27fab974441 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -2729,12 +2729,28 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
Field *table_field;
ha_rows rows= 0;
handler *file=table->file;
+ double sample_fraction= thd->variables.sample_percentage / 100;
+ const ha_rows MIN_THRESHOLD_FOR_SAMPLING= 50000;
DBUG_ENTER("collect_statistics_for_table");
table->collected_stats->cardinality_is_null= TRUE;
table->collected_stats->cardinality= 0;
+ if (thd->variables.sample_percentage == 0)
+ {
+ if (file->records() < MIN_THRESHOLD_FOR_SAMPLING)
+ {
+ sample_fraction= 1;
+ }
+ else
+ {
+ sample_fraction= std::fmin(
+ (MIN_THRESHOLD_FOR_SAMPLING + 4096 *
+ log(200 * file->records())) / file->records(), 1);
+ }
+ }
+
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
table_field= *field_ptr;
@@ -2747,7 +2763,7 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
/* Perform a full table scan to collect statistics on 'table's columns */
if (!(rc= file->ha_rnd_init(TRUE)))
- {
+ {
DEBUG_SYNC(table->in_use, "statistics_collection_start");
while ((rc= file->ha_rnd_next(table->record[0])) != HA_ERR_END_OF_FILE)
@@ -2758,17 +2774,20 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
if (rc)
break;
- for (field_ptr= table->field; *field_ptr; field_ptr++)
+ if (thd_rnd(thd) <= sample_fraction)
{
- table_field= *field_ptr;
- if (!bitmap_is_set(table->read_set, table_field->field_index))
- continue;
- if ((rc= table_field->collected_stats->add()))
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
+ {
+ table_field= *field_ptr;
+ if (!bitmap_is_set(table->read_set, table_field->field_index))
+ continue;
+ if ((rc= table_field->collected_stats->add()))
+ break;
+ }
+ if (rc)
break;
+ rows++;
}
- if (rc)
- break;
- rows++;
}
file->ha_rnd_end();
}
@@ -2782,7 +2801,8 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
if (!rc)
{
table->collected_stats->cardinality_is_null= FALSE;
- table->collected_stats->cardinality= rows;
+ table->collected_stats->cardinality=
+ static_cast<ha_rows>(rows / sample_fraction);
}
bitmap_clear_all(table->write_set);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 7241685fb61..99009146cb8 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -349,6 +349,15 @@ static Sys_var_long Sys_pfs_connect_attrs_size(
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+static Sys_var_double Sys_analyze_sample_percentage(
+ "analyze_sample_percentage",
+ "Percentage of rows from the table ANALYZE TABLE will sample "
+ "to collect table statistics. Set to 0 to let MariaDB decide "
+ "what percentage of rows to sample.",
+ SESSION_VAR(sample_percentage),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 100),
+ DEFAULT(100));
+
static Sys_var_ulong Sys_auto_increment_increment(
"auto_increment_increment",
"Auto-increment columns are incremented by this",
1
0
revision-id: ccce4d3be9bb5dfce66576f9744bcb927b754cf4 (mariadb-10.3.6-116-gccce4d3)
parent(s): e1de23b8d51c53b87a9d54352af0e99d4386e0ee
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-02-14 15:23:23 -0800
message:
MDEV-16188 Post review fixes
Also adjusted some test files.
---
mysql-test/include/icp_tests.inc | 1 +
mysql-test/include/index_merge1.inc | 5 +++--
mysql-test/main/index_merge_myisam.result | 15 +++++----------
mysql-test/main/innodb_ext_key.result | 8 ++++----
mysql-test/main/innodb_ext_key.test | 2 ++
mysql-test/main/subselect_sj2.result | 8 ++++----
mysql-test/main/subselect_sj2.test | 2 ++
mysql-test/main/subselect_sj2_jcl6.result | 8 ++++----
mysql-test/main/subselect_sj2_mat.result | 8 ++++----
sql/rowid_filter.cc | 14 +++++++++-----
sql/rowid_filter.h | 2 +-
11 files changed, 39 insertions(+), 34 deletions(-)
diff --git a/mysql-test/include/icp_tests.inc b/mysql-test/include/icp_tests.inc
index f82a5a2..1ff34a9 100644
--- a/mysql-test/include/icp_tests.inc
+++ b/mysql-test/include/icp_tests.inc
@@ -226,6 +226,7 @@ EXPLAIN
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' and i1 > 2;
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' and i1 > 2;
+--replace_column 9 100
EXPLAIN
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' or i1 > 2;
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' or i1 > 2;
diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc
index f2ef38f..a5362b5 100644
--- a/mysql-test/include/index_merge1.inc
+++ b/mysql-test/include/index_merge1.inc
@@ -479,6 +479,7 @@ create table t2(
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
insert into t2 select * from t1;
+
--echo must use sort-union rather than union:
--replace_column 9 #
explain select * from t1 where a=4 or b=4;
@@ -489,9 +490,9 @@ select * from t1 ignore index(a,b) where a=4 or b=4;
--echo must use union, not sort-union:
--replace_column 9 #
-explain select * from t2 where a=4 or b=4;
+explain select * from t2 where a=2 or b=2;
--sorted_result
-select * from t2 where a=4 or b=4;
+select * from t2 where a=2 or b=2;
drop table t1, t2;
diff --git a/mysql-test/main/index_merge_myisam.result b/mysql-test/main/index_merge_myisam.result
index 77d6ae2..e1f7c72 100644
--- a/mysql-test/main/index_merge_myisam.result
+++ b/mysql-test/main/index_merge_myisam.result
@@ -522,18 +522,13 @@ a filler b
4 zz 4
5 qq 4
must use union, not sort-union:
-explain select * from t2 where a=4 or b=4;
+explain select * from t2 where a=2 or b=2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ALL a,b NULL NULL NULL # Using where
-select * from t2 where a=4 or b=4;
+1 SIMPLE t2 index_merge a,b a,b 5,5 NULL # Using union(a,b); Using where
+select * from t2 where a=2 or b=2;
a filler b
-4 4 0
-4 5 0
-4 filler 4
-4 filler 4
-4 qq 5
-4 zz 4
-5 qq 4
+2 filler 2
+2 filler 2
drop table t1, t2;
CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'),
KEY b(b), KEY a(a));
diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result
index daf1f53..b457217 100644
--- a/mysql-test/main/innodb_ext_key.result
+++ b/mysql-test/main/innodb_ext_key.result
@@ -824,8 +824,8 @@ set optimizer_switch='extended_keys=off';
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 10
-1 SIMPLE t2 eq_ref a a 4 test.t1.a 1 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL #
+1 SIMPLE t2 eq_ref a a 4 test.t1.a # Using where
flush status;
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
a pk a b
@@ -846,8 +846,8 @@ set optimizer_switch='extended_keys=on';
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 10
-1 SIMPLE t2 eq_ref a a 4 test.t1.a 1 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL #
+1 SIMPLE t2 eq_ref a a 4 test.t1.a # Using where
flush status;
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
a pk a b
diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test
index 333214e..d2f4266 100644
--- a/mysql-test/main/innodb_ext_key.test
+++ b/mysql-test/main/innodb_ext_key.test
@@ -497,6 +497,7 @@ select
from t1 A, t1 B;
set optimizer_switch='extended_keys=off';
+--replace_column 9 #
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
flush status;
@@ -504,6 +505,7 @@ select * from t1, t2 where t2.a=t1.a and t2.b < 2;
show status like 'handler_read%';
set optimizer_switch='extended_keys=on';
+--replace_column 9 #
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
flush status;
diff --git a/mysql-test/main/subselect_sj2.result b/mysql-test/main/subselect_sj2.result
index 649647d..a127c18 100644
--- a/mysql-test/main/subselect_sj2.result
+++ b/mysql-test/main/subselect_sj2.result
@@ -815,10 +815,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/mysql-test/main/subselect_sj2.test b/mysql-test/main/subselect_sj2.test
index e7dd6e7..2b4f619 100644
--- a/mysql-test/main/subselect_sj2.test
+++ b/mysql-test/main/subselect_sj2.test
@@ -995,6 +995,8 @@ CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
--echo # The following must use LooseScan but not join buffering
+
+--replace_column 9 #
explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
diff --git a/mysql-test/main/subselect_sj2_jcl6.result b/mysql-test/main/subselect_sj2_jcl6.result
index 62866bd..56c11e8 100644
--- a/mysql-test/main/subselect_sj2_jcl6.result
+++ b/mysql-test/main/subselect_sj2_jcl6.result
@@ -831,10 +831,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/mysql-test/main/subselect_sj2_mat.result b/mysql-test/main/subselect_sj2_mat.result
index 91ab00d..e4583cf 100644
--- a/mysql-test/main/subselect_sj2_mat.result
+++ b/mysql-test/main/subselect_sj2_mat.result
@@ -817,10 +817,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/sql/rowid_filter.cc b/sql/rowid_filter.cc
index 4a4869b..d6ea22c 100644
--- a/sql/rowid_filter.cc
+++ b/sql/rowid_filter.cc
@@ -189,8 +189,6 @@ int compare_range_rowid_filter_cost_info_by_a(
void TABLE::prune_range_rowid_filters()
{
- uint i, j;
-
/*
For the elements of the array with cost info on range filters
build a bit matrix of absolutely independent elements.
@@ -201,11 +199,15 @@ void TABLE::prune_range_rowid_filters()
*/
Range_rowid_filter_cost_info **filter_ptr_1= range_rowid_filter_cost_info_ptr;
- for (i= 0; i < range_rowid_filter_cost_info_elems; i++, filter_ptr_1++)
+ for (uint i= 0;
+ i < range_rowid_filter_cost_info_elems;
+ i++, filter_ptr_1++)
{
uint key_no= (*filter_ptr_1)->key_no;
Range_rowid_filter_cost_info **filter_ptr_2= filter_ptr_1 + 1;
- for (j= i+1; j < range_rowid_filter_cost_info_elems; j++, filter_ptr_2++)
+ for (uint j= i+1;
+ j < range_rowid_filter_cost_info_elems;
+ j++, filter_ptr_2++)
{
key_map map_1= key_info[key_no].overlapped;
map_1.merge(key_info[key_no].constraint_correlated);
@@ -236,7 +238,9 @@ void TABLE::prune_range_rowid_filters()
Range_rowid_filter_cost_info **cand_filter_ptr=
range_rowid_filter_cost_info_ptr;
- for (i= 0; i < range_rowid_filter_cost_info_elems; i++, cand_filter_ptr++)
+ for (uint i= 0;
+ i < range_rowid_filter_cost_info_elems;
+ i++, cand_filter_ptr++)
{
bool is_pruned= false;
Range_rowid_filter_cost_info **usable_filter_ptr=
diff --git a/sql/rowid_filter.h b/sql/rowid_filter.h
index 3f8faea..a9930dc 100644
--- a/sql/rowid_filter.h
+++ b/sql/rowid_filter.h
@@ -153,7 +153,7 @@ class Range_rowid_filter_cost_info;
typedef enum
{
SORTED_ARRAY_CONTAINER,
- BLOOM_FILTER_CONTAINER
+ BLOOM_FILTER_CONTAINER // Not used yet
} Rowid_filter_container_type;
/**
1
0
revision-id: 997b4fa7bf056a6ee93885484b0818b5fffa5e36 (mariadb-10.3.6-116-g997b4fa)
parent(s): e1de23b8d51c53b87a9d54352af0e99d4386e0ee
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-02-14 15:21:58 -0800
message:
MDEV-16188 Post review fixes
Also adjusted some test files.
---
mysql-test/include/icp_tests.inc | 1 +
mysql-test/include/index_merge1.inc | 5 +++--
mysql-test/main/index_merge_myisam.result | 15 +++++----------
mysql-test/main/innodb_ext_key.result | 8 ++++----
mysql-test/main/innodb_ext_key.test | 2 ++
mysql-test/main/subselect_sj2.result | 8 ++++----
mysql-test/main/subselect_sj2.test | 2 ++
mysql-test/main/subselect_sj2_jcl6.result | 8 ++++----
mysql-test/main/subselect_sj2_mat.result | 8 ++++----
sql/rowid_filter.cc | 14 +++++++++-----
10 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/mysql-test/include/icp_tests.inc b/mysql-test/include/icp_tests.inc
index f82a5a2..1ff34a9 100644
--- a/mysql-test/include/icp_tests.inc
+++ b/mysql-test/include/icp_tests.inc
@@ -226,6 +226,7 @@ EXPLAIN
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' and i1 > 2;
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' and i1 > 2;
+--replace_column 9 100
EXPLAIN
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' or i1 > 2;
SELECT c1 FROM t3 WHERE c1 >= 'c-1004=w' and c1 <= 'c-1006=w' or i1 > 2;
diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc
index f2ef38f..a5362b5 100644
--- a/mysql-test/include/index_merge1.inc
+++ b/mysql-test/include/index_merge1.inc
@@ -479,6 +479,7 @@ create table t2(
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
insert into t2 select * from t1;
+
--echo must use sort-union rather than union:
--replace_column 9 #
explain select * from t1 where a=4 or b=4;
@@ -489,9 +490,9 @@ select * from t1 ignore index(a,b) where a=4 or b=4;
--echo must use union, not sort-union:
--replace_column 9 #
-explain select * from t2 where a=4 or b=4;
+explain select * from t2 where a=2 or b=2;
--sorted_result
-select * from t2 where a=4 or b=4;
+select * from t2 where a=2 or b=2;
drop table t1, t2;
diff --git a/mysql-test/main/index_merge_myisam.result b/mysql-test/main/index_merge_myisam.result
index 77d6ae2..e1f7c72 100644
--- a/mysql-test/main/index_merge_myisam.result
+++ b/mysql-test/main/index_merge_myisam.result
@@ -522,18 +522,13 @@ a filler b
4 zz 4
5 qq 4
must use union, not sort-union:
-explain select * from t2 where a=4 or b=4;
+explain select * from t2 where a=2 or b=2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ALL a,b NULL NULL NULL # Using where
-select * from t2 where a=4 or b=4;
+1 SIMPLE t2 index_merge a,b a,b 5,5 NULL # Using union(a,b); Using where
+select * from t2 where a=2 or b=2;
a filler b
-4 4 0
-4 5 0
-4 filler 4
-4 filler 4
-4 qq 5
-4 zz 4
-5 qq 4
+2 filler 2
+2 filler 2
drop table t1, t2;
CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'),
KEY b(b), KEY a(a));
diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result
index daf1f53..b457217 100644
--- a/mysql-test/main/innodb_ext_key.result
+++ b/mysql-test/main/innodb_ext_key.result
@@ -824,8 +824,8 @@ set optimizer_switch='extended_keys=off';
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 10
-1 SIMPLE t2 eq_ref a a 4 test.t1.a 1 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL #
+1 SIMPLE t2 eq_ref a a 4 test.t1.a # Using where
flush status;
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
a pk a b
@@ -846,8 +846,8 @@ set optimizer_switch='extended_keys=on';
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL NULL NULL NULL NULL 10
-1 SIMPLE t2 eq_ref a a 4 test.t1.a 1 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL #
+1 SIMPLE t2 eq_ref a a 4 test.t1.a # Using where
flush status;
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
a pk a b
diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test
index 333214e..d2f4266 100644
--- a/mysql-test/main/innodb_ext_key.test
+++ b/mysql-test/main/innodb_ext_key.test
@@ -497,6 +497,7 @@ select
from t1 A, t1 B;
set optimizer_switch='extended_keys=off';
+--replace_column 9 #
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
flush status;
@@ -504,6 +505,7 @@ select * from t1, t2 where t2.a=t1.a and t2.b < 2;
show status like 'handler_read%';
set optimizer_switch='extended_keys=on';
+--replace_column 9 #
explain
select * from t1, t2 where t2.a=t1.a and t2.b < 2;
flush status;
diff --git a/mysql-test/main/subselect_sj2.result b/mysql-test/main/subselect_sj2.result
index 649647d..a127c18 100644
--- a/mysql-test/main/subselect_sj2.result
+++ b/mysql-test/main/subselect_sj2.result
@@ -815,10 +815,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/mysql-test/main/subselect_sj2.test b/mysql-test/main/subselect_sj2.test
index e7dd6e7..2b4f619 100644
--- a/mysql-test/main/subselect_sj2.test
+++ b/mysql-test/main/subselect_sj2.test
@@ -995,6 +995,8 @@ CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
--echo # The following must use LooseScan but not join buffering
+
+--replace_column 9 #
explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
diff --git a/mysql-test/main/subselect_sj2_jcl6.result b/mysql-test/main/subselect_sj2_jcl6.result
index 62866bd..56c11e8 100644
--- a/mysql-test/main/subselect_sj2_jcl6.result
+++ b/mysql-test/main/subselect_sj2_jcl6.result
@@ -831,10 +831,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/mysql-test/main/subselect_sj2_mat.result b/mysql-test/main/subselect_sj2_mat.result
index 91ab00d..e4583cf 100644
--- a/mysql-test/main/subselect_sj2_mat.result
+++ b/mysql-test/main/subselect_sj2_mat.result
@@ -817,10 +817,10 @@ explain
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias1 const PRIMARY PRIMARY 4 const 1 Using index
-1 PRIMARY alias2 index f12 f12 7 NULL 1 Using index; LooseScan
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index; FirstMatch(alias2)
-1 PRIMARY t3 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY alias1 const PRIMARY PRIMARY 4 const # Using index
+1 PRIMARY alias2 index f12 f12 7 NULL # Using index; LooseScan
+1 PRIMARY t1 index NULL PRIMARY 4 NULL # Using index; FirstMatch(alias2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL # Using where; Using join buffer (flat, BNL join)
SELECT * FROM t3
WHERE f12 IN (SELECT alias2.f12 FROM t1 AS alias1, t2 AS alias2, t1 WHERE alias1.f13 = 24);
f12
diff --git a/sql/rowid_filter.cc b/sql/rowid_filter.cc
index 4a4869b..d6ea22c 100644
--- a/sql/rowid_filter.cc
+++ b/sql/rowid_filter.cc
@@ -189,8 +189,6 @@ int compare_range_rowid_filter_cost_info_by_a(
void TABLE::prune_range_rowid_filters()
{
- uint i, j;
-
/*
For the elements of the array with cost info on range filters
build a bit matrix of absolutely independent elements.
@@ -201,11 +199,15 @@ void TABLE::prune_range_rowid_filters()
*/
Range_rowid_filter_cost_info **filter_ptr_1= range_rowid_filter_cost_info_ptr;
- for (i= 0; i < range_rowid_filter_cost_info_elems; i++, filter_ptr_1++)
+ for (uint i= 0;
+ i < range_rowid_filter_cost_info_elems;
+ i++, filter_ptr_1++)
{
uint key_no= (*filter_ptr_1)->key_no;
Range_rowid_filter_cost_info **filter_ptr_2= filter_ptr_1 + 1;
- for (j= i+1; j < range_rowid_filter_cost_info_elems; j++, filter_ptr_2++)
+ for (uint j= i+1;
+ j < range_rowid_filter_cost_info_elems;
+ j++, filter_ptr_2++)
{
key_map map_1= key_info[key_no].overlapped;
map_1.merge(key_info[key_no].constraint_correlated);
@@ -236,7 +238,9 @@ void TABLE::prune_range_rowid_filters()
Range_rowid_filter_cost_info **cand_filter_ptr=
range_rowid_filter_cost_info_ptr;
- for (i= 0; i < range_rowid_filter_cost_info_elems; i++, cand_filter_ptr++)
+ for (uint i= 0;
+ i < range_rowid_filter_cost_info_elems;
+ i++, cand_filter_ptr++)
{
bool is_pruned= false;
Range_rowid_filter_cost_info **usable_filter_ptr=
1
0