GBase 8a 可能有效的OR优化

业务SQL中包含OR, 如果发现性能对比没有这个OR下降极大,可以考虑本文介绍的OR优化试试。包括在过滤条件里的OR以及JOIN条件里的OR两种情况。

所有改写都是在默认执行计划的优化效果不好时,看看这个手工指定的优化是否更好一些。性能是否提高以及最终结果是否正确,都建议多加验证。

过滤条件

分为两种情况,同一个列不同的值,以及不同的列不同的值(前者算后者的特殊情况,但更常见。核心就是手工将多个OR判断,改成1个判断。

A=XX OR A=YY 以及 A in (XX,YY)的写法

改写成适合数字的写法
decode(A,XX,XX,YY,XX,'')=XX
也就是把YY值改成XX,变成都判断等值XX

改成case的写法,适合字符

case A when XX then XX when YY then XX end)=XX
gbase> select * from t3 where id=1 or id=11;
+------+------+
| id   | id2  |
+------+------+
|    1 |    1 |
|   11 |   11 |
+------+------+
2 rows in set (Elapsed: 00:00:00.07)

gbase> select * from t3 where decode(id,1,1,11,1)=1;
+------+------+
| id   | id2  |
+------+------+
|    1 |    1 |
|   11 |   11 |
+------+------+
2 rows in set (Elapsed: 00:00:00.08)

A=XX OR B=YY or C=ZZ

改写成

concat(case when a=XX then XX else '' end,case when B=YY then XX else '' end,case when C=ZZ then XX else '' end) like 'XX%'

其中的XX,YY可以是相同值或者不同值。 核心也是将多个OR判断,改成1个判断。

gbase> select * from t3 where id=111 or id2=9999;
+------+------+
| id   | id2  |
+------+------+
|  111 | 1111 |
+------+------+
1 row in set (Elapsed: 00:00:00.04)

gbase> select * from t3 where concat(case when id=111 then 111 else '' end,case when id2=9999 then 111 else '' end) like '111%';
+------+------+
| id   | id2  |
+------+------+
|  111 | 1111 |
+------+------+
1 row in set (Elapsed: 00:00:00.09)

JOIN条件 要求结果集没有膨胀

如下的JOIN里,OR条件

select b.XX from a 
left join b on (a.id=b.id or a.name=b.name) and ...其它join条件

改写成2个join

select coalesce(b.XX,b2.XX) from a
left join b on a.id=b.id and …其它join条件
left join b b2 on a.id<>b2.id and a.name=b2.name and …其它join条件

要求结果集没有膨胀,比如a表1万行,结果集依然是左表的1万行。也就是1对1的场景,右表不能出现重复值,导致左表膨胀。
否则因左表出现重复,1:n,导致改写后的方案结果集行数少了。

而select部分用到b表的列,需要根据b和b2的列进行选择,比如b.XX 变成 coalesce(b.XX,b2.XX)

gbase> select * from t1;
+------+------+
| id   | id2  |
+------+------+
|    1 |   66 |
|    2 |   77 |
+------+------+
2 rows in set (Elapsed: 00:00:00.06)

gbase> select * from t3;
+------+------+
| id   | id2  |
+------+------+
|    1 |   66 |
|    3 |   77 |
|    9 |   99 |
+------+------+
3 rows in set (Elapsed: 00:00:00.09)

gbase> select * from t1 left join t3 on t1.id=t3.id or t1.id2=t3.id2;
+------+------+------+------+
| id   | id2  | id   | id2  |
+------+------+------+------+
|    1 |   66 |    1 |   66 |
|    2 |   77 |    3 |   77 |
+------+------+------+------+
2 rows in set (Elapsed: 00:00:00.28)

gbase> select * from t1 left join t3 on t1.id=t3.id left join t3 t3_2 on t1.id<>t3_2.id and t1.id2=t3_2.id2;
+------+------+------+------+------+------+
| id   | id2  | id   | id2  | id   | id2  |
+------+------+------+------+------+------+
|    2 |   77 | NULL | NULL |    3 |   77 |
|    1 |   66 |    1 |   66 | NULL | NULL |
+------+------+------+------+------+------+
2 rows in set (Elapsed: 00:00:00.28)

gbase> select t1.id,t1.id2,coalesce(t3.id,t3_2.id)id,coalesce(t3.id2,t3_2.id2)id2  from t1 left join t3 on t1.id=t3.id left join t3 t3_2 on t1.id<>t3_2.id and t1.id2=t3_2.id2;
+------+------+------+------+
| id   | id2  | id   | id2  |
+------+------+------+------+
|    2 |   77 |    3 |   77 |
|    1 |   66 |    1 |   66 |
+------+------+------+------+
2 rows in set (Elapsed: 00:00:00.16)

总结

本文的OR优化,都趋向于手工调整执行计划,特别是过滤条件。 而JOIN的OR优化,必须保证1:1,不能是1:n。否则结果集可能是错的。