Skip to content

Commit a2f245e

Browse files
committed
MDEV-10372: EXPLAIN fixes for recursive CTEs, including FORMAT=JSON
- Tabular EXPLAIN now prints "RECURSIVE UNION". - There is a basic implementation of EXPLAIN FORMAT=JSON. - it produces "recursive_union" JSON struct - No other details or ANALYZE support, yet.
1 parent e1c92a6 commit a2f245e

File tree

8 files changed

+493
-17
lines changed

8 files changed

+493
-17
lines changed

mysql-test/r/cte_recursive.result

Lines changed: 354 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ select * from t1;
115115
id select_type table type possible_keys key key_len ref rows Extra
116116
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
117117
2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where
118-
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 5
119-
3 UNCACHEABLE UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
118+
3 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 5
119+
3 RECURSIVE UNION t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
120120
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
121121
# just WITH : types of t1 columns are determined by all parts of union
122122
create view v1 as
@@ -599,10 +599,10 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
599599
1 PRIMARY <derived3> ref key0 key0 5 c.h_id 2 100.00
600600
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 <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)
604-
5 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
605-
5 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
602+
4 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
603+
4 RECURSIVE UNION p ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
604+
5 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
605+
5 RECURSIVE 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
607607
2 UNCACHEABLE SUBQUERY <derived3> ALL NULL NULL NULL NULL 12 100.00 Using where
608608
Warnings:
@@ -781,8 +781,8 @@ select * from ancestors;
781781
id select_type table type possible_keys key key_len ref rows filtered Extra
782782
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
784-
3 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00
785-
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
784+
3 RECURSIVE UNION p ALL NULL NULL NULL NULL 12 100.00
785+
3 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
786786
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
787787
Warnings:
788788
Note 1003 with recursive 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') and (`test`.`folks`.`dob` = DATE'2000-01-01')) union select `p`.`id` AS `id`,`p`.`name` AS `name`,`p`.`dob` AS `dob`,`p`.`father` AS `father`,`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestors` `a` where ((`a`.`father` = `p`.`id`) or (`a`.`mother` = `p`.`id`)))select `ancestors`.`id` AS `id`,`ancestors`.`name` AS `name`,`ancestors`.`dob` AS `dob`,`ancestors`.`father` AS `father`,`ancestors`.`mother` AS `mother` from `ancestors`
@@ -1137,10 +1137,10 @@ select * from ancestors;
11371137
id select_type table type possible_keys key key_len ref rows Extra
11381138
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 12
11391139
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
1140+
3 RECURSIVE UNION p ALL PRIMARY NULL NULL NULL 12
1141+
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.p.id 2
1142+
4 RECURSIVE UNION p ALL PRIMARY NULL NULL NULL 12
1143+
4 RECURSIVE UNION <derived2> ref key0 key0 5 test.p.id 2
11441144
NULL UNION RESULT <union2,3,4> ALL NULL NULL NULL NULL NULL
11451145
with recursive
11461146
ancestors
@@ -1168,4 +1168,346 @@ id name dob father mother
11681168
9 Grandma Ann 1941-10-15 NULL NULL
11691169
7 Grandma Sally 1943-08-23 NULL 6
11701170
6 Grandgrandma Martha 1923-05-17 NULL NULL
1171+
#
1172+
# EXPLAIN FORMAT=JSON on a query where one recursive CTE uses another:
1173+
#
1174+
explain
1175+
with recursive
1176+
prev_gen
1177+
as
1178+
(
1179+
select folks.*
1180+
from folks, prev_gen
1181+
where folks.id=prev_gen.father or folks.id=prev_gen.mother
1182+
union
1183+
select *
1184+
from folks
1185+
where name='Me'
1186+
),
1187+
ancestors
1188+
as
1189+
(
1190+
select *
1191+
from folks
1192+
where name='Me'
1193+
union
1194+
select *
1195+
from ancestors
1196+
union
1197+
select *
1198+
from prev_gen
1199+
)
1200+
select ancestors.name, ancestors.dob from ancestors;
1201+
id select_type table type possible_keys key key_len ref rows Extra
1202+
1 PRIMARY <derived4> ALL NULL NULL NULL NULL 24
1203+
4 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where
1204+
6 RECURSIVE UNION <derived3> ALL NULL NULL NULL NULL 12
1205+
5 RECURSIVE UNION <derived4> ALL NULL NULL NULL NULL 24
1206+
NULL UNION RESULT <union4,6,5> ALL NULL NULL NULL NULL NULL
1207+
3 SUBQUERY folks ALL NULL NULL NULL NULL 12 Using where
1208+
2 RECURSIVE UNION folks ALL PRIMARY NULL NULL NULL 12
1209+
2 RECURSIVE UNION <derived3> ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
1210+
NULL UNION RESULT <union3,2> ALL NULL NULL NULL NULL NULL
1211+
explain FORMAT=JSON
1212+
with recursive
1213+
prev_gen
1214+
as
1215+
(
1216+
select folks.*
1217+
from folks, prev_gen
1218+
where folks.id=prev_gen.father or folks.id=prev_gen.mother
1219+
union
1220+
select *
1221+
from folks
1222+
where name='Me'
1223+
),
1224+
ancestors
1225+
as
1226+
(
1227+
select *
1228+
from folks
1229+
where name='Me2'
1230+
union
1231+
select *
1232+
from ancestors where id < 234
1233+
union
1234+
select *
1235+
from prev_gen where id < 345
1236+
)
1237+
select ancestors.name, ancestors.dob from ancestors;
1238+
EXPLAIN
1239+
{
1240+
"query_block": {
1241+
"select_id": 1,
1242+
"table": {
1243+
"table_name": "<derived4>",
1244+
"access_type": "ALL",
1245+
"rows": 24,
1246+
"filtered": 100,
1247+
"materialized": {
1248+
"query_block": {
1249+
"recursive_union": {
1250+
"table_name": "<union4,6,5>",
1251+
"access_type": "ALL",
1252+
"query_specifications": [
1253+
{
1254+
"query_block": {
1255+
"select_id": 4,
1256+
"table": {
1257+
"table_name": "folks",
1258+
"access_type": "ALL",
1259+
"rows": 12,
1260+
"filtered": 100,
1261+
"attached_condition": "(folks.`name` = 'Me2')"
1262+
}
1263+
}
1264+
},
1265+
{
1266+
"query_block": {
1267+
"select_id": 6,
1268+
"table": {
1269+
"table_name": "<derived3>",
1270+
"access_type": "ALL",
1271+
"rows": 12,
1272+
"filtered": 100,
1273+
"attached_condition": "(prev_gen.`id` < 345)",
1274+
"materialized": {
1275+
"query_block": {
1276+
"recursive_union": {
1277+
"table_name": "<union3,2>",
1278+
"access_type": "ALL",
1279+
"query_specifications": [
1280+
{
1281+
"query_block": {
1282+
"select_id": 3,
1283+
"table": {
1284+
"table_name": "folks",
1285+
"access_type": "ALL",
1286+
"rows": 12,
1287+
"filtered": 100,
1288+
"attached_condition": "(folks.`name` = 'Me')"
1289+
}
1290+
}
1291+
},
1292+
{
1293+
"query_block": {
1294+
"select_id": 2,
1295+
"table": {
1296+
"table_name": "folks",
1297+
"access_type": "ALL",
1298+
"possible_keys": ["PRIMARY"],
1299+
"rows": 12,
1300+
"filtered": 100
1301+
},
1302+
"block-nl-join": {
1303+
"table": {
1304+
"table_name": "<derived3>",
1305+
"access_type": "ALL",
1306+
"rows": 12,
1307+
"filtered": 100
1308+
},
1309+
"buffer_type": "flat",
1310+
"buffer_size": "256Kb",
1311+
"join_type": "BNL",
1312+
"attached_condition": "((prev_gen.father = folks.`id`) or (prev_gen.mother = folks.`id`))"
1313+
}
1314+
}
1315+
}
1316+
]
1317+
}
1318+
}
1319+
}
1320+
}
1321+
}
1322+
},
1323+
{
1324+
"query_block": {
1325+
"select_id": 5,
1326+
"table": {
1327+
"table_name": "<derived4>",
1328+
"access_type": "ALL",
1329+
"rows": 24,
1330+
"filtered": 100,
1331+
"attached_condition": "(ancestors.`id` < 234)"
1332+
}
1333+
}
1334+
}
1335+
]
1336+
}
1337+
}
1338+
}
1339+
}
1340+
}
1341+
}
1342+
#
1343+
explain format=json
1344+
with recursive
1345+
ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
1346+
w_id, w_name, w_dob, w_father, w_mother)
1347+
as
1348+
(
1349+
select h.*, w.*
1350+
from folks h, folks w, coupled_ancestors a
1351+
where a.father = h.id AND a.mother = w.id
1352+
union
1353+
select h.*, w.*
1354+
from folks v, folks h, folks w
1355+
where v.name = 'Me' and
1356+
(v.father = h.id AND v.mother= w.id)
1357+
),
1358+
coupled_ancestors (id, name, dob, father, mother)
1359+
as
1360+
(
1361+
select h_id, h_name, h_dob, h_father, h_mother
1362+
from ancestor_couples
1363+
union all
1364+
select w_id, w_name, w_dob, w_father, w_mother
1365+
from ancestor_couples
1366+
)
1367+
select h_name, h_dob, w_name, w_dob
1368+
from ancestor_couples;
1369+
EXPLAIN
1370+
{
1371+
"query_block": {
1372+
"select_id": 1,
1373+
"table": {
1374+
"table_name": "<derived3>",
1375+
"access_type": "ALL",
1376+
"rows": 12,
1377+
"filtered": 100,
1378+
"materialized": {
1379+
"query_block": {
1380+
"recursive_union": {
1381+
"table_name": "<union3,2>",
1382+
"access_type": "ALL",
1383+
"query_specifications": [
1384+
{
1385+
"query_block": {
1386+
"select_id": 3,
1387+
"table": {
1388+
"table_name": "v",
1389+
"access_type": "ALL",
1390+
"rows": 12,
1391+
"filtered": 100,
1392+
"attached_condition": "((v.`name` = 'Me') and (v.father is not null) and (v.mother is not null))"
1393+
},
1394+
"table": {
1395+
"table_name": "h",
1396+
"access_type": "eq_ref",
1397+
"possible_keys": ["PRIMARY"],
1398+
"key": "PRIMARY",
1399+
"key_length": "4",
1400+
"used_key_parts": ["id"],
1401+
"ref": ["test.v.father"],
1402+
"rows": 1,
1403+
"filtered": 100
1404+
},
1405+
"table": {
1406+
"table_name": "w",
1407+
"access_type": "eq_ref",
1408+
"possible_keys": ["PRIMARY"],
1409+
"key": "PRIMARY",
1410+
"key_length": "4",
1411+
"used_key_parts": ["id"],
1412+
"ref": ["test.v.mother"],
1413+
"rows": 1,
1414+
"filtered": 100
1415+
}
1416+
}
1417+
},
1418+
{
1419+
"query_block": {
1420+
"select_id": 2,
1421+
"table": {
1422+
"table_name": "<derived4>",
1423+
"access_type": "ALL",
1424+
"rows": 2,
1425+
"filtered": 100,
1426+
"attached_condition": "((a.father is not null) and (a.mother is not null))"
1427+
},
1428+
"table": {
1429+
"table_name": "h",
1430+
"access_type": "eq_ref",
1431+
"possible_keys": ["PRIMARY"],
1432+
"key": "PRIMARY",
1433+
"key_length": "4",
1434+
"used_key_parts": ["id"],
1435+
"ref": ["a.father"],
1436+
"rows": 1,
1437+
"filtered": 100
1438+
},
1439+
"table": {
1440+
"table_name": "w",
1441+
"access_type": "eq_ref",
1442+
"possible_keys": ["PRIMARY"],
1443+
"key": "PRIMARY",
1444+
"key_length": "4",
1445+
"used_key_parts": ["id"],
1446+
"ref": ["a.mother"],
1447+
"rows": 1,
1448+
"filtered": 100
1449+
}
1450+
}
1451+
}
1452+
]
1453+
}
1454+
}
1455+
}
1456+
}
1457+
}
1458+
}
11711459
drop table folks;
1460+
#
1461+
# MDEV-10372: [bb-10.2-mdev9864 tree] EXPLAIN with recursive CTE enters endless recursion
1462+
#
1463+
create table t1(a int);
1464+
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
1465+
explain format=json
1466+
with recursive T as (select a from t1 union select a+10 from T where a < 1000)
1467+
select * from T;
1468+
EXPLAIN
1469+
{
1470+
"query_block": {
1471+
"select_id": 1,
1472+
"table": {
1473+
"table_name": "<derived2>",
1474+
"access_type": "ALL",
1475+
"rows": 10,
1476+
"filtered": 100,
1477+
"materialized": {
1478+
"query_block": {
1479+
"recursive_union": {
1480+
"table_name": "<union2,3>",
1481+
"access_type": "ALL",
1482+
"query_specifications": [
1483+
{
1484+
"query_block": {
1485+
"select_id": 2,
1486+
"table": {
1487+
"table_name": "t1",
1488+
"access_type": "ALL",
1489+
"rows": 10,
1490+
"filtered": 100
1491+
}
1492+
}
1493+
},
1494+
{
1495+
"query_block": {
1496+
"select_id": 3,
1497+
"table": {
1498+
"table_name": "<derived2>",
1499+
"access_type": "ALL",
1500+
"rows": 10,
1501+
"filtered": 100,
1502+
"attached_condition": "(T.a < 1000)"
1503+
}
1504+
}
1505+
}
1506+
]
1507+
}
1508+
}
1509+
}
1510+
}
1511+
}
1512+
}
1513+
drop table t1;

0 commit comments

Comments
 (0)