Skip to content

Commit bef20b5

Browse files
committed
MDEV-30538 Plans for SELECT and multi-table UPDATE/DELETE unexpectedly differ
This patch allowed transformation of EXISTS subqueries into equivalent IN predicands at the top level of WHERE conditions for multi-table UPDATE and DELETE statements. There was no reason to prohibit the transformation for such statements. The transformation provides more opportunities of using semi-join optimizations. Approved by Oleksandr Byelkin <sanja@mariadb.com>
1 parent 0845bce commit bef20b5

File tree

4 files changed

+201
-5
lines changed

4 files changed

+201
-5
lines changed

mysql-test/main/multi_update.result

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,3 +1251,123 @@ EXPLAIN
12511251
}
12521252
}
12531253
DROP TABLES t1, t2;
1254+
# End of 10.3 tests
1255+
#
1256+
# MDEV-28538: multi-table UPDATE/DELETE with possible exists-to-in
1257+
#
1258+
create table t1 (c1 int, c2 int, c3 int, index idx(c2));
1259+
insert into t1 values
1260+
(1,1,1),(3,2,2),(1,3,3),
1261+
(2,1,4),(2,2,5),(4,3,6),
1262+
(2,4,7),(2,5,8);
1263+
create table t2 (c1 int, c2 int, c3 int, index idx(c2));
1264+
insert into t2 values
1265+
(1,7,1),(1,8,2),(1,3,3),
1266+
(2,1,4),(2,2,5),(2,3,6),
1267+
(2,4,7),(2,5,8);
1268+
create table t3 (c1 int, c2 int, c3 int, index idx(c2));
1269+
insert into t3 values
1270+
(1,1,1),(1,2,2),(1,3,3),
1271+
(2,1,4),(2,2,5),(2,3,6),
1272+
(2,4,7),(2,5,8);
1273+
insert into t3 select c1+1, c2+2, c3 from t3;
1274+
insert into t3 select c1, c2+2, c3 from t3;
1275+
analyze table t1,t2,t3 persistent for all;
1276+
Table Op Msg_type Msg_text
1277+
test.t1 analyze status Engine-independent statistics collected
1278+
test.t1 analyze status OK
1279+
test.t2 analyze status Engine-independent statistics collected
1280+
test.t2 analyze status OK
1281+
test.t3 analyze status Engine-independent statistics collected
1282+
test.t3 analyze status OK
1283+
explain select * from t1,t3
1284+
where t1.c2 = t3.c2 and
1285+
t1.c1 > 1 and
1286+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1287+
id select_type table type possible_keys key key_len ref rows Extra
1288+
1 PRIMARY t1 ALL idx NULL NULL NULL 8 Using where
1289+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
1290+
1 PRIMARY t3 ref idx idx 5 test.t1.c2 3
1291+
2 MATERIALIZED t2 range idx idx 5 NULL 3 Using index condition; Using where
1292+
explain delete from t1 using t1,t3
1293+
where t1.c2 = t3.c2 and
1294+
t1.c1 > 1 and
1295+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1296+
id select_type table type possible_keys key key_len ref rows Extra
1297+
1 PRIMARY t1 ALL idx NULL NULL NULL 8 Using where
1298+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
1299+
1 PRIMARY t3 ref idx idx 5 test.t1.c2 3 Using index
1300+
2 MATERIALIZED t2 range idx idx 5 NULL 3 Using where
1301+
explain update t1,t3 set t1.c1 = t1.c1+10
1302+
where t1.c2 = t3.c2 and
1303+
t1.c1 > 1 and
1304+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1305+
id select_type table type possible_keys key key_len ref rows Extra
1306+
1 PRIMARY t1 ALL idx NULL NULL NULL 8 Using where
1307+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
1308+
1 PRIMARY t3 ref idx idx 5 test.t1.c2 3 Using index
1309+
2 MATERIALIZED t2 range idx idx 5 NULL 3 Using where
1310+
create table t as select * from t1;
1311+
select * from t1,t3
1312+
where t1.c2 = t3.c2 and
1313+
t1.c1 > 1 and
1314+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1315+
c1 c2 c3 c1 c2 c3
1316+
2 1 4 1 1 1
1317+
2 1 4 2 1 4
1318+
2 2 5 1 2 2
1319+
2 2 5 2 2 5
1320+
2 4 7 2 4 7
1321+
2 4 7 2 4 2
1322+
2 4 7 3 4 5
1323+
2 4 7 1 4 2
1324+
2 4 7 2 4 5
1325+
2 5 8 2 5 8
1326+
2 5 8 2 5 3
1327+
2 5 8 3 5 6
1328+
2 5 8 1 5 3
1329+
2 5 8 2 5 6
1330+
2 5 8 2 5 1
1331+
2 5 8 3 5 4
1332+
select * from t1;
1333+
c1 c2 c3
1334+
1 1 1
1335+
3 2 2
1336+
1 3 3
1337+
2 1 4
1338+
2 2 5
1339+
4 3 6
1340+
2 4 7
1341+
2 5 8
1342+
delete from t1 using t1,t3
1343+
where t1.c2 = t3.c2 and
1344+
t1.c1 > 1 and
1345+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1346+
select * from t1;
1347+
c1 c2 c3
1348+
1 1 1
1349+
3 2 2
1350+
1 3 3
1351+
4 3 6
1352+
truncate table t1;
1353+
insert into t1 select * from t;
1354+
analyze table t1 persistent for all;
1355+
Table Op Msg_type Msg_text
1356+
test.t1 analyze status Engine-independent statistics collected
1357+
test.t1 analyze status Table is already up to date
1358+
update t1,t3 set t1.c1 = t1.c1+10
1359+
where t1.c2 = t3.c2 and
1360+
t1.c1 > 1 and
1361+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1362+
select * from t1;
1363+
c1 c2 c3
1364+
1 1 1
1365+
3 2 2
1366+
1 3 3
1367+
12 1 4
1368+
12 2 5
1369+
4 3 6
1370+
12 4 7
1371+
12 5 8
1372+
drop table t1,t2,t3,t;
1373+
# End of 10.4 tests

mysql-test/main/multi_update.test

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,3 +1130,73 @@ EXPLAIN FORMAT=JSON UPDATE t2 JOIN t1 USING(a) SET t2.part=2 WHERE t2.part=1 AND
11301130
EXPLAIN FORMAT=JSON UPDATE t2 JOIN t1 USING(a) SET t2.part=3 WHERE t2.part=2 AND t1.part=2;
11311131

11321132
DROP TABLES t1, t2;
1133+
1134+
--echo # End of 10.3 tests
1135+
1136+
--echo #
1137+
--echo # MDEV-28538: multi-table UPDATE/DELETE with possible exists-to-in
1138+
--echo #
1139+
1140+
create table t1 (c1 int, c2 int, c3 int, index idx(c2));
1141+
insert into t1 values
1142+
(1,1,1),(3,2,2),(1,3,3),
1143+
(2,1,4),(2,2,5),(4,3,6),
1144+
(2,4,7),(2,5,8);
1145+
1146+
create table t2 (c1 int, c2 int, c3 int, index idx(c2));
1147+
insert into t2 values
1148+
(1,7,1),(1,8,2),(1,3,3),
1149+
(2,1,4),(2,2,5),(2,3,6),
1150+
(2,4,7),(2,5,8);
1151+
1152+
create table t3 (c1 int, c2 int, c3 int, index idx(c2));
1153+
insert into t3 values
1154+
(1,1,1),(1,2,2),(1,3,3),
1155+
(2,1,4),(2,2,5),(2,3,6),
1156+
(2,4,7),(2,5,8);
1157+
insert into t3 select c1+1, c2+2, c3 from t3;
1158+
insert into t3 select c1, c2+2, c3 from t3;
1159+
1160+
analyze table t1,t2,t3 persistent for all;
1161+
1162+
let $c=
1163+
t1.c2 = t3.c2 and
1164+
t1.c1 > 1 and
1165+
exists (select 'X' from t2 where t2.c1 = t1.c1 and t2.c2 > 4);
1166+
1167+
let $q1=
1168+
select * from t1,t3
1169+
where $c;
1170+
1171+
eval explain $q1;
1172+
1173+
let $q2=
1174+
delete from t1 using t1,t3
1175+
where $c;
1176+
1177+
eval explain $q2;
1178+
1179+
let $q3=
1180+
update t1,t3 set t1.c1 = t1.c1+10
1181+
where $c;
1182+
1183+
eval explain $q3;
1184+
1185+
create table t as select * from t1;
1186+
1187+
eval $q1;
1188+
select * from t1;
1189+
1190+
eval $q2;
1191+
select * from t1;
1192+
1193+
truncate table t1;
1194+
insert into t1 select * from t;
1195+
analyze table t1 persistent for all;
1196+
1197+
eval $q3;
1198+
select * from t1;
1199+
1200+
drop table t1,t2,t3,t;
1201+
1202+
--echo # End of 10.4 tests

mysql-test/main/update_use_source.result

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ rollback;
7676
explain update t1 set c1=0 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 > 3;
7777
id select_type table type possible_keys key key_len ref rows Extra
7878
1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
79-
2 DEPENDENT SUBQUERY a ALL NULL NULL NULL NULL 8 Using where
79+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
80+
2 MATERIALIZED a ALL NULL NULL NULL NULL 8
8081
start transaction;
8182
update t1 set c1=c1+10 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 >= 3;
8283
affected rows: 4
@@ -317,7 +318,8 @@ rollback;
317318
explain update t1 set c1=0 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 > 3;
318319
id select_type table type possible_keys key key_len ref rows Extra
319320
1 PRIMARY t1 range t1_c2 t1_c2 5 NULL 2 Using where
320-
2 DEPENDENT SUBQUERY a ref t1_c2 t1_c2 5 test.t1.c2 4 Using index
321+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
322+
2 MATERIALIZED a range t1_c2 t1_c2 5 NULL 2 Using where; Using index
321323
start transaction;
322324
update t1 set c1=c1+10 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 >= 3;
323325
affected rows: 4
@@ -558,7 +560,8 @@ rollback;
558560
explain update t1 set c1=0 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 > 3;
559561
id select_type table type possible_keys key key_len ref rows Extra
560562
1 PRIMARY t1 range t1_c2 t1_c2 5 NULL 2 Using where
561-
2 DEPENDENT SUBQUERY a ref t1_c2 t1_c2 5 test.t1.c2 1 Using index
563+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
564+
2 MATERIALIZED a range t1_c2 t1_c2 5 NULL 2 Using where; Using index
562565
start transaction;
563566
update t1 set c1=c1+10 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 >= 3;
564567
affected rows: 4
@@ -800,7 +803,8 @@ rollback;
800803
explain update t1 set c1=0 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 > 3;
801804
id select_type table type possible_keys key key_len ref rows Extra
802805
1 PRIMARY t1 range t1_c2 t1_c2 5 NULL 2 Using where
803-
2 DEPENDENT SUBQUERY a ref t1_c2 t1_c2 5 test.t1.c2 1 Using index
806+
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
807+
2 MATERIALIZED a range t1_c2 t1_c2 5 NULL 2 Using where; Using index
804808
start transaction;
805809
update t1 set c1=c1+10 where exists (select 'X' from t1 a where a.c2 = t1.c2) and c2 >= 3;
806810
affected rows: 4

sql/item_subselect.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2825,7 +2825,9 @@ bool Item_exists_subselect::select_prepare_to_be_in()
28252825
bool trans_res= FALSE;
28262826
DBUG_ENTER("Item_exists_subselect::select_prepare_to_be_in");
28272827
if (!optimizer &&
2828-
thd->lex->sql_command == SQLCOM_SELECT &&
2828+
(thd->lex->sql_command == SQLCOM_SELECT ||
2829+
thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
2830+
thd->lex->sql_command == SQLCOM_DELETE_MULTI) &&
28292831
!unit->first_select()->is_part_of_union() &&
28302832
optimizer_flag(thd, OPTIMIZER_SWITCH_EXISTS_TO_IN) &&
28312833
(is_top_level_item() ||

0 commit comments

Comments
 (0)