【SQL 优化器技术系列】 Or Expansion

Oracle 2005 年出了一个 30 多页的小册子,《Query Optimization in Oracle Database10g Release 2》,介绍了常见的优化器技术。

我是做 SQL 执行的,优化部分只了解皮毛,从没有系统学习过。本系列逐个学习和介绍,自我提升,也帮助他人。

简单来说,OR Expansion 就是把 OR 拆成 UNION ALL,来打开优化空间。

举个例子:

select * from t1, t2 where t1.pkey > 10 or t2.pkey = 100;

这个语句直接执行怎么做?先让 t1, t2 做笛卡尔乘积,然后做过滤。

思考:能不能把 or 条件拆了,分别下压到两张基表上去,然后做 join?> > 答案:显然是不行的,举个例子:t2 有一个 pkey = 1 的行,t1 有一个 pkey = 20 的行,按照语义,[t1.pkey = 20, t1.pkey = 1] 这一行数据属于结果集。但是如果下压的话,显然 t2 不会输出值为 1 的这一行。

为了提高性能,这个语句可以改写成:

select * from t1,t2 where t1.pkey > 10
union all
select * from t1,t2 where t2.pkey = 100

这样一来,上下两个子 query 可以分别用到一些过滤条件,各自做 join 时可以少处理一些数据。

进一步思考:是不是所有的 OR 都能做 expansion?是不是所有的 OR 都应该做 expansion?这个是由代价决定的,并无定数。比如说,上面的 query 里 t1.pkey > 10 如果没有什么过滤性,那么 t1, t2 还是相当于要做笛卡尔乘积,性能并不会有实质提升;对于下面一个子 query 而言,性能提升肯定是必然的,先扫出 t2 的一行,然后和 t1 做一个NLJ,很舒适。

Oracle 小册子里举了一个更复杂一点点的 Query,摘录如下:

#改写前
SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND (P1.PORT_NAME = 'OAKLAND' OR P2.PORT_NAME = 'OAKLAND')

#改写后
SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND P1.PORT_NAME = 'OAKLAND'
UNION ALL
SELECT * FROM SHIPMENT, PORT P1, PORT P2
WHERE SHIPMENT.SOURCE_PORT_ID = P1.PORT_ID
AND SHIPMENT.DESTINATION_PORT_ID = P2.PORT_ID
AND P2.PORT_NAME = 'OAKLAND' AND P1.PORT_NAME <> 'OAKLAND'

上半部分,P1 数据量被消减,可能可以当驱动表;下半部分,P2 数据量被消减,可能很有用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值