问题现象
包含标量子查询的 UPDATE 语句性能较差,需要优化。
UPDATE T1 SET T1.C1=(SELECT C1 FROM T2 WHERE T1.C2=T2.C2 AND T2.C3>100) WHERE T1.C1 >100 AND T1.C3=1;
UPDATE 语句的执行计划中 SUBPLAN FILTER 的代价很高:
================================================
|ID|OPERATOR |NAME |EST. ROWS |COST |
------------------------------------------------
|0 |UPDATE | |0 |3016991|
|1 | SUBPLAN FILTER | |0 |3014736|
|2 | TABLE SCAN |T1 |10000 |14480 |
|3 | TABLE SCAN |T2 |1 |2818 |
================================================
问题原因
因为 UPDATE 语句使用了标量子查询 T1.C1=(SELECT C1 FROM T2 WHERE T2.C2=A.C2 AND T2.C3>100),执行时需要将满足 T1 表查询条件 T1.C1 >100 AND T1.C3=1 的每一条记录与子查询进行关联,重复扫描 T2 表,而 T2 表上没有索引支持其上的查询条件 T2.C2=A.C2 AND T2.C3>100,导致了性能问题。
适用版本
OceanBase 数据库所有版本。
解决方法
方法一:改写 UPDATE 语句为 MERGE,消除标量子查询。
MERGE INTO T1
USING T2 ON (T1.C2 =T2.C2 AND T2.C3>100)
WHEN MATCHED THEN UPDATE SET T1.C1=T2.C1
WHERE T1.C1 >100 AND T1.C3=1;
转化为 MERGE 后,执行计划从 SUBPLAN FILTER 改为 HASH JOIN,T1、T2 表均只 SCAN 一次,执行代价大幅降低。
================================================
|ID|OPERATOR |NAME|EST. ROWS|COST |
------------------------------------------------
|0 |MERGE | |10000 |28158|
|1 | HASH RIGHT OUTER JOIN| |10000 |26590|
|2 | TABLE SCAN |T2 |1000 |4136 |
|3 | TABLE SCAN |T1 |10000 |14480|
================================================
方法二:将标量子查询改写为 JOIN。
UPDATE T1
LEFT JOIN T2 ON T1.C2=T2.C2 AND T2.C3>100
SET T1.C1=T2.C1
WHERE T1.C1 >100 AND T1.C3=1;
转化为 JOIN 后,执行计划从 SUBPLAN FILTER 改为 HASH JOIN,T1、T2 表均只 SCAN 一次,执行代价大幅降低。
================================================
|ID|OPERATOR |NAME|EST. ROWS|COST |
------------------------------------------------
|0 |UPDATE | |10000 |28158|
|1 | HASH RIGHT OUTER JOIN| |10000 |26590|
|2 | TABLE SCAN |T2 |1000 |4136 |
|3 | TABLE SCAN |T1 |10000 |14480|
================================================