From f824984c70bdfe0d9eda13655c17521430219aaf Mon Sep 17 00:00:00 2001 From: Rex Johnston Date: Sun, 26 Apr 2026 07:29:44 +1200 Subject: [PATCH] MDEV-39499 Updates to derived-with-keys, window functions determining ..records per key Enabling derived keys optimization for derived.col = const pushed conditions. Estimating records per key in derived key for the optimizer based on form and/or size of components of a derived table. Consider any derived table of the form SELECT ..., ROW_NUMBER () OVER (PARTITION BY c1,c2 order by ...) FROM t1, t2, t3 ... WHERE ... If the optimizer generates a key on this derived table because of a constraint being pushed into it, it currently will not consider key components of the form col = const We lift this constraint and add code to TABLE::add_tmp_key to search for a window function ROW_NUMBER(). From the partition list c1, c2 we can in infer an estimate of the number of rows we expect to see for each key value. In the absence of EITS, we still have an number of expected records in our referred to table and will fall back to using that as a worst case scenario. As a consequence of forcing best_access_path to now consider a generated index's records per key on any type of derived table, we see a number of optimization changes, for example a range optimizer might now be considered best and might return IMPOSSIBLE_RANGE (seen in rowid_filter_myisam.result). --- libmysqld/CMakeLists.txt | 1 + mysql-test/main/cte_recursive.result | 10 +- mysql-test/main/derived.result | 6 +- mysql-test/main/derived_cond_pushdown.result | 178 ++++++--- .../main/derived_cond_pushdown_innodb.result | 4 +- mysql-test/main/derived_opt.result | 343 +++++++++++++++++ mysql-test/main/derived_opt.test | 168 +++++++++ mysql-test/main/join_nested_jcl6.result | 40 +- mysql-test/main/mrr_derived_crash_4610.result | 2 +- mysql-test/main/rowid_filter_myisam.result | 2 +- mysql-test/main/subselect3_jcl6.result | 10 +- mysql-test/main/subselect4.result | 14 +- mysql-test/main/subselect_mat.result | 2 +- mysql-test/suite/heap/heap.result | 2 +- .../r/v_privileges_by_table_by_level.result | 348 +++++++++--------- .../t/v_privileges_by_table_by_level.test | 6 + sql/CMakeLists.txt | 1 + sql/field.h | 1 + sql/opt_window_function_cardinality.cc | 150 ++++++++ sql/opt_window_function_cardinality.h | 26 ++ sql/sql_select.cc | 58 ++- sql/table.cc | 34 +- 22 files changed, 1104 insertions(+), 302 deletions(-) create mode 100644 sql/opt_window_function_cardinality.cc create mode 100644 sql/opt_window_function_cardinality.h diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index a636cfc23f156..4f8bfa632314a 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -71,6 +71,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/mf_iocache.cc ../sql/my_decimal.cc ../sql/net_serv.cc ../sql/opt_range.cc ../sql/opt_group_by_cardinality.cc + ../sql/opt_window_function_cardinality.cc ../sql/opt_rewrite_date_cmp.cc ../sql/opt_rewrite_remove_casefold.cc ../sql/opt_sum.cc diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index 37d4b51b1e003..c7ae724c5a46f 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -1721,16 +1721,16 @@ i div 4 - (i % 4) = ps.i div 4 - (ps.i % 4) ) SELECT regexp_replace(board,concat('(',REPEAT('.', 4),')'),'\\1\n') n_queens FROM solutions WHERE n_queens = 4; n_queens ---*- -*--- ----* --*-- - -*-- ---* *--- --*- +--*- +*--- +---* +-*-- + # # MDEV-10883: execution of prepared statement from SELECT # with recursive CTE that renames columns diff --git a/mysql-test/main/derived.result b/mysql-test/main/derived.result index 04f227091f58d..b96ac4c249b24 100644 --- a/mysql-test/main/derived.result +++ b/mysql-test/main/derived.result @@ -563,7 +563,7 @@ EXPLAIN SELECT * FROM (SELECT * FROM t1) AS table1, (SELECT DISTINCT * FROM t2) AS table2 WHERE b = a AND a <> ANY (SELECT 9); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -1 PRIMARY ref key0 key0 5 const 0 +1 PRIMARY ref key0 key0 5 const 1 3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary Warnings: Note 1249 Select 4 was reduced during optimization @@ -1547,7 +1547,7 @@ where T.a=5 from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 -2 MATERIALIZED ALL NULL NULL NULL NULL 10000 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 const 10 3 DERIVED duplicates_tbl ALL NULL NULL NULL NULL 10000 select t1.a IN ( SELECT COUNT(*) @@ -1581,7 +1581,7 @@ where T.a=5 from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 -2 DEPENDENT SUBQUERY ALL NULL NULL NULL NULL 10000 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 const 10 3 DERIVED duplicates_tbl ALL NULL NULL NULL NULL 10000 select t1.a = all ( SELECT COUNT(*) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index d095d74c42bd5..b1dc99bfd8dd9 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -8850,7 +8850,7 @@ SELECT * FROM ( SELECT * FROM ( SELECT MIN(i) as f FROM t1 ) sq1 ) AS sq2 WHERE f = 8; id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY ref key0 key0 5 const 0 100.00 3 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Warnings: Note 1003 /* select#1 */ select `sq1`.`f` AS `f` from (/* select#3 */ select min(`test`.`t1`.`i`) AS `f` from `test`.`t1` having `f` = 8) `sq1` where `sq1`.`f` = 8 @@ -9004,20 +9004,22 @@ EXPLAIN "query_block": { "select_id": 3, "cost": "COST_REPLACED", + "outer_ref_condition": "2 is not null", "nested_loop": [ { "table": { "table_name": "", - "access_type": "index_subquery", + "access_type": "ref", "possible_keys": ["key0"], "key": "key0", "key_length": "5", "used_key_parts": ["c"], - "ref": ["func"], + "ref": ["const"], "loops": 1, - "rows": 1, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, + "attached_condition": "(t2.b) = v3.c", "materialized": { "query_block": { "select_id": 5, @@ -9196,16 +9198,21 @@ EXPLAIN "query_block": { "select_id": 3, "cost": "COST_REPLACED", + "outer_ref_condition": "1 is not null", "nested_loop": [ { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["b"], + "ref": ["const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, - "attached_condition": "v2.b = 1", "materialized": { "query_block": { "select_id": 4, @@ -9551,16 +9558,21 @@ EXPLAIN "query_block": { "select_id": 2, "cost": "COST_REPLACED", + "outer_ref_condition": "50 is not null", "nested_loop": [ { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, - "attached_condition": "v1.a = 50", "materialized": { "query_block": { "select_id": 3, @@ -9705,12 +9717,17 @@ EXPLAIN "sort_key": "v1.a", "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "4", + "used_key_parts": ["b"], + "ref": ["const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, - "attached_condition": "v1.b = 2", + "attached_condition": "v1.b <=> 2 and v1.b = 2", "materialized": { "query_block": { "select_id": 3, @@ -9780,9 +9797,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["f"], + "ref": ["const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "v1.f = 2", @@ -9812,7 +9834,7 @@ EXPLAIN "table": { "table_name": "", "access_type": "ALL", - "loops": 2, + "loops": 1, "rows": 2, "cost": "COST_REPLACED", "filtered": 100, @@ -9893,9 +9915,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = 3", @@ -9968,9 +9995,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "5", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = 2.71", @@ -10038,9 +10070,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "6", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = 3.21", @@ -10108,9 +10145,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "35", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = 'aa'", @@ -10250,9 +10292,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "4", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = '2007-05-28'", @@ -10320,9 +10367,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "4", + "used_key_parts": ["i"], + "ref": ["const"], "loops": 1, - "rows": 3, + "rows": 1, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "sq.i = '10:00:02'", @@ -10474,9 +10526,14 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "6", + "used_key_parts": ["c"], + "ref": ["const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, "attached_condition": "v1.c = 'foo'", @@ -11057,34 +11114,17 @@ EXPLAIN "nested_loop": [ { "table": { - "table_name": "t1", + "table_name": "", "access_type": "ref", - "possible_keys": ["i1"], - "key": "i1", + "possible_keys": ["key0"], + "key": "key0", "key_length": "5", - "used_key_parts": ["i1"], + "used_key_parts": ["i2"], "ref": ["const"], "loops": 1, - "rows": 1, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, - "using_index": true - } - }, - { - "block-nl-join": { - "table": { - "table_name": "", - "access_type": "ALL", - "loops": 1, - "rows": 2, - "cost": "COST_REPLACED", - "filtered": 100, - "attached_condition": "v2.i2 = 1" - }, - "buffer_type": "flat", - "buffer_size": "65", - "join_type": "BNL", "materialized": { "query_block": { "select_id": 3, @@ -11105,6 +11145,22 @@ EXPLAIN } } } + }, + { + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["i1"], + "key": "i1", + "key_length": "5", + "used_key_parts": ["i1"], + "ref": ["const"], + "loops": 1, + "rows": 1, + "cost": "COST_REPLACED", + "filtered": 100, + "using_index": true + } } ] } @@ -13446,7 +13502,7 @@ union all select col2, col1 from v2; explain select * from v3 where col1=123; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 2 Using where +1 PRIMARY ref key0 key0 5 const 0 2 DERIVED t1 ref a a 5 const 1 3 UNION t1 ref a a 5 const 1 # This must use ref accesses for reading table t1, not full scans: @@ -13461,12 +13517,16 @@ EXPLAIN { "table": { "table_name": "", - "access_type": "ALL", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "10", + "used_key_parts": ["col2", "col1"], + "ref": ["const", "const"], "loops": 1, - "rows": 2, + "rows": 0, "cost": "COST_REPLACED", "filtered": 100, - "attached_condition": "v3.col1 = 123 and v3.col2 = 321", "materialized": { "query_block": { "union_result": { @@ -22573,7 +22633,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 const PRIMARY PRIMARY 4 const 1 Using index 1 PRIMARY t4 const PRIMARY,a NULL NULL NULL 0 Impossible ON condition 1 PRIMARY ref key0 key0 5 const 0 Using where -3 LATERAL DERIVED t5 ref id1 id1 5 const 0 Using index +3 LATERAL DERIVED t5 ref id1 id1 5 const 1 Using index DROP VIEW v1; DROP TABLE t1,t2,t3,t4,t5; # End of 10.3 tests @@ -22863,8 +22923,8 @@ t1.valdate = dt.maxdate AND t1.valint1 IN (SELECT * FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 21 Using where; Start temporary -1 PRIMARY t1 ref valint1,valint1_2 valint1 5 test.t2.a 2 Using index condition; Using where; End temporary -1 PRIMARY ref key0 key0 11 test.t1.valdate,test.t1.valint1 1 +1 PRIMARY t1 ref valint1,valint1_2 valint1 5 test.t2.a 2 Using index condition; End temporary +1 PRIMARY ref key0 key0 5 test.t1.valint1 1 Using where 2 LATERAL DERIVED t ref valint1,valint1_2 valint1 5 test.t2.a 2 Using index condition SELECT t1.valdouble, t1.valint1 FROM t1, diff --git a/mysql-test/main/derived_cond_pushdown_innodb.result b/mysql-test/main/derived_cond_pushdown_innodb.result index d01ce8cdd20a3..5a6ec26bbe717 100644 --- a/mysql-test/main/derived_cond_pushdown_innodb.result +++ b/mysql-test/main/derived_cond_pushdown_innodb.result @@ -15,7 +15,7 @@ JOIN ON CHARSET(dt2_c2) BETWEEN dt1_c1 AND dt1_c1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY system NULL NULL NULL NULL 1 100.00 -1 PRIMARY ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY ref key0 key0 9 const 0 100.00 Using where 3 DERIVED t2 system NULL NULL NULL NULL 1 100.00 2 DERIVED t1 ref c1 c1 9 const 1 100.00 Using where; Using index Warnings: @@ -29,7 +29,7 @@ JOIN ON COERCIBILITY(dt2_c2) BETWEEN dt1_c1 AND dt1_c1; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY system NULL NULL NULL NULL 1 100.00 -1 PRIMARY ALL NULL NULL NULL NULL 2 100.00 Using where +1 PRIMARY ref key0 key0 9 const 0 100.00 Using where 3 DERIVED t2 system NULL NULL NULL NULL 1 100.00 2 DERIVED t1 ref c1 c1 9 const 1 100.00 Using where; Using index Warnings: diff --git a/mysql-test/main/derived_opt.result b/mysql-test/main/derived_opt.result index 2e9cabeba867c..1dba3c3fea2e7 100644 --- a/mysql-test/main/derived_opt.result +++ b/mysql-test/main/derived_opt.result @@ -566,4 +566,347 @@ DROP TABLE t1, t2; # # End of 10.3 tests # +# +# MDEV-39499 Updates to derived-with-keys, window functions determining +# records per key +# +set @save_use_stat_tables=@@use_stat_tables; +set use_stat_tables='preferably'; +create table t1 (a int, b int) engine=MyISAM; +insert into t1 select seq, seq from seq_1_to_1000; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# no partition clause in derived table window function +# rows column for should always be 1 +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (ORDER BY ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 1 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with stats available +# we use statistics on t1.a to determine how many rows we estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 1000 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with no stats available +# we will use the row count of table referenced as our estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 3 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# multipart partition clause +# combine estimates from each part of the partition clause +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a, c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 3000 Using where +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# alter statistics to see 2 records per key +truncate t1; +insert into t1 select seq/2, seq/2 from seq_1_to_1000; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# no partition clause in derived table window function +# rows column for should always be 1 +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (ORDER BY ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 1 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with stats available +# we use statistics on t1.a to determine how many rows we estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 500 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with no stats available +# we will use the row count of table referenced as our estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 3 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# multipart partition clause +# combine estimates from each part of the partition clause +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a, c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 1500 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# alter statistics to see 10 records per key +truncate t1; +insert into t1 select seq/10, seq/10 from seq_1_to_1000; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# no partition clause in derived table window function +# rows column for should always be 1 +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (ORDER BY ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 1 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with stats available +# we use statistics on t1.a to determine how many rows we estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 100 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# single partition clause on table with no stats available +# we will use the row count of table referenced as our estimate +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 3 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +# multipart partition clause +# combine estimates from each part of the partition clause +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( +select * from +( +select c1, t1.a, +ROW_NUMBER() OVER (PARTITION BY a, c1 order by ABS(c3-b)) as ranked +from i1 join t1 +where ABS(c1)=ABS(a) +) as dt +where ranked = 1 +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ref key0 key0 8 const 302 +4 DERIVED ALL NULL NULL NULL NULL 3 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +explain +with i1 (c1, c2, c3) AS +( +values (1, 2, 4), (2, 3, 5), (4, 3, 4), (1, 2, 40), (2, 3, 50), (4, 3, 40), +(1, 2, 400), (2, 3, 500), (4, 3, 400), (1, 2, 4000), (2, 3, 5000), (4, 3, 4000) +), +ranked_table as +( +select * from +( +select c1,c2,c3, t1.a, +lead(a) OVER (PARTITION BY c1 order by c1) as lead, +lag(a) OVER (PARTITION BY c1 order by c3) as lag, +sum(a) OVER (PARTITION BY c1 order by c3 desc) as sum, +count(a) OVER (PARTITION BY c1 order by c1) as count +from i1 join t1 +) as dt +) +select * from ranked_table; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 12000 +4 DERIVED ALL NULL NULL NULL NULL 12 Using temporary +4 DERIVED t1 ALL NULL NULL NULL NULL 1000 Using join buffer (flat, BNL join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +drop table t1; +set use_stat_tables=@save_use_stat_tables; +# +# End of 11.4 tests +# set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/main/derived_opt.test b/mysql-test/main/derived_opt.test index 57c97cc407143..22b8fd1b53798 100644 --- a/mysql-test/main/derived_opt.test +++ b/mysql-test/main/derived_opt.test @@ -1,4 +1,5 @@ # Initialize +--source include/have_sequence.inc --disable_warnings drop table if exists t0,t1,t2,t3; drop database if exists test1; @@ -439,5 +440,172 @@ DROP TABLE t1, t2; --echo # End of 10.3 tests --echo # + +--echo # +--echo # MDEV-39499 Updates to derived-with-keys, window functions determining +--echo # records per key +--echo # + +set @save_use_stat_tables=@@use_stat_tables; +set use_stat_tables='preferably'; +create table t1 (a int, b int) engine=MyISAM; +insert into t1 select seq, seq from seq_1_to_1000; +analyze table t1 persistent for all; + +# no partition clause in derived table window function +let $q_0= +explain +with i1 (c1, c2, c3) AS +( + values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( + select * from + ( + select c1, t1.a, + ROW_NUMBER() OVER (ORDER BY ABS(c3-b)) as ranked + from i1 join t1 + where ABS(c1)=ABS(a) + ) as dt + where ranked = 1 +) +select * from ranked_table; + +# single partition clause on table with stats available +let $q_1= +explain +with i1 (c1, c2, c3) AS +( + values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( + select * from + ( + select c1, t1.a, + ROW_NUMBER() OVER (PARTITION BY a order by ABS(c3-b)) as ranked + from i1 join t1 + where ABS(c1)=ABS(a) + ) as dt + where ranked = 1 +) +select * from ranked_table; + +# single partition clause on table with no stats available +let $q_2= +explain +with i1 (c1, c2, c3) AS +( + values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( + select * from + ( + select c1, t1.a, + ROW_NUMBER() OVER (PARTITION BY c1 order by ABS(c3-b)) as ranked + from i1 join t1 + where ABS(c1)=ABS(a) + ) as dt + where ranked = 1 +) +select * from ranked_table; + +# multipart partition clause +let $q_3= +explain +with i1 (c1, c2, c3) AS +( + values (1, 2, 4), (2, 3, 5), (4, 3, 4) +), +ranked_table as +( + select * from + ( + select c1, t1.a, + ROW_NUMBER() OVER (PARTITION BY a, c1 order by ABS(c3-b)) as ranked + from i1 join t1 + where ABS(c1)=ABS(a) + ) as dt + where ranked = 1 +) +select * from ranked_table; + +--echo # no partition clause in derived table window function +--echo # rows column for should always be 1 +eval $q_0; +--echo # single partition clause on table with stats available +--echo # we use statistics on t1.a to determine how many rows we estimate +eval $q_1; +--echo # single partition clause on table with no stats available +--echo # we will use the row count of table referenced as our estimate +eval $q_2; +--echo # multipart partition clause +--echo # combine estimates from each part of the partition clause +eval $q_3; + +--echo # alter statistics to see 2 records per key +truncate t1; +insert into t1 select seq/2, seq/2 from seq_1_to_1000; +analyze table t1 persistent for all; + +--echo # no partition clause in derived table window function +--echo # rows column for should always be 1 +eval $q_0; +--echo # single partition clause on table with stats available +--echo # we use statistics on t1.a to determine how many rows we estimate +eval $q_1; +--echo # single partition clause on table with no stats available +--echo # we will use the row count of table referenced as our estimate +eval $q_2; +--echo # multipart partition clause +--echo # combine estimates from each part of the partition clause +eval $q_3; + +--echo # alter statistics to see 10 records per key +truncate t1; +insert into t1 select seq/10, seq/10 from seq_1_to_1000; +analyze table t1 persistent for all; + +--echo # no partition clause in derived table window function +--echo # rows column for should always be 1 +eval $q_0; +--echo # single partition clause on table with stats available +--echo # we use statistics on t1.a to determine how many rows we estimate +eval $q_1; +--echo # single partition clause on table with no stats available +--echo # we will use the row count of table referenced as our estimate +eval $q_2; +--echo # multipart partition clause +--echo # combine estimates from each part of the partition clause +eval $q_3; + +explain +with i1 (c1, c2, c3) AS +( + values (1, 2, 4), (2, 3, 5), (4, 3, 4), (1, 2, 40), (2, 3, 50), (4, 3, 40), + (1, 2, 400), (2, 3, 500), (4, 3, 400), (1, 2, 4000), (2, 3, 5000), (4, 3, 4000) +), +ranked_table as +( + select * from + ( + select c1,c2,c3, t1.a, + lead(a) OVER (PARTITION BY c1 order by c1) as lead, + lag(a) OVER (PARTITION BY c1 order by c3) as lag, + sum(a) OVER (PARTITION BY c1 order by c3 desc) as sum, + count(a) OVER (PARTITION BY c1 order by c1) as count + from i1 join t1 + ) as dt +) +select * from ranked_table; +drop table t1; +set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # End of 11.4 tests +--echo # + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/main/join_nested_jcl6.result b/mysql-test/main/join_nested_jcl6.result index 0ba5b55bea33b..c7b782273cf53 100644 --- a/mysql-test/main/join_nested_jcl6.result +++ b/mysql-test/main/join_nested_jcl6.result @@ -558,8 +558,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t0.b 3 10.00 Using where; Using join buffer (flat, BNLH join) 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 hash_ALL NULL #hash#$hj 5 test.t2.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) @@ -652,16 +652,16 @@ t0.b=t1.b AND id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t0.b 3 10.00 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE t9 hash_ALL NULL #hash#$hj 5 const 3 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 hash_ALL NULL #hash#$hj 5 test.t2.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t8 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) -1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t3`.`b` = `test`.`t4`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t9`.`b` = `test`.`t8`.`b` or `test`.`t8`.`c` is null) +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t4`.`b` = `test`.`t3`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) SELECT t9.a,t9.b FROM t9; a b @@ -849,8 +849,8 @@ WHERE t1.a <= 2; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 hash_ALL NULL #hash#$hj 5 test.t2.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`b` is not null) where `test`.`t1`.`a` <= 2 INSERT INTO t2 VALUES (-1,9,0), (-3,10,0), (-2,8,0), (-4,11,0), (-5,15,0); @@ -920,16 +920,16 @@ t0.b=t1.b AND id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t0.b 3 10.00 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE t9 hash_ALL NULL #hash#$hj 5 const 3 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t8 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 hash_ALL NULL #hash#$hj 5 test.t2.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) -1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t3`.`b` = `test`.`t4`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t9`.`b` = `test`.`t8`.`b` or `test`.`t8`.`c` is null) +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t4`.`b` = `test`.`t3`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) INSERT INTO t4 VALUES (-3,12,0), (-4,13,0), (-1,11,0), (-3,11,0), (-5,15,0); INSERT INTO t5 VALUES (-3,11,0), (-2,12,0), (-3,13,0), (-4,12,0); CREATE INDEX idx_b ON t4(b); @@ -972,16 +972,16 @@ t0.b=t1.b AND id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t0.b 3 10.00 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t9 hash_ALL NULL #hash#$hj 5 const 3 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t5 ALL idx_b NULL NULL NULL 7 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t8 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 1 100.00 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t4`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`a` > 0 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t3`.`b` = `test`.`t4`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t4`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`a` > 0 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t4`.`b` = `test`.`t3`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) INSERT INTO t8 VALUES (-3,12,0), (-1,14,0), (-5,15,0), (-1,11,0), (-4,13,0); CREATE INDEX idx_b ON t8(b); EXPLAIN EXTENDED @@ -1022,16 +1022,16 @@ t0.b=t1.b AND id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 hash_ALL NULL #hash#$hj 5 test.t0.b 3 10.00 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t9 hash_ALL NULL #hash#$hj 5 const 3 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t5 ALL idx_b NULL NULL NULL 7 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 1 100.00 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan 1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 1 100.00 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t4`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t8`.`a` >= 0 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`a` > 0 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t3`.`b` = `test`.`t4`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`a` > 0 and `test`.`t4`.`a` > 0 and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t8`.`a` >= 0 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`a` > 0 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t4`.`b` = `test`.`t3`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) INSERT INTO t1 VALUES (-1,133,0), (-2,12,0), (-3,11,0), (-5,15,0); CREATE INDEX idx_b ON t1(b); CREATE INDEX idx_a ON t0(a); @@ -1072,17 +1072,17 @@ t0.b=t1.b AND (t9.a=1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ref idx_a idx_a 5 const 2 100.00 Using where -1 SIMPLE t1 ref idx_b idx_b 5 test.t0.b 1 100.00 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t9 hash_ALL NULL #hash#$hj 5 const 3 10.00 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE t1 ref idx_b idx_b 5 test.t0.b 1 100.00 Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan 1 SIMPLE t5 ALL idx_b NULL NULL NULL 7 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t7 hash_ALL NULL #hash#$hj 5 test.t5.b 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 1 100.00 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan 1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 const 2 10.00 Using where; Using join buffer (incremental, BNLH join) 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 1 100.00 Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) Warnings: -Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2 and `test`.`t1`.`a` > 0) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t3`.`b` = `test`.`t4`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t3`.`a` = 1 and `test`.`t4`.`b` = `test`.`t2`.`b` and `test`.`t2`.`b` is not null) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(`test`.`t8`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` < 10 and `test`.`t5`.`b` is not null)) on(`test`.`t7`.`b` = `test`.`t5`.`b` and `test`.`t6`.`b` >= 2 and `test`.`t5`.`b` is not null)) on((`test`.`t3`.`b` = 2 or `test`.`t3`.`c` is null) and (`test`.`t6`.`b` = 2 or `test`.`t6`.`c` is null) and (`test`.`t5`.`b` = `test`.`t0`.`b` or `test`.`t3`.`c` is null or `test`.`t6`.`c` is null or `test`.`t8`.`c` is null) and `test`.`t1`.`a` <> 2 and `test`.`t1`.`a` > 0) join `test`.`t9` where `test`.`t0`.`a` = 1 and `test`.`t1`.`b` = `test`.`t0`.`b` and `test`.`t9`.`a` = 1 and (`test`.`t2`.`a` >= 4 or `test`.`t2`.`c` is null) and (`test`.`t3`.`a` < 5 or `test`.`t3`.`c` is null) and (`test`.`t4`.`b` = `test`.`t3`.`b` or `test`.`t3`.`c` is null or `test`.`t4`.`c` is null) and (`test`.`t5`.`a` >= 2 or `test`.`t5`.`c` is null) and (`test`.`t6`.`a` >= 4 or `test`.`t6`.`c` is null) and (`test`.`t7`.`a` <= 2 or `test`.`t7`.`c` is null) and (`test`.`t8`.`a` < 1 or `test`.`t8`.`c` is null) and (`test`.`t8`.`b` = `test`.`t9`.`b` or `test`.`t8`.`c` is null) SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b FROM t0,t1 @@ -1930,7 +1930,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00 1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index -1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists +1 SIMPLE t2i ALL NULL NULL NULL NULL 3 10.00 Using where; Not exists Warnings: Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`test`.`t2a`.`K2` AS `K2`,`test`.`t2a`.`K1r` AS `K1r`,`test`.`t2a`.`rowTimestamp` AS `rowTimestamp`,`test`.`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on(`test`.`t2i`.`K1r` = 1)) on(`test`.`t1i`.`K1` = 1 and (`test`.`t2i`.`K1r` = 1 and `test`.`t2i`.`rowTimestamp` > `test`.`t2a`.`rowTimestamp` or `test`.`t2i`.`rowTimestamp` = `test`.`t2a`.`rowTimestamp` and `test`.`t2i`.`K2` > `test`.`t2a`.`K2` or `test`.`t2i`.`K2` is null)) where `test`.`t2a`.`K1r` = 1 and `test`.`t2i`.`K2` is null CREATE VIEW v1 AS @@ -1969,7 +1969,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00 1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index -1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists +1 SIMPLE t2i ALL NULL NULL NULL NULL 3 10.00 Using where; Not exists Warnings: Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`t2a`.`K2` AS `K2`,`t2a`.`K1r` AS `K1r`,`t2a`.`rowTimestamp` AS `rowTimestamp`,`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on(`test`.`t2i`.`K1r` = 1)) on(`test`.`t1i`.`K1` = 1 and (`test`.`t2i`.`K1r` = 1 and `test`.`t2i`.`rowTimestamp` > `t2a`.`rowTimestamp` or `test`.`t2i`.`rowTimestamp` = `t2a`.`rowTimestamp` and `test`.`t2i`.`K2` > `t2a`.`K2` or `test`.`t2i`.`K2` is null)) where `t2a`.`K1r` = 1 and `test`.`t2i`.`K2` is null DROP VIEW v1; diff --git a/mysql-test/main/mrr_derived_crash_4610.result b/mysql-test/main/mrr_derived_crash_4610.result index d7800e8a2a94a..87c22ac4a110f 100644 --- a/mysql-test/main/mrr_derived_crash_4610.result +++ b/mysql-test/main/mrr_derived_crash_4610.result @@ -8,7 +8,7 @@ explain select 1 from join t1 on f1 = f3 where f3 = 'aaaa' order by val; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY PRIMARY 12 const 1 -1 PRIMARY ref key0 key0 13 const 0 Using where; Using filesort +1 PRIMARY ref key0 key0 13 const 0 Using index condition; Using where; Using filesort 2 DERIVED t4 ALL NULL NULL NULL NULL 1 2 DERIVED t2 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join) 2 DERIVED t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) diff --git a/mysql-test/main/rowid_filter_myisam.result b/mysql-test/main/rowid_filter_myisam.result index e385f0086ca0f..7a89b0f4a75f9 100644 --- a/mysql-test/main/rowid_filter_myisam.result +++ b/mysql-test/main/rowid_filter_myisam.result @@ -91,7 +91,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING -2 SUBQUERY t2 index_subquery i1,i2 i2 5 const 10 0.92 Using where +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table Warnings: Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk` from `test`.`t1` having 0 DROP TABLE t1,t2; diff --git a/mysql-test/main/subselect3_jcl6.result b/mysql-test/main/subselect3_jcl6.result index 3e1f471ace487..dbb47aba1cdb8 100644 --- a/mysql-test/main/subselect3_jcl6.result +++ b/mysql-test/main/subselect3_jcl6.result @@ -1363,7 +1363,7 @@ count(*) explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -1 PRIMARY X hash_ALL NULL #hash#$hj 5 test.t1.a 6 Using where; Start temporary; Using join buffer (flat, BNLH join) +1 PRIMARY X hash_ALL NULL #hash#$hj 10 const,test.t1.a 6 Using where; Start temporary; Using join buffer (flat, BNLH join) 1 PRIMARY Y hash_ALL NULL #hash#$hj 5 test.t1.b 6 Using where; Using join buffer (incremental, BNLH join) 1 PRIMARY Z hash_ALL NULL #hash#$hj 5 test.t1.c 6 Using where; End temporary; Using join buffer (incremental, BNLH join) drop table t0,t1,t2; @@ -1438,11 +1438,11 @@ INNER JOIN t2 c ON c.idContact=cona.idContact WHERE cona.postalStripped='T2H3B2' ); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY cona ALL NULL NULL NULL NULL 2 100.00 Using where; Start temporary -1 PRIMARY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 PRIMARY a eq_ref PRIMARY PRIMARY 4 test.c.idObj 1 50.00 Using index; End temporary +1 PRIMARY a index PRIMARY PRIMARY 4 NULL 3 100.00 Using index +1 PRIMARY cona ALL NULL NULL NULL NULL 2 10.00 Using where; Using join buffer (flat, BNL join) +1 PRIMARY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00 Using where; FirstMatch(a); Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan Warnings: -Note 1003 select `test`.`a`.`idIndividual` AS `idIndividual` from `test`.`t1` `a` semi join (`test`.`t3` `cona` join `test`.`t2` `c`) where `test`.`cona`.`postalStripped` = 'T2H3B2' and `test`.`a`.`idIndividual` = `test`.`c`.`idObj` and `test`.`c`.`idContact` = `test`.`cona`.`idContact` +Note 1003 select `test`.`a`.`idIndividual` AS `idIndividual` from `test`.`t1` `a` semi join (`test`.`t3` `cona` join `test`.`t2` `c`) where `test`.`cona`.`postalStripped` = 'T2H3B2' and `test`.`c`.`idObj` = `test`.`a`.`idIndividual` and `test`.`c`.`idContact` = `test`.`cona`.`idContact` SELECT a.idIndividual FROM t1 a WHERE a.idIndividual IN ( SELECT c.idObj FROM t3 cona diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 7230c692d8a6d..4d77fa6c43863 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -1514,7 +1514,7 @@ EXPLAIN SELECT 'bug' FROM DUAL WHERE ( 5 ) IN ( SELECT * FROM v1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 4 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 4 const 1 Using where 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used 4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1524,7 +1524,7 @@ EXPLAIN SELECT ( 5 ) IN ( SELECT * FROM v1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 4 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 4 const 1 Using where 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used 4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1535,7 +1535,7 @@ EXPLAIN SELECT 'bug' FROM DUAL WHERE ( 5 ) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 5 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 5 const 1 Using where 3 DERIVED t1 system NULL NULL NULL NULL 1 4 UNION t2 system NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1567,7 +1567,7 @@ EXPLAIN SELECT 'bug' FROM DUAL WHERE ( 5 ) IN ( SELECT * FROM v1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 4 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 4 const 1 Using where 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used 4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1577,7 +1577,7 @@ EXPLAIN SELECT ( 5 ) IN ( SELECT * FROM v1 ); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 4 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 4 const 1 Using where 3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used 4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1588,7 +1588,7 @@ EXPLAIN SELECT 'bug' FROM DUAL WHERE ( 5 ) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used -2 SUBQUERY const NULL distinct_key 5 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 5 const 1 Using where 3 DERIVED t1 system NULL NULL NULL NULL 1 4 UNION t2 system NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -1598,7 +1598,7 @@ EXPLAIN SELECT 'bug' FROM t3 WHERE ( 5 ) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 -2 SUBQUERY const NULL distinct_key 5 const 1 Using where +2 SUBQUERY const distinct_key distinct_key 5 const 1 Using where 3 DERIVED t1 system NULL NULL NULL NULL 1 4 UNION t2 system NULL NULL NULL NULL 1 NULL UNION RESULT ALL NULL NULL NULL NULL NULL diff --git a/mysql-test/main/subselect_mat.result b/mysql-test/main/subselect_mat.result index 7be03643d90a5..59d201859c204 100644 --- a/mysql-test/main/subselect_mat.result +++ b/mysql-test/main/subselect_mat.result @@ -2018,7 +2018,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 1 PRIMARY t2 index NULL c 5 NULL 8 Using where; Using index 2 MATERIALIZED s2 ref d d 4 const 2 Using where; Using index -2 MATERIALIZED s1 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED s1 hash_ALL NULL #hash#$hj 4 const 8 Using where; Using join buffer (flat, BNLH join) 3 SUBQUERY t2 ALL NULL NULL NULL NULL 8 SELECT a, c FROM t1, t2 WHERE (a, c) IN (SELECT s1.b, s1.c FROM t2 AS s1, t2 AS s2 diff --git a/mysql-test/suite/heap/heap.result b/mysql-test/suite/heap/heap.result index 70d2239496eb0..ade563faae7c6 100644 --- a/mysql-test/suite/heap/heap.result +++ b/mysql-test/suite/heap/heap.result @@ -795,7 +795,7 @@ EXPLAIN SELECT col_int_nokey FROM t2 WHERE ('h', 0) NOT IN ( SELECT * FROM v1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 -2 SUBQUERY ALL NULL NULL NULL NULL 2 Using where +2 SUBQUERY ref key0 key0 8 const 0 Using where 3 DERIVED t1 range PRIMARY PRIMARY 4 NULL 1 Using index condition; Using where DROP TABLE t1,t2,h1; DROP VIEW v1; diff --git a/mysql-test/suite/sysschema/r/v_privileges_by_table_by_level.result b/mysql-test/suite/sysschema/r/v_privileges_by_table_by_level.result index 63b0d71ced6b2..e8e4e29ca945a 100644 --- a/mysql-test/suite/sysschema/r/v_privileges_by_table_by_level.result +++ b/mysql-test/suite/sysschema/r/v_privileges_by_table_by_level.result @@ -17,78 +17,78 @@ CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END, privilege, level FROM sys.privileges_by_table_by_level WHERE table_name='t1'; table_schema table_name CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END privilege level -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL +test1 t1 'test1_user'@'%' ALTER SCHEMA +test1 t1 'test1_user'@'%' ALTER TABLE +test1 t1 'test1_user'@'%' CREATE SCHEMA +test1 t1 'test1_user'@'%' CREATE TABLE +test1 t1 'test1_user'@'%' DELETE SCHEMA +test1 t1 'test1_user'@'%' DELETE TABLE +test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA +test1 t1 'test1_user'@'%' DELETE HISTORY TABLE +test1 t1 'test1_user'@'%' DROP SCHEMA +test1 t1 'test1_user'@'%' DROP TABLE +test1 t1 'test1_user'@'%' INDEX SCHEMA +test1 t1 'test1_user'@'%' INDEX TABLE +test1 t1 'test1_user'@'%' INSERT SCHEMA +test1 t1 'test1_user'@'%' INSERT TABLE +test1 t1 'test1_user'@'%' REFERENCES SCHEMA +test1 t1 'test1_user'@'%' REFERENCES TABLE +test1 t1 'test1_user'@'%' SELECT SCHEMA +test1 t1 'test1_user'@'%' SELECT TABLE +test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA +test1 t1 'test1_user'@'%' SHOW VIEW TABLE +test1 t1 'test1_user'@'%' TRIGGER SCHEMA +test1 t1 'test1_user'@'%' TRIGGER TABLE +test1 t1 'test1_user'@'%' UPDATE SCHEMA +test1 t1 'test1_user'@'%' UPDATE TABLE test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL +test1 t1 ALTER GLOBAL +test1 t1 ALTER GLOBAL +test1 t1 CREATE GLOBAL +test1 t1 CREATE GLOBAL +test1 t1 CREATE GLOBAL test1 t1 CREATE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DROP GLOBAL +test1 t1 DROP GLOBAL +test1 t1 DROP GLOBAL test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL test1 t1 INDEX GLOBAL -test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INSERT GLOBAL +test1 t1 INSERT GLOBAL +test1 t1 INSERT GLOBAL test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL -test1 t1 ALTER GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SHOW VIEW GLOBAL +test1 t1 SHOW VIEW GLOBAL +test1 t1 SHOW VIEW GLOBAL test1 t1 SHOW VIEW GLOBAL test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 'test1_user'@'%' SELECT SCHEMA -test1 t1 'test1_user'@'%' INSERT SCHEMA -test1 t1 'test1_user'@'%' UPDATE SCHEMA -test1 t1 'test1_user'@'%' DELETE SCHEMA -test1 t1 'test1_user'@'%' CREATE SCHEMA -test1 t1 'test1_user'@'%' DROP SCHEMA -test1 t1 'test1_user'@'%' REFERENCES SCHEMA -test1 t1 'test1_user'@'%' INDEX SCHEMA -test1 t1 'test1_user'@'%' ALTER SCHEMA -test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA -test1 t1 'test1_user'@'%' TRIGGER SCHEMA -test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA -test1 t1 'test1_user'@'%' SELECT TABLE -test1 t1 'test1_user'@'%' INSERT TABLE -test1 t1 'test1_user'@'%' UPDATE TABLE -test1 t1 'test1_user'@'%' DELETE TABLE -test1 t1 'test1_user'@'%' CREATE TABLE -test1 t1 'test1_user'@'%' DROP TABLE -test1 t1 'test1_user'@'%' REFERENCES TABLE -test1 t1 'test1_user'@'%' INDEX TABLE -test1 t1 'test1_user'@'%' ALTER TABLE -test1 t1 'test1_user'@'%' SHOW VIEW TABLE -test1 t1 'test1_user'@'%' TRIGGER TABLE -test1 t1 'test1_user'@'%' DELETE HISTORY TABLE +test1 t1 TRIGGER GLOBAL +test1 t1 TRIGGER GLOBAL +test1 t1 TRIGGER GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL # Revoke some table privileges REVOKE REFERENCES, DELETE, ALTER, DROP ON t1 FROM test1_user; SELECT table_schema, table_name, @@ -96,167 +96,167 @@ CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END, privilege, level FROM sys.privileges_by_table_by_level WHERE table_name='t1'; table_schema table_name CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END privilege level -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL +test1 t1 'test1_user'@'%' ALTER SCHEMA +test1 t1 'test1_user'@'%' CREATE SCHEMA +test1 t1 'test1_user'@'%' CREATE TABLE +test1 t1 'test1_user'@'%' DELETE SCHEMA +test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA +test1 t1 'test1_user'@'%' DELETE HISTORY TABLE +test1 t1 'test1_user'@'%' DROP SCHEMA +test1 t1 'test1_user'@'%' INDEX SCHEMA +test1 t1 'test1_user'@'%' INDEX TABLE +test1 t1 'test1_user'@'%' INSERT SCHEMA +test1 t1 'test1_user'@'%' INSERT TABLE +test1 t1 'test1_user'@'%' REFERENCES SCHEMA +test1 t1 'test1_user'@'%' SELECT SCHEMA +test1 t1 'test1_user'@'%' SELECT TABLE +test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA +test1 t1 'test1_user'@'%' SHOW VIEW TABLE +test1 t1 'test1_user'@'%' TRIGGER SCHEMA +test1 t1 'test1_user'@'%' TRIGGER TABLE +test1 t1 'test1_user'@'%' UPDATE SCHEMA +test1 t1 'test1_user'@'%' UPDATE TABLE +test1 t1 ALTER GLOBAL +test1 t1 ALTER GLOBAL test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL -test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL test1 t1 CREATE GLOBAL +test1 t1 CREATE GLOBAL +test1 t1 CREATE GLOBAL +test1 t1 CREATE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DELETE HISTORY GLOBAL +test1 t1 DROP GLOBAL +test1 t1 DROP GLOBAL +test1 t1 DROP GLOBAL test1 t1 DROP GLOBAL -test1 t1 REFERENCES GLOBAL test1 t1 INDEX GLOBAL -test1 t1 ALTER GLOBAL -test1 t1 SHOW VIEW GLOBAL -test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 SELECT GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INDEX GLOBAL +test1 t1 INSERT GLOBAL +test1 t1 INSERT GLOBAL +test1 t1 INSERT GLOBAL test1 t1 INSERT GLOBAL -test1 t1 UPDATE GLOBAL -test1 t1 DELETE GLOBAL -test1 t1 CREATE GLOBAL -test1 t1 DROP GLOBAL test1 t1 REFERENCES GLOBAL -test1 t1 INDEX GLOBAL -test1 t1 ALTER GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 REFERENCES GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SELECT GLOBAL +test1 t1 SHOW VIEW GLOBAL +test1 t1 SHOW VIEW GLOBAL +test1 t1 SHOW VIEW GLOBAL test1 t1 SHOW VIEW GLOBAL test1 t1 TRIGGER GLOBAL -test1 t1 DELETE HISTORY GLOBAL -test1 t1 'test1_user'@'%' SELECT SCHEMA -test1 t1 'test1_user'@'%' INSERT SCHEMA -test1 t1 'test1_user'@'%' UPDATE SCHEMA -test1 t1 'test1_user'@'%' DELETE SCHEMA -test1 t1 'test1_user'@'%' CREATE SCHEMA -test1 t1 'test1_user'@'%' DROP SCHEMA -test1 t1 'test1_user'@'%' REFERENCES SCHEMA -test1 t1 'test1_user'@'%' INDEX SCHEMA -test1 t1 'test1_user'@'%' ALTER SCHEMA -test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA -test1 t1 'test1_user'@'%' TRIGGER SCHEMA -test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA -test1 t1 'test1_user'@'%' SELECT TABLE -test1 t1 'test1_user'@'%' INSERT TABLE -test1 t1 'test1_user'@'%' UPDATE TABLE -test1 t1 'test1_user'@'%' CREATE TABLE -test1 t1 'test1_user'@'%' INDEX TABLE -test1 t1 'test1_user'@'%' SHOW VIEW TABLE -test1 t1 'test1_user'@'%' TRIGGER TABLE -test1 t1 'test1_user'@'%' DELETE HISTORY TABLE +test1 t1 TRIGGER GLOBAL +test1 t1 TRIGGER GLOBAL +test1 t1 TRIGGER GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL +test1 t1 UPDATE GLOBAL CREATE ROLE test1_role; GRANT SELECT, UPDATE, DELETE, DROP, INDEX ON t1 to test1_role; # Must show both the user and the role SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='t1' AND grantee LIKE '%test1%'; TABLE_SCHEMA TABLE_NAME GRANTEE PRIVILEGE LEVEL -test1 t1 'test1_user'@'%' SELECT SCHEMA -test1 t1 'test1_user'@'%' INSERT SCHEMA -test1 t1 'test1_user'@'%' UPDATE SCHEMA -test1 t1 'test1_user'@'%' DELETE SCHEMA +test1 t1 'test1_role'@'' DELETE TABLE +test1 t1 'test1_role'@'' DROP TABLE +test1 t1 'test1_role'@'' INDEX TABLE +test1 t1 'test1_role'@'' SELECT TABLE +test1 t1 'test1_role'@'' UPDATE TABLE +test1 t1 'test1_user'@'%' ALTER SCHEMA test1 t1 'test1_user'@'%' CREATE SCHEMA +test1 t1 'test1_user'@'%' CREATE TABLE +test1 t1 'test1_user'@'%' DELETE SCHEMA +test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA +test1 t1 'test1_user'@'%' DELETE HISTORY TABLE test1 t1 'test1_user'@'%' DROP SCHEMA -test1 t1 'test1_user'@'%' REFERENCES SCHEMA test1 t1 'test1_user'@'%' INDEX SCHEMA -test1 t1 'test1_user'@'%' ALTER SCHEMA -test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA -test1 t1 'test1_user'@'%' TRIGGER SCHEMA -test1 t1 'test1_user'@'%' DELETE HISTORY SCHEMA -test1 t1 'test1_user'@'%' SELECT TABLE -test1 t1 'test1_user'@'%' INSERT TABLE -test1 t1 'test1_user'@'%' UPDATE TABLE -test1 t1 'test1_user'@'%' CREATE TABLE test1 t1 'test1_user'@'%' INDEX TABLE +test1 t1 'test1_user'@'%' INSERT SCHEMA +test1 t1 'test1_user'@'%' INSERT TABLE +test1 t1 'test1_user'@'%' REFERENCES SCHEMA +test1 t1 'test1_user'@'%' SELECT SCHEMA +test1 t1 'test1_user'@'%' SELECT TABLE +test1 t1 'test1_user'@'%' SHOW VIEW SCHEMA test1 t1 'test1_user'@'%' SHOW VIEW TABLE +test1 t1 'test1_user'@'%' TRIGGER SCHEMA test1 t1 'test1_user'@'%' TRIGGER TABLE -test1 t1 'test1_user'@'%' DELETE HISTORY TABLE -test1 t1 'test1_role'@'' SELECT TABLE -test1 t1 'test1_role'@'' UPDATE TABLE -test1 t1 'test1_role'@'' DELETE TABLE -test1 t1 'test1_role'@'' DROP TABLE -test1 t1 'test1_role'@'' INDEX TABLE +test1 t1 'test1_user'@'%' UPDATE SCHEMA +test1 t1 'test1_user'@'%' UPDATE TABLE CREATE VIEW v1 AS SELECT * FROM t1; SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; TABLE_SCHEMA TABLE_NAME GRANTEE PRIVILEGE LEVEL -test1 v1 'test1_user'@'%' SELECT SCHEMA -test1 v1 'test1_user'@'%' INSERT SCHEMA -test1 v1 'test1_user'@'%' UPDATE SCHEMA -test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_user'@'%' ALTER SCHEMA test1 v1 'test1_user'@'%' CREATE SCHEMA +test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA test1 v1 'test1_user'@'%' DROP SCHEMA -test1 v1 'test1_user'@'%' REFERENCES SCHEMA test1 v1 'test1_user'@'%' INDEX SCHEMA -test1 v1 'test1_user'@'%' ALTER SCHEMA +test1 v1 'test1_user'@'%' INSERT SCHEMA +test1 v1 'test1_user'@'%' REFERENCES SCHEMA +test1 v1 'test1_user'@'%' SELECT SCHEMA test1 v1 'test1_user'@'%' SHOW VIEW SCHEMA test1 v1 'test1_user'@'%' TRIGGER SCHEMA -test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA +test1 v1 'test1_user'@'%' UPDATE SCHEMA GRANT SELECT ON v1 TO test1_role; SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; TABLE_SCHEMA TABLE_NAME GRANTEE PRIVILEGE LEVEL -test1 v1 'test1_user'@'%' SELECT SCHEMA -test1 v1 'test1_user'@'%' INSERT SCHEMA -test1 v1 'test1_user'@'%' UPDATE SCHEMA -test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_role'@'' SELECT TABLE +test1 v1 'test1_user'@'%' ALTER SCHEMA test1 v1 'test1_user'@'%' CREATE SCHEMA +test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA test1 v1 'test1_user'@'%' DROP SCHEMA -test1 v1 'test1_user'@'%' REFERENCES SCHEMA test1 v1 'test1_user'@'%' INDEX SCHEMA -test1 v1 'test1_user'@'%' ALTER SCHEMA +test1 v1 'test1_user'@'%' INSERT SCHEMA +test1 v1 'test1_user'@'%' REFERENCES SCHEMA +test1 v1 'test1_user'@'%' SELECT SCHEMA test1 v1 'test1_user'@'%' SHOW VIEW SCHEMA test1 v1 'test1_user'@'%' TRIGGER SCHEMA -test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA -test1 v1 'test1_role'@'' SELECT TABLE +test1 v1 'test1_user'@'%' UPDATE SCHEMA GRANT ALL ON v1 TO test1_user; SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; TABLE_SCHEMA TABLE_NAME GRANTEE PRIVILEGE LEVEL -test1 v1 'test1_user'@'%' SELECT SCHEMA -test1 v1 'test1_user'@'%' INSERT SCHEMA -test1 v1 'test1_user'@'%' UPDATE SCHEMA -test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_role'@'' SELECT TABLE +test1 v1 'test1_user'@'%' ALTER SCHEMA +test1 v1 'test1_user'@'%' ALTER TABLE test1 v1 'test1_user'@'%' CREATE SCHEMA +test1 v1 'test1_user'@'%' CREATE TABLE +test1 v1 'test1_user'@'%' DELETE SCHEMA +test1 v1 'test1_user'@'%' DELETE TABLE +test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA +test1 v1 'test1_user'@'%' DELETE HISTORY TABLE test1 v1 'test1_user'@'%' DROP SCHEMA -test1 v1 'test1_user'@'%' REFERENCES SCHEMA +test1 v1 'test1_user'@'%' DROP TABLE test1 v1 'test1_user'@'%' INDEX SCHEMA -test1 v1 'test1_user'@'%' ALTER SCHEMA -test1 v1 'test1_user'@'%' SHOW VIEW SCHEMA -test1 v1 'test1_user'@'%' TRIGGER SCHEMA -test1 v1 'test1_user'@'%' DELETE HISTORY SCHEMA -test1 v1 'test1_user'@'%' SELECT TABLE +test1 v1 'test1_user'@'%' INDEX TABLE +test1 v1 'test1_user'@'%' INSERT SCHEMA test1 v1 'test1_user'@'%' INSERT TABLE -test1 v1 'test1_user'@'%' UPDATE TABLE -test1 v1 'test1_user'@'%' DELETE TABLE -test1 v1 'test1_user'@'%' CREATE TABLE -test1 v1 'test1_user'@'%' DROP TABLE +test1 v1 'test1_user'@'%' REFERENCES SCHEMA test1 v1 'test1_user'@'%' REFERENCES TABLE -test1 v1 'test1_user'@'%' INDEX TABLE -test1 v1 'test1_user'@'%' ALTER TABLE +test1 v1 'test1_user'@'%' SELECT SCHEMA +test1 v1 'test1_user'@'%' SELECT TABLE +test1 v1 'test1_user'@'%' SHOW VIEW SCHEMA test1 v1 'test1_user'@'%' SHOW VIEW TABLE +test1 v1 'test1_user'@'%' TRIGGER SCHEMA test1 v1 'test1_user'@'%' TRIGGER TABLE -test1 v1 'test1_user'@'%' DELETE HISTORY TABLE -test1 v1 'test1_role'@'' SELECT TABLE +test1 v1 'test1_user'@'%' UPDATE SCHEMA +test1 v1 'test1_user'@'%' UPDATE TABLE DROP TABLE t1; DROP VIEW v1; DROP USER test1_user; diff --git a/mysql-test/suite/sysschema/t/v_privileges_by_table_by_level.test b/mysql-test/suite/sysschema/t/v_privileges_by_table_by_level.test index 3e866a621b160..b0e7f9acd4019 100644 --- a/mysql-test/suite/sysschema/t/v_privileges_by_table_by_level.test +++ b/mysql-test/suite/sysschema/t/v_privileges_by_table_by_level.test @@ -14,6 +14,7 @@ GRANT ALL PRIVILEGES ON test1.* TO test1_user; --echo # Grant all table privileges GRANT ALL ON t1 to test1_user; +--sorted_result SELECT table_schema, table_name, CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END, privilege, level @@ -21,6 +22,7 @@ SELECT table_schema, table_name, --echo # Revoke some table privileges REVOKE REFERENCES, DELETE, ALTER, DROP ON t1 FROM test1_user; +--sorted_result SELECT table_schema, table_name, CASE WHEN grantee LIKE '\'root%' THEN '' ELSE GRANTEE END, privilege, level @@ -30,18 +32,22 @@ CREATE ROLE test1_role; GRANT SELECT, UPDATE, DELETE, DROP, INDEX ON t1 to test1_role; --echo # Must show both the user and the role +--sorted_result SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='t1' AND grantee LIKE '%test1%'; CREATE VIEW v1 AS SELECT * FROM t1; +--sorted_result SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; GRANT SELECT ON v1 TO test1_role; +--sorted_result SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; GRANT ALL ON v1 TO test1_user; +--sorted_result SELECT * FROM sys.privileges_by_table_by_level WHERE table_schema='test1' AND table_name='v1' AND grantee LIKE '%test1%'; diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1fc81dbe0aef3..7f7136dfba3f4 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -114,6 +114,7 @@ SET (SQL_SOURCE ../sql-common/client_plugin.c opt_range.cc opt_group_by_cardinality.cc + opt_window_function_cardinality.cc opt_rewrite_date_cmp.cc opt_rewrite_remove_casefold.cc opt_sum.cc diff --git a/sql/field.h b/sql/field.h index d6b61d235cb61..631abdd8ca890 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4012,6 +4012,7 @@ class Field_datetimef final :public Field_datetime_with_dec { longlong val_datetime_packed(THD *thd) override; uint size_of() const override { return sizeof *this; } Binlog_type_info binlog_type_info() const override; + bool hash_join_is_possible() override { return !null_bit; }; //MDEV-39369 }; diff --git a/sql/opt_window_function_cardinality.cc b/sql/opt_window_function_cardinality.cc new file mode 100644 index 0000000000000..d3ae199fc595c --- /dev/null +++ b/sql/opt_window_function_cardinality.cc @@ -0,0 +1,150 @@ +/* + Copyright (c) 2026, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +/** + @file + + Contains est_derived_window_fn_cardinality() +*/ + +#include "mariadb.h" +#include "sql_priv.h" +#include "sql_select.h" +#include "sql_statistics.h" +#include "item_windowfunc.h" +#include "opt_window_function_cardinality.h" + + +/* + @brief + Ignoring the selectivity of any join conditions, estimate the number of + rows produced by the partition clause of a row_number window function + in our derived table. This is a simple multiplication of the estimate + of the number of distinct values for each partition element, starting + with 1 for zero elements. +*/ + +static ha_rows handle_single_part_rownumber( Item_window_func *item_row_number) +{ + if (item_row_number->window_spec->partition_list && + item_row_number->window_spec->partition_list->elements) + { + double records= 1; + ORDER *part_list= item_row_number->window_spec->partition_list->first; + for (; part_list; part_list= part_list->next) + { + if ((*part_list->item)->type() == Item::FIELD_ITEM) + { + Item_field *item_field= ((Item_field*)(*part_list->item)); + DBUG_ASSERT(item_field); + Field *field= item_field->field; + DBUG_ASSERT(field); + /* + use EITS records per key if we have them, + otherwise + use number of records in the table (as a worst case scenario) + */ + if (field->read_stats) + { + // records*= field->read_stats->get_avg_frequency(); + double freq= field->read_stats->get_avg_frequency(); + records*= freq > 0 ? field->table->used_stat_records / freq + : (double)field->table->used_stat_records; + } + else + records*= (double)field->table->used_stat_records; + } + } + return records < 1.0 ? (ha_rows)1 : (ha_rows)records; + } + else + { + return (ha_rows)1; + } +} + + +/* + @brief + Given a SELECT with a window function, estimate the number of output rows + + @detail + Consider a derived table of the form + + SELECT ..., ROW_NUMBER () OVER (PARTITION BY c1,c2 order by ...) + FROM t1, t2, t3 ... + WHERE ... + + The optimizer can push outside predicates into this table and generate + a temporary key on this materialized table. + + If a key generated on the derived table column of the row_number window + function, we can infer row numbers by ignoring any join conditions and + looking at the source of the data for columns c1, c2 + + Currently we ignore the rest of the key parts. + + @param + derived the SELECT_LEX corresponding to our derived table + out_records pointer to out (maybe) written result. + reg_fields and array of field pointer to parts of the keys + key_parts the number of parts to the key + + @return + true if we have an estimate + false if no estimate is possible +*/ + +bool est_derived_window_fn_cardinality(st_select_lex* derived, + ulong *out_records, + Field **reg_fields, + uint key_parts) +{ + uint fc= 0; + + while (fc < key_parts) + { + uint ic= 0; + if (!reg_fields[fc]) + { + fc++; + continue; + } + uint field_index= reg_fields[fc]->field_index; + List_iterator_fast li(*derived->get_item_list()); + Item *item; + + // find our window function in the item list + while ((item= li++)) + { + // if the single part key is on our window function + if ((ic == field_index) && item->type() == Item::WINDOW_FUNC_ITEM) + { + Item_window_func *itm_row_num= (Item_window_func*)item; + + if (itm_row_num->window_func()->sum_func() == Item_sum::ROW_NUMBER_FUNC) + { + *out_records= (ulong)handle_single_part_rownumber(itm_row_num); + return true; + } + } + ic++; + } + fc++; + } + + return false; +} diff --git a/sql/opt_window_function_cardinality.h b/sql/opt_window_function_cardinality.h new file mode 100644 index 0000000000000..f3493ac1e4014 --- /dev/null +++ b/sql/opt_window_function_cardinality.h @@ -0,0 +1,26 @@ +/* + Copyright (c) 2026, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#ifndef OPT_WINDOW_FUNCTION_CARDINALITY_INCLUDED +#define OPT_WINDOW_FUNCTION_CARDINALITY_INCLUDED + +bool est_derived_window_fn_cardinality(st_select_lex* derived, + ulong *out_records, + Field **reg_fields, + uint key_parts); + +#endif /* OPT_WINDOW_FUNCTION_CARDINALITY_INCLUDED */ + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aefdd6d5d883b..53495b7db66a0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7365,22 +7365,40 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field) */ if (!field->compression_method() && field->hash_join_is_possible() && - (key_field->optimize & KEY_OPTIMIZE_EQ) && - key_field->val->used_tables()) + (key_field->optimize & KEY_OPTIMIZE_EQ)) { - if (field->can_optimize_hash_join(key_field->cond, key_field->val) != - Data_type_compatibility::OK) - return false; - if (form->is_splittable()) - form->add_splitting_info_for_key_field(key_field); - /* - If a key use is extracted from an equi-join predicate then it is - added not only as a key use for every index whose component can - be evalusted utilizing this key use, but also as a key use for - hash join. Such key uses are marked with a special key number. - */ - if (add_keyuse(keyuse_array, key_field, get_hash_join_key_no(), 0)) - return TRUE; + bool not_derived_grouped= true; + TABLE_LIST *tl= form->pos_in_table_list; + /* + Check that a key built on a derived table isn't grouped + */ + if (tl->is_materialized_derived()) + { + st_select_lex_unit *unit= tl->derived; + for( st_select_lex *sl= unit->first_select(); + sl; + sl= sl->next_select()) + { + if (sl->group_list.elements) + not_derived_grouped= false; + } + } + if (not_derived_grouped || key_field->val->used_tables()) + { + if (field->can_optimize_hash_join(key_field->cond, key_field->val) != + Data_type_compatibility::OK) + return false; + if (form->is_splittable()) + form->add_splitting_info_for_key_field(key_field); + /* + If a key use is extracted from an equi-join predicate then it is + added not only as a key use for every index whose component can + be evalusted utilizing this key use, but also as a key use for + hash join. Such key uses are marked with a special key number. + */ + if (add_keyuse(keyuse_array, key_field, get_hash_join_key_no(), 0)) + return TRUE; + } } } return FALSE; @@ -9002,8 +9020,14 @@ best_access_path(JOIN *join, table->opt_range[key].get_costs(&tmp); goto got_cost2; } - /* quick_range couldn't use key! */ - records= (double) s->records/rec; + /* + quick_range couldn't use key! + Check records per key, it may have been inferred from + derived table characteristics, so there will be no table map. + */ + if (!(records= + keyinfo->rec_per_key_null_aware(key_parts-1, notnull_part))) + records= (double) s->records/rec; if (unlikely(trace_access_idx.trace_started())) trace_access_idx. add("used_range_estimates", false). diff --git a/sql/table.cc b/sql/table.cc index 56c6eef387361..57d9987cf8e56 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -55,6 +55,9 @@ #endif #include "log_event.h" // MAX_TABLE_MAP_ID #include "sql_class.h" +#include "item_windowfunc.h" +#include "sql_statistics.h" +#include "opt_window_function_cardinality.h" /* For MySQL 5.7 virtual fields */ #define MYSQL57_GENERATED_FIELD 128 @@ -8581,6 +8584,9 @@ bool TABLE::check_tmp_key(uint key, uint key_parts, uint i; uint key_len= 0; + if (key_parts > MAX_REF_PARTS) + return FALSE; + for (i= 0; i < key_parts; i++) { uint fld_idx= next_field_no(arg); @@ -8603,6 +8609,7 @@ bool TABLE::check_tmp_key(uint key, uint key_parts, return key_len <= MI_MAX_KEY_LENGTH; } + /** @brief Add one key to a temporary table @@ -8633,7 +8640,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, char buf[NAME_CHAR_LEN]; KEY *keyinfo= key_info + key; KEY_PART_INFO *key_part_info; - Field **reg_field; + Field *reg_field[MAX_REF_PARTS]; uint i; bool key_start= TRUE; @@ -8667,13 +8674,13 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, for (i= 0; i < key_parts; i++) { uint fld_idx= next_field_no(arg); - reg_field= field + fld_idx; + reg_field[i]= field[fld_idx]; if (key_start) - (*reg_field)->key_start.set_bit(key); - (*reg_field)->part_of_key.set_bit(key); - create_key_part_by_field(key_part_info, *reg_field, fld_idx+1); + reg_field[i]->key_start.set_bit(key); + reg_field[i]->part_of_key.set_bit(key); + create_key_part_by_field(key_part_info, reg_field[i], fld_idx+1); keyinfo->key_length += key_part_info->store_length; - (*reg_field)->flags|= PART_KEY_FLAG; + reg_field[i]->flags|= PART_KEY_FLAG; key_start= FALSE; key_part_info++; } @@ -8695,12 +8702,27 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, { st_select_lex* first= derived->first_select(); uint select_list_items= first->get_item_list()->elements; + /* + If our key parts match the select list, we know that there will be + one record per key + */ if (key_parts == select_list_items) { if ((!first->is_part_of_union() && (first->options & SELECT_DISTINCT)) || derived->check_distinct_in_union()) keyinfo->rec_per_key[key_parts - 1]= 1; } + /* + If we have only one select in our unit and + we have a window function in our select + */ + if (!first->next_select() && first->with_sum_func) + { + est_derived_window_fn_cardinality(first, + &keyinfo->rec_per_key[key_parts-1], + reg_field, + key_parts); + } } set_if_bigger(s->max_key_length, keyinfo->key_length);