如何优化 select * from TABLE_A

其实是标题党,吸引你进来,来做一次历时一周的sql优化。

实际的sql为(表名,列名与实际数据为虚构,如有雷同,纯属巧合):

select * from A where data =‘28-FEB-2025’ and ID = 1 and dep_id = 11022;

背景介绍:

  • 数据库:Oracle 19C
  • 并不是分区表
  • 表内数据大概在9亿左右
  • 索引建在column date,ID,DEP_ID
  • 表的统计更新状态正常
  • 索引状态正常
  • 当前状态的结果集数量为70万,全部返回的时间为55分钟。执行计划的cost接近20000
  • 开发同事希望全部返回的时间降到10秒-20秒

面对这样的背景,我沉默了很久。和他说,咱们先把它改成分区表吧。这张表这么大,你们之前是怎么忍过来的。

在和业务的同事开会讨论了三天之后,我们成功地把这张表改为了分区表。分区键为该查询的三个条件,即date,ID,dep_id.

有进行了一天的讨论后,一直认为,并没有做复合分区的必要。

所以,目前的表的状态为

  • 分区表
  • 分区键为date,ID,dep_id
  • 每一个partition 不存在 subpartition
  • 每一个分区的数据量为百万级别(80万-130万)
  • 每个分区的统计更新状态正常
  • 暂时没有新建索引
  • 工具执行当前查询的返回时间为0.1秒
  • 返回全部结果的时间为25-30分钟

第一阶段的优化后,我当时认为已经到达极限了。无法再继续优化了。因为此时的实际sql为:

select * from A partition(P1);

这与

select * from table_A;

没有区别。

不过,我还是接受了这样的疑问,为什么不加入parallel hint?

把sql变为

select /* + parallel (16)*/ from table_A;

我说,会有作用,但并不明显。原因在于当前,工具执行的时间为0.1 秒,代表着查询的速度其实是很快的,我们现在的瓶颈在print 结果上面。如果不增加查询条件,减少返回值。速度不会改变。

当然我们还是进行了测试,分别进行了并行度 8,16,32的测试。

测试结果与不加并行几乎无差别。

压力又回到了业务组的同事,你们真的需要这么多的数据嘛?

再又一轮的讨论中,我们得知,可以新加三个查询条件。city_code, int_code 和 AR。

不过,这三列里面的distinct value并不多。单独以某一列做b tree索引,并不是一个好的办法。

目前有这样两条方案:

1.把这三列绑定在一起做组合local索引。
2.把这三列绑在一起做位图local索引。

实测下来,执行计划中的cost均有明显降低,由5500降到了400左右.

但最后我们放弃位图的原因是,如果不在查询中加入指定index的hint,有时候,数据库的优化器并不会选择这个索引。
开发组的同事表示,这对后期的代码改动以及交接业务会带来一定的工作量。既然两个差不多,就选简单的吧。

建好索引,交差。

本以为这是事情的终章了,但是在夜深人静的时候,还是觉得隐隐不安,打开电脑,果然出现了新需求。

select * from A where data =‘28-FEB-2025’ and ID = 1 and dep_id = 11022 and city_code||‘.’||int_code in (‘122.9’,‘13.11’,‘6.3’);

这条查询为啥不走索引呢?

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值