Skip to content

Commit f982d10

Browse files
committed
Fixed the following problem:
Temporary tables created for recursive CTE were instantiated at the prepare phase. As a result these temporary tables missed indexes for look-ups and optimizer could not use them.
1 parent 8c6a9aa commit f982d10

File tree

11 files changed

+184
-55
lines changed

11 files changed

+184
-55
lines changed

mysql-test/r/cte_recursive.result

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ select t2.a from t1,t2 where t1.a+1=t2.a
113113
)
114114
select * from t1;
115115
id select_type table type possible_keys key key_len ref rows Extra
116-
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 30
116+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
117117
2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where
118118
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 5
119119
3 UNCACHEABLE UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
@@ -595,18 +595,18 @@ select h.name, h.dob, w.name, w.dob
595595
from ancestor_couple_ids c, coupled_ancestors h, coupled_ancestors w
596596
where c.h_id = h.id and c.w_id= w.id;
597597
id select_type table type possible_keys key key_len ref rows filtered Extra
598-
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 36 100.00
599-
1 PRIMARY <derived3> ALL NULL NULL NULL NULL 468 100.00 Using where; Using join buffer (flat, BNL join)
600-
1 PRIMARY <derived3> ALL NULL NULL NULL NULL 468 100.00 Using where; Using join buffer (incremental, BNL join)
598+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00 Using where
599+
1 PRIMARY <derived3> ref key0 key0 5 c.h_id 2 100.00
600+
1 PRIMARY <derived3> ref key0 key0 5 c.w_id 2 100.00
601601
3 SUBQUERY folks ALL NULL NULL NULL NULL 12 100.00 Using where
602-
4 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00
603-
4 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 36 100.00 Using where; Using join buffer (flat, BNL join)
602+
4 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
603+
4 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
604604
5 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
605605
5 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
606606
NULL UNION RESULT <union3,4,5> ALL NULL NULL NULL NULL NULL NULL
607-
2 UNCACHEABLE SUBQUERY <derived3> ALL NULL NULL NULL NULL 36 100.00 Using where
607+
2 UNCACHEABLE SUBQUERY <derived3> ALL NULL NULL NULL NULL 12 100.00 Using where
608608
Warnings:
609-
Note 1003 with recursive ancestor_couple_ids as (select `a`.`father` AS `h_id`,`a`.`mother` AS `w_id` from `coupled_ancestors` `a` where ((`a`.`father` is not null) and (`a`.`mother` is not null)))coupled_ancestors as (select `test`.`folks`.`id` AS `id`,`test`.`folks`.`name` AS `name`,`test`.`folks`.`dob` AS `dob`,`test`.`folks`.`father` AS `father`,`test`.`folks`.`mother` AS `mother` from `test`.`folks` where (`test`.`folks`.`name` = 'Me') union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `fa` where (`fa`.`h_id` = `test`.`p`.`id`) union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `ma` where (`test`.`p`.`id` = `ma`.`w_id`)), select `h`.`name` AS `name`,`h`.`dob` AS `dob`,`w`.`name` AS `name`,`w`.`dob` AS `dob` from `ancestor_couple_ids` `c` join `coupled_ancestors` `h` join `coupled_ancestors` `w` where ((`h`.`id` = `c`.`h_id`) and (`w`.`id` = `c`.`w_id`))
609+
Note 1003 with recursive ancestor_couple_ids as (select `a`.`father` AS `h_id`,`a`.`mother` AS `w_id` from `coupled_ancestors` `a` where ((`a`.`father` is not null) and (`a`.`mother` is not null)))coupled_ancestors as (select `test`.`folks`.`id` AS `id`,`test`.`folks`.`name` AS `name`,`test`.`folks`.`dob` AS `dob`,`test`.`folks`.`father` AS `father`,`test`.`folks`.`mother` AS `mother` from `test`.`folks` where (`test`.`folks`.`name` = 'Me') union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `fa` where (`test`.`p`.`id` = `fa`.`h_id`) union all select `test`.`p`.`id` AS `id`,`test`.`p`.`name` AS `name`,`test`.`p`.`dob` AS `dob`,`test`.`p`.`father` AS `father`,`test`.`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestor_couple_ids` `ma` where (`test`.`p`.`id` = `ma`.`w_id`)), select `h`.`name` AS `name`,`h`.`dob` AS `dob`,`w`.`name` AS `name`,`w`.`dob` AS `dob` from `ancestor_couple_ids` `c` join `coupled_ancestors` `h` join `coupled_ancestors` `w` where ((`h`.`id` = `c`.`h_id`) and (`w`.`id` = `c`.`w_id`))
610610
with recursive
611611
ancestor_couple_ids(h_id, w_id)
612612
as
@@ -779,7 +779,7 @@ where p.id = a.father or p.id = a.mother
779779
)
780780
select * from ancestors;
781781
id select_type table type possible_keys key key_len ref rows filtered Extra
782-
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 156 100.00
782+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 12 100.00
783783
2 SUBQUERY folks ALL NULL NULL NULL NULL 12 100.00 Using where
784784
3 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00
785785
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
@@ -809,9 +809,9 @@ id name dob father mother
809809
20 Dad 1970-02-02 10 9
810810
30 Mom 1975-03-03 8 7
811811
10 Grandpa Bill 1940-04-05 NULL NULL
812-
8 Grandpa Ben 1940-10-21 NULL NULL
813812
9 Grandma Ann 1941-10-15 NULL NULL
814813
7 Grandma Sally 1943-08-23 NULL 6
814+
8 Grandpa Ben 1940-10-21 NULL NULL
815815
6 Grandgrandma Martha 1923-05-17 NULL NULL
816816
with recursive
817817
ancestors
@@ -896,9 +896,9 @@ generation name
896896
1 Dad
897897
1 Mom
898898
2 Grandpa Bill
899-
2 Grandpa Ben
900899
2 Grandma Ann
901900
2 Grandma Sally
901+
2 Grandpa Ben
902902
3 Grandgrandma Martha
903903
set standards_compliant_cte=1;
904904
with recursive
@@ -951,9 +951,9 @@ id name dob father mother
951951
20 Dad 1970-02-02 10 9
952952
30 Mom 1975-03-03 8 7
953953
10 Grandpa Bill 1940-04-05 NULL NULL
954-
8 Grandpa Ben 1940-10-21 NULL NULL
955954
9 Grandma Ann 1941-10-15 NULL NULL
956955
7 Grandma Sally 1943-08-23 NULL 6
956+
8 Grandpa Ben 1940-10-21 NULL NULL
957957
with recursive
958958
ancestor_ids (id)
959959
as
@@ -998,10 +998,10 @@ id name dob father mother
998998
20 Dad 1970-02-02 10 9
999999
30 Mom 1975-03-03 8 7
10001000
10 Grandpa Bill 1940-04-05 NULL NULL
1001-
8 Grandpa Ben 1940-10-21 NULL NULL
1002-
25 Uncle Jim 1968-11-18 8 7
10031001
9 Grandma Ann 1941-10-15 NULL NULL
1002+
25 Uncle Jim 1968-11-18 8 7
10041003
7 Grandma Sally 1943-08-23 NULL 6
1004+
8 Grandpa Ben 1940-10-21 NULL NULL
10051005
6 Grandgrandma Martha 1923-05-17 NULL NULL
10061006
27 Auntie Melinda 1971-03-29 NULL NULL
10071007
with recursive
@@ -1029,9 +1029,9 @@ generation name
10291029
1 Dad
10301030
1 Mom
10311031
2 Grandpa Bill
1032-
2 Grandpa Ben
10331032
2 Grandma Ann
10341033
2 Grandma Sally
1034+
2 Grandpa Ben
10351035
3 Grandgrandma Martha
10361036
with recursive
10371037
ancestor_ids (id, generation)
@@ -1112,7 +1112,60 @@ generation name
11121112
1 Dad
11131113
1 Mom
11141114
2 Grandpa Bill
1115-
2 Grandpa Ben
11161115
2 Grandma Ann
11171116
2 Grandma Sally
1117+
2 Grandpa Ben
1118+
alter table folks add primary key (id);
1119+
explain
1120+
with recursive
1121+
ancestors
1122+
as
1123+
(
1124+
select *
1125+
from folks
1126+
where name = 'Me'
1127+
union
1128+
select p.*
1129+
from folks as p, ancestors as fa
1130+
where p.id = fa.father
1131+
union
1132+
select p.*
1133+
from folks as p, ancestors as ma
1134+
where p.id = ma.mother
1135+
)
1136+
select * from ancestors;
1137+
id select_type table type possible_keys key key_len ref rows Extra
1138+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 12
1139+
2 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where
1140+
3 UNCACHEABLE UNION p ALL PRIMARY NULL NULL NULL 12
1141+
3 UNCACHEABLE UNION <derived2> ref key0 key0 5 test.p.id 2
1142+
4 UNCACHEABLE UNION p ALL PRIMARY NULL NULL NULL 12
1143+
4 UNCACHEABLE UNION <derived2> ref key0 key0 5 test.p.id 2
1144+
NULL UNION RESULT <union2,3,4> ALL NULL NULL NULL NULL NULL
1145+
with recursive
1146+
ancestors
1147+
as
1148+
(
1149+
select *
1150+
from folks
1151+
where name = 'Me'
1152+
union
1153+
select p.*
1154+
from folks as p, ancestors as fa
1155+
where p.id = fa.father
1156+
union
1157+
select p.*
1158+
from folks as p, ancestors as ma
1159+
where p.id = ma.mother
1160+
)
1161+
select * from ancestors;
1162+
id name dob father mother
1163+
100 Me 2000-01-01 20 30
1164+
20 Dad 1970-02-02 10 9
1165+
30 Mom 1975-03-03 8 7
1166+
10 Grandpa Bill 1940-04-05 NULL NULL
1167+
8 Grandpa Ben 1940-10-21 NULL NULL
1168+
9 Grandma Ann 1941-10-15 NULL NULL
1169+
7 Grandma Sally 1943-08-23 NULL 6
1170+
6 Grandgrandma Martha 1923-05-17 NULL NULL
11181171
drop table folks;

mysql-test/t/cte_recursive.test

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,5 +937,45 @@ as
937937
)
938938
select * from ancestors;
939939

940+
alter table folks add primary key (id);
941+
942+
explain
943+
with recursive
944+
ancestors
945+
as
946+
(
947+
select *
948+
from folks
949+
where name = 'Me'
950+
union
951+
select p.*
952+
from folks as p, ancestors as fa
953+
where p.id = fa.father
954+
union
955+
select p.*
956+
from folks as p, ancestors as ma
957+
where p.id = ma.mother
958+
)
959+
select * from ancestors;
960+
961+
with recursive
962+
ancestors
963+
as
964+
(
965+
select *
966+
from folks
967+
where name = 'Me'
968+
union
969+
select p.*
970+
from folks as p, ancestors as fa
971+
where p.id = fa.father
972+
union
973+
select p.*
974+
from folks as p, ancestors as ma
975+
where p.id = ma.mother
976+
)
977+
select * from ancestors;
978+
979+
940980
drop table folks;
941981

sql/sql_cte.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "sql_cte.h"
44
#include "sql_view.h" // for make_valid_column_names
55
#include "sql_parse.h"
6+
#include "sql_select.h"
67

78

89
/**
@@ -956,3 +957,20 @@ void With_element::print(String *str, enum_query_type query_type)
956957
}
957958

958959

960+
bool With_element::instantiate_tmp_tables()
961+
{
962+
List_iterator_fast<TABLE> li(rec_result->rec_tables);
963+
TABLE *rec_table;
964+
while ((rec_table= li++))
965+
{
966+
if (!rec_table->is_created() &&
967+
instantiate_tmp_table(rec_table,
968+
rec_result->tmp_table_param.keyinfo,
969+
rec_result->tmp_table_param.start_recinfo,
970+
&rec_result->tmp_table_param.recinfo,
971+
0))
972+
return true;
973+
}
974+
return false;
975+
}
976+

sql/sql_cte.h

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
class select_union;
77
struct st_unit_ctxt_elem;
88

9-
/**
10-
@class With_clause
11-
@brief Set of with_elements
129

13-
It has a reference to the first with element from this with clause.
14-
This reference allows to navigate through all the elements of the with clause.
15-
It contains a reference to the unit to which this with clause is attached.
16-
It also contains a flag saying whether this with clause was specified as recursive.
17-
*/
10+
/**
11+
@class With_element
12+
@brief Definition of a CTE table
13+
14+
It contains a reference to the name of the table introduced by this with element,
15+
and a reference to the unit that specificies this table. Also it contains
16+
a reference to the with clause to which this element belongs to.
17+
*/
1818

1919
class With_element : public Sql_alloc
2020
{
@@ -184,18 +184,20 @@ class With_element : public Sql_alloc
184184

185185
void set_result_table(TABLE *tab) { result_table= tab; }
186186

187+
bool instantiate_tmp_tables();
188+
187189
friend class With_clause;
188190
};
189191

190-
191192
/**
192-
@class With_element
193-
@brief Definition of a CTE table
194-
195-
It contains a reference to the name of the table introduced by this with element,
196-
and a reference to the unit that specificies this table. Also it contains
197-
a reference to the with clause to which this element belongs to.
198-
*/
193+
@class With_clause
194+
@brief Set of with_elements
195+
196+
It has a reference to the first with element from this with clause.
197+
This reference allows to navigate through all the elements of the with clause.
198+
It contains a reference to the unit to which this with clause is attached.
199+
It also contains a flag saying whether this with clause was specified as recursive.
200+
*/
199201

200202
class With_clause : public Sql_alloc
201203
{

sql/sql_derived.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
653653
(first_select->options |
654654
thd->variables.option_bits |
655655
TMP_TABLE_ALL_COLUMNS),
656-
derived->alias, FALSE, TRUE);
656+
derived->alias, FALSE, FALSE);
657657
thd->create_tmp_table_for_derived= FALSE;
658658

659659
if (!res && !derived->table)
@@ -681,7 +681,9 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
681681
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
682682
{
683683
sl->context.outer_context= 0;
684-
if (!derived->is_with_table_recursive_reference())
684+
if (!derived->is_with_table_recursive_reference() ||
685+
(!derived->with->with_anchor &&
686+
!derived->with->is_with_prepared_anchor()))
685687
{
686688
// Prepare underlying views/DT first.
687689
if ((res= sl->handle_derived(lex, DT_PREPARE)))
@@ -928,7 +930,8 @@ bool TABLE_LIST::fill_recursive(THD *thd)
928930
rc= unit->exec_recursive(false);
929931
else
930932
{
931-
while(!with->all_are_stabilized() && !rc)
933+
rc= with->instantiate_tmp_tables();
934+
while(!rc && !with->all_are_stabilized())
932935
{
933936
rc= unit->exec_recursive(true);
934937
}

sql/sql_lex.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,7 @@ void st_select_lex_unit::init_query()
20652065
offset_limit_cnt= 0;
20662066
union_distinct= 0;
20672067
prepared= optimized= executed= 0;
2068+
optimize_started= 0;
20682069
item= 0;
20692070
union_result= 0;
20702071
table= 0;
@@ -4393,6 +4394,19 @@ void SELECT_LEX::increase_derived_records(ha_rows records)
43934394
SELECT_LEX_UNIT *unit= master_unit();
43944395
DBUG_ASSERT(unit->derived);
43954396

4397+
if (unit->with_element && unit->with_element->is_recursive)
4398+
{
4399+
st_select_lex *first_recursive= unit->with_element->first_recursive;
4400+
st_select_lex *sl= unit->first_select();
4401+
for ( ; sl != first_recursive; sl= sl->next_select())
4402+
{
4403+
if (sl == this)
4404+
break;
4405+
}
4406+
if (sl == first_recursive)
4407+
return;
4408+
}
4409+
43964410
select_union *result= (select_union*)unit->result;
43974411
result->records+= records;
43984412
}

sql/sql_lex.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ class st_select_lex_unit: public st_select_lex_node {
611611
executed, // already executed
612612
cleaned;
613613

614+
bool optimize_started;
615+
614616
// list of fields which points to temporary table for union
615617
List<Item> item_list;
616618
/*

sql/sql_select.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,6 @@ static COND *optimize_cond(JOIN *join, COND *conds,
165165
int flags= 0);
166166
bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
167167
static int do_select(JOIN *join, Procedure *procedure);
168-
static bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
169-
MARIA_COLUMNDEF *start_recinfo,
170-
MARIA_COLUMNDEF **recinfo,
171-
ulonglong options);
172168

173169
static enum_nested_loop_state evaluate_join_record(JOIN *, JOIN_TAB *, int);
174170
static enum_nested_loop_state
@@ -17915,7 +17911,6 @@ int rr_sequential_and_unpack(READ_RECORD *info)
1791517911
TRUE - Error
1791617912
*/
1791717913

17918-
static
1791917914
bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
1792017915
MARIA_COLUMNDEF *start_recinfo,
1792117916
MARIA_COLUMNDEF **recinfo,

sql/sql_select.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,6 +2235,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
22352235
TMP_ENGINE_COLUMNDEF *start_recinfo,
22362236
TMP_ENGINE_COLUMNDEF **recinfo,
22372237
ulonglong options);
2238+
bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
2239+
MARIA_COLUMNDEF *start_recinfo,
2240+
MARIA_COLUMNDEF **recinfo,
2241+
ulonglong options);
22382242
bool open_tmp_table(TABLE *table);
22392243
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
22402244
double prev_record_reads(POSITION *positions, uint idx, table_map found_ref);

0 commit comments

Comments
 (0)