Skip to content

Commit 2d88d09

Browse files
committed
MDEV-38877: Unnecessary filesort on derived table materialization
Fixes unnecessary filesort on derived tables when ordered/grouped by a field in the key. The data is inherently sorted, wrapping the result set in a filesort is redundant.
1 parent ce880db commit 2d88d09

7 files changed

Lines changed: 99 additions & 6 deletions

File tree

mysql-test/main/derived_cond_pushdown.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21164,7 +21164,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
2116421164
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7 100.00
2116521165
2 DERIVED <derived4> ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
2116621166
2 DERIVED a2 eq_ref PRIMARY PRIMARY 4 a1.f 1 100.00 Using index
21167-
4 DERIVED t1 index PRIMARY PRIMARY 4 NULL 7 100.00 Using index; Using temporary; Using filesort
21167+
4 DERIVED t1 index PRIMARY PRIMARY 4 NULL 7 100.00 Using index
2116821168
Warnings:
2116921169
Note 1003 /* select#1 */ select `s`.`f` AS `f`,`s`.`c` AS `c` from (/* select#2 */ select straight_join `a2`.`f` AS `f`,count(0) AS `c` from (/* select#4 */ select `test`.`t1`.`f` AS `f`,count(0) AS `c` from `test`.`t1` group by `test`.`t1`.`f`) `a1` join `test`.`t1` `a2` where `a2`.`f` = `a1`.`f` group by `a2`.`f`) `s`
2117021170
SELECT * FROM ( SELECT STRAIGHT_JOIN f, COUNT(*) as c FROM v1 GROUP BY f ) AS s;

mysql-test/main/derived_split_innodb.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ id select_type table type possible_keys key key_len ref rows Extra
131131
1 PRIMARY t const f2 NULL NULL NULL 0 Impossible ON condition
132132
1 PRIMARY <derived2> const key0,key1 NULL NULL NULL 0 Impossible ON condition
133133
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
134-
2 DERIVED t2 ALL PRIMARY NULL NULL NULL 3 Using temporary; Using filesort
134+
2 DERIVED t2 index PRIMARY PRIMARY 4 NULL 3
135135
set statement optimizer_switch='split_materialized=off' for explain select t.f2
136136
from t1
137137
left join
@@ -998,7 +998,7 @@ id select_type table type possible_keys key key_len ref rows Extra
998998
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
999999
1 PRIMARY t2 ref a a 5 test.t1.a 1 Using where; Using index
10001000
1 PRIMARY <derived2> ref key0 key0 5 func 1 Using where
1001-
2 DERIVED t10 index grp_id grp_id 5 NULL 10000 Using index; Using temporary; Using filesort
1001+
2 DERIVED t10 index grp_id grp_id 5 NULL 10000 Using index
10021002
drop table t1,t2, t10;
10031003
drop view v1;
10041004
#

mysql-test/main/mdev-38877.result

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#
2+
# MDEV-38877: Unnecessary filesort on derived table materialization
3+
# when derived table is inherently sorted by the grouping columns
4+
#
5+
CREATE TABLE t1 (
6+
groups_20 int NOT NULL,
7+
groups_20_2 int NOT NULL,
8+
b int,
9+
PRIMARY KEY (groups_20, groups_20_2)
10+
);
11+
CREATE TABLE t2 (a int, b int, index(a));
12+
INSERT INTO t1 SELECT seq/1000, seq+1, seq from seq_1_to_10000;
13+
INSERT INTO t2 SELECT seq, seq from seq_1_to_1000;
14+
ANALYZE TABLE t1, t2;
15+
EXPLAIN
16+
SELECT
17+
a,
18+
SUM(b)
19+
FROM (
20+
SELECT
21+
groups_20
22+
FROM t1
23+
GROUP BY groups_20
24+
HAVING COUNT(*) != 1000
25+
) DT
26+
JOIN t2 ON a = groups_20
27+
GROUP BY a;
28+
id select_type table type possible_keys key key_len ref rows Extra
29+
1 PRIMARY t2 ALL a NULL NULL NULL 1000 Using where; Using temporary; Using filesort
30+
1 PRIMARY <derived2> ref key0 key0 4 test.t2.a 1
31+
2 DERIVED t1 index PRIMARY PRIMARY 8 NULL 10000 Using index
32+
DROP TABLE t1, t2;

mysql-test/main/mdev-38877.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--source include/have_sequence.inc
2+
3+
--echo #
4+
--echo # MDEV-38877: Unnecessary filesort on derived table materialization
5+
--echo # when derived table is inherently sorted by the grouping columns
6+
--echo #
7+
8+
CREATE TABLE t1 (
9+
groups_20 int NOT NULL,
10+
groups_20_2 int NOT NULL,
11+
b int,
12+
PRIMARY KEY (groups_20, groups_20_2)
13+
);
14+
15+
CREATE TABLE t2 (a int, b int, index(a));
16+
17+
--disable_result_log
18+
INSERT INTO t1 SELECT seq/1000, seq+1, seq from seq_1_to_10000;
19+
20+
INSERT INTO t2 SELECT seq, seq from seq_1_to_1000;
21+
22+
ANALYZE TABLE t1, t2;
23+
--enable_result_log
24+
25+
EXPLAIN
26+
SELECT
27+
a,
28+
SUM(b)
29+
FROM (
30+
SELECT
31+
groups_20
32+
FROM t1
33+
GROUP BY groups_20
34+
HAVING COUNT(*) != 1000
35+
) DT
36+
JOIN t2 ON a = groups_20
37+
GROUP BY a;
38+
39+
DROP TABLE t1, t2;

mysql-test/main/opt_hints_split_materialized.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -763,15 +763,15 @@ one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a;
763763
id select_type table type possible_keys key key_len ref rows Extra
764764
1 PRIMARY T1 ALL NULL NULL NULL NULL 1000 Using where
765765
1 PRIMARY <derived2> ref key0 key0 5 test.T1.a 1
766-
2 DERIVED t1000 index grp grp 5 NULL 1000 Using index; Using temporary; Using filesort
766+
2 DERIVED t1000 index grp grp 5 NULL 1000 Using index
767767
explain
768768
select /*+ SPLIT_MATERIALIZED(TBL) */ *
769769
from
770770
one_k T1, (select grp, count(*) from t1000 group by grp) TBL where TBL.grp=T1.a;
771771
id select_type table type possible_keys key key_len ref rows Extra
772772
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 100
773773
1 PRIMARY T1 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join)
774-
2 DERIVED t1000 index grp grp 5 NULL 1000 Using index; Using temporary; Using filesort
774+
2 DERIVED t1000 index grp grp 5 NULL 1000 Using index
775775
drop table one_k, t1000;
776776
#
777777
# end case 4

sql/sql_select.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32727,9 +32727,24 @@ void JOIN::save_query_plan(Join_plan_state *save_to)
3272732727

3272832728
for (uint i= 0; i < table_count; i++)
3272932729
{
32730+
uint num_keys= join_tab[i].table->s->keys;
3273032731
save_to->join_tab_keyuse[i]= join_tab[i].keyuse;
3273132732
join_tab[i].keyuse= NULL;
3273232733
save_to->join_tab_checked_keys[i]= join_tab[i].checked_keys;
32734+
if (num_keys > 0)
32735+
{
32736+
if (!save_to->const_key_parts[i])
32737+
{
32738+
save_to->const_key_parts[i]=
32739+
(key_part_map *) thd->calloc(sizeof(key_part_map) * num_keys);
32740+
}
32741+
32742+
if (save_to->const_key_parts[i])
32743+
{
32744+
memcpy(save_to->const_key_parts[i], join_tab[i].table->const_key_parts,
32745+
sizeof(key_part_map) * num_keys);
32746+
}
32747+
}
3273332748
join_tab[i].checked_keys.clear_all();
3273432749
}
3273532750
memcpy((uchar*) save_to->best_positions, (uchar*) best_positions,
@@ -32777,6 +32792,9 @@ void JOIN::restore_query_plan(Join_plan_state *restore_from)
3277732792
{
3277832793
join_tab[i].keyuse= restore_from->join_tab_keyuse[i];
3277932794
join_tab[i].checked_keys= restore_from->join_tab_checked_keys[i];
32795+
memcpy(join_tab[i].table->const_key_parts,
32796+
restore_from->const_key_parts[i],
32797+
sizeof(key_part_map) * join_tab[i].table->s->keys);
3278032798
}
3278132799

3278232800
memcpy((uchar*) best_positions, (uchar*) restore_from->best_positions,

sql/sql_select.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,8 @@ class JOIN :public Sql_alloc
12351235
KEYUSE **join_tab_keyuse;
12361236
/* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */
12371237
key_map *join_tab_checked_keys;
1238+
/* Copies of TABLE::key_part_map for each JOIN_TAB->TABLE */
1239+
key_part_map **const_key_parts;
12381240
SJ_MATERIALIZATION_INFO **sj_mat_info;
12391241
my_bool error;
12401242
public:
@@ -1244,7 +1246,7 @@ class JOIN :public Sql_alloc
12441246
keyuse.buffer= NULL;
12451247
keyuse.malloc_flags= 0;
12461248
best_positions= 0; /* To detect errors */
1247-
error= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
1249+
error= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL),
12481250
&best_positions,
12491251
sizeof(*best_positions) * (tables + 1),
12501252
&join_tab_keyuse,
@@ -1253,6 +1255,8 @@ class JOIN :public Sql_alloc
12531255
sizeof(*join_tab_checked_keys) * tables,
12541256
&sj_mat_info,
12551257
sizeof(sj_mat_info) * tables,
1258+
&const_key_parts,
1259+
sizeof(*const_key_parts) * tables,
12561260
NullS) == 0;
12571261
}
12581262
Join_plan_state(JOIN *join);

0 commit comments

Comments
 (0)