`OR`连接的条件重写为`UNION`

Copyright © 2023 PawSQL

本篇属于高级SQL优化系列专题中的一篇,该专题介绍PawSQL引擎优化算法原理及优化案例,欢迎大家订阅。

问题定义

如果使用OR连接两个查询条件,数据库优化器有可能无法使用索引来完成查询。譬如对于以下的SQL语句,

select * from customer where c_phone like '139%' or c_name = 'Ray'

如果这两个字段上都有索引,可以把他们重写为UNION查询,以便使用索引提升查询性能。

select * from customer where c_phone like '139%'
union 
select * from customer where c_name = 'Ray'

但是这种转换并不总是能够提升查询性能,它需要一定的适用条件,并需要经过基于代价的估算。

如果数据库支持index merging(请参考如和创建高效的索引),也可以调整数据库相关参数启用index merging优化策略来提升数据库性能。

适用条件

  1. OR连接的条件必须是可以利用索引的
  2. 重写后的UNION语句估算代价比原SQL小
  3. 如果OR分支的条件是互斥的,那么重写为UNION ALL

案例分析

案例1. 条件分支无法利用索引,不进行重写

select * from customer 
where c_phone = '1' or c_phone like '%139%'

解析: 其中一个条件c_phone like '%139%'无法利用索引,重写后仍然需要全表扫描,PawSQL不进行重写

案例2. 过滤条件选择率足够低,不进行重写

select * from customer 
where custkey = 1 
and (c_phone = '1' or c_phone like '%139%') 

解析custkey是主键,custkey = 1唯一定位一条记录,所以无需进行重写

案例3. 满足重写条件,进行重写

select distinct * from customer 
where c_phone like '139%' or c_name = 'Ray'

解析: 两个条件都可以利用索引,且选择率低于10%,可以进行重写,由于union可以去重,所以原SQL中的distinct在重写后可以去除。

select * from customer where c_phone = '1' 
union 
select * from customer where c_phone like '139%'

案例4. OR条件分支互斥,重写为UNION ALL

select * from customer where custkey = 1 or (custkey = 2 and c_phone like '139%') 

解析:由于两个条件分支c_custkey = 2 and c_phone like '139%'c_custkey = 1 互斥,因此重写为UNION ALL

select * from customer where c_custkey = 2 and c_phone like '139%'
union all 
select * from customer where c_custkey = 1

案例5. 包含ORDER BY子句和LIMIT子句,满足重写条件

select * from orders o
where O_ORDERDATE>='2021-01-01' 
      and (O_ORDERPRIORITY = 1 or O_SHIPPRIORITY = 1)
order by O_ORDERDATE desc limit 10

**解析:**虽然O_ORDERPRIORITY = 1O_SHIPPRIORITY = 1的选择率较高,但是由于通过索引可以避免排序,总体代价较低,PawSQL进行了重写优化.

select *
from (
   (select /*QB_2*/ *
    from orders as o
    where o.O_ORDERDATE >= '2021-01-01'
    and o.O_SHIPPRIORITY = 1
    order by o.O_ORDERDATE desc limit 10) 
       union 
  (select /*QB_1*/ *
  from orders as o
  where o.O_ORDERDATE >= '2021-01-01'
    and o.O_ORDERPRIORITY = '1'
  order by o.O_ORDERDATE desc limit 10
  )
) as PawDT_1702555889039
order by PawDT_1702555889039.O_ORDERDATE desc limit 10

案例6. 包含分组和聚集,满足重写条件

select O_ORDERDATE, count(1) from orders o
where O_ORDERDATE>='2021-01-01' and (O_ORDERPRIORITY = 1 or O_SHIPPRIORITY = 1) 
group by O_ORDERDATE

**解析:**虽然O_ORDERPRIORITY = 1O_SHIPPRIORITY = 1的选择率较高,但是由于通过索引可以避免排序,总体代价较低,PawSQL进行了重写优化.

select PawDT_1702884016144.O_ORDERDATE, count(1)
from (
    select /*QB_2*/ o.O_ORDERDATE, o.O_ORDERKEY
    from tpch_pkfk.orders as o
    where o.O_ORDERDATE >= '2021-01-01'
    and o.O_SHIPPRIORITY = 1
       union 
select /*QB_1*/ o.O_ORDERDATE, o.O_ORDERKEY
 from tpch_pkfk.orders as o
 where o.O_ORDERDATE >= '2021-01-01'
    and o.O_ORDERPRIORITY = '1'
 ) as PawDT_1702884016144
group by PawDT_1702884016144.O_ORDERDATE

性能验证

案例5性能提升900倍

  • 优化前执行计划(执行时间432.322ms)

在这里插入图片描述

  • 优化后执行计划(执行时间0.189ms)
    在这里插入图片描述

案例6性能提升20倍

  • 优化前执行计划(2.816ms)
    在这里插入图片描述

  • 优化后执行计划(0.131ms)
    在这里插入图片描述

关于PawSQL

PawSQL专注数据库性能优化的自动化和智能化,支持MySQL,PostgreSQL,openGauss,Oracle等,提供的SQL优化产品包括

  • PawSQL Cloud,在线自动化SQL优化工具,支持SQL审查,智能查询重写、基于代价的索引推荐,适用于数据库管理员及数据应用开发人员,
  • PawSQL Advisor,IntelliJ 插件, 适用于数据应用开发人员,可以IDEA/DataGrip应用市场通过名称搜索“PawSQL Advisor”安装。
  • PawSQL Engine, 是PawSQL系列产品的后端优化引擎,可以独立安装部署,并通过http/json的接口提供SQL优化服务。PawSQL Engine以docker镜像的方式提供部署安装。

联系我们

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值