最近遇到 表改造 问题, 发表文章纪念之
表模型设计 感觉 一项技术活, 满足不可预见的功能添加, 不可能 添加一个字段, 整个项目代码 换血。 其次性能 要求,起码保证业务常态, 和高峰状态下性能平稳。
最牛逼的是 满足性能的可线性扩张。
废话不说, 上干货。
现在的业务, 大概在每 20分钟左右 到一批数据, 到达数据后做 更新等操作的一系列调度流程, 等结束后, 启动删除数据流程,
删除数据是删除 4 小时之前的数据, 次是保证 OC 表中, 只保留4小时之内的数据, 一些调度流程一般在1.5 小时结束,估测OC
删除数据是删除 4 小时之前的数据, 次是保证 OC 表中, 只保留4小时之内的数据, 一些调度流程一般在1.5 小时结束,估测OC
中 会保留2 个流程的最新 数据, 供前段业务查询。
现在OC表的结构
按照 13 个地市list分区, 比如 南京, 苏州, 常州等.... 另外表中有时间片, 10分钟个时间片, 一天24 小时, 此中的时间片
字段 OC_time 1-144 , 而加载的一批数据 全是1个 时间片的, 比如 08:00 过来的一批数据, 这些数据时间片为 48.
字段 OC_time 1-144 , 而加载的一批数据 全是1个 时间片的, 比如 08:00 过来的一批数据, 这些数据时间片为 48.
现在监控的问题
一张OC表 大概 2.5个G 左右, 从现在来看水位线 高80%, 保留4 小时数据, 这些OC表从0点到4小时前的数据虽然delete 了, 但是
表上面的空快 还在。定期管理 也不现实,业务轮回太频繁。
一张OC表 大概 2.5个G 左右, 从现在来看水位线 高80%, 保留4 小时数据, 这些OC表从0点到4小时前的数据虽然delete 了, 但是
表上面的空快 还在。定期管理 也不现实,业务轮回太频繁。
监控的oracle buffer cache 中 OC表 大量的空快。
此时 前段 查询大概在 20多秒吧。 基本满足 用户需求, 用户偶尔反应慢。
另外系统整体 环境, 大量的等待事件表明内存不够用, IO 繁忙, AWR 报告中此类 问题严重, 此就不具体说明了。
更改 :
现在 的一级分区, 不能大批量的数据 清空操作 不方便, 改成 二级分区, truncated 二级分区管理数据, 自动回收水位。 另外 4小时 为一个范围分区。一天 6 个分区
调度流程完成, 算出要保留的哪些分区,然后情况上一个 分区的数据, 随着业务流程轮回truncated 分区。 预计现在 2.5 G的表 能稳定 在 7到800M左右,能节约内存 ,IO等。 而前端 查询必然带地市
字段值,也就是说 一般查询 小于100M的,所以5秒内肯定出数据,
字段值,也就是说 一般查询 小于100M的,所以5秒内肯定出数据,
本来想和原系统表 大致类似, 用 地市做一级分区的, 但是 10G数据库, 不支持 list-range 分区(要是11g多好), 故采用 range - list 分区, 分区搞好后,监控OC表的体积 果然 能稳定在
700-800M左右, 内存中空快的数量 几乎减少90%。 果然在 先前 预计的一样。大赞!
700-800M左右, 内存中空快的数量 几乎减少90%。 果然在 先前 预计的一样。大赞!
但是随之而来的问题, 前段页面查询效率 突然下滑, 为啥?? 和解??
原来发现 前段查询, 是查询 最大oc_time 的数据,大致的SQL, sql: select count(*) from table_oc where 地市=南京 and oc_time = func_getmax_oc_time('table_oc', '南京市') and 。。。。。。
我的去!! 原来 幸幸苦苦 把OC 表改成分区表, 排除所有 可能的隐患, 居然.... 心里默默 责怪 领导 当时 搞 func_getmax_oc_time('table_oc', '南京市')。函数, 曾多次
提醒 需要把 这个值 先查询出来, 再带入到 sql 中多好。 直接定位到具体的二级分区。 但是还是出现这样的SQL。
如何 优化:
说到这 其实有优化 经验的 都已经知道如何 优化了。 故这里简述
从执行计划上面来看, 出现的是 以及分区定位问题, oracle 不知道 次函数 的返回值是多少, 故需要 到所有的一级分区 去挨个 filter, 导致的问题。 也不可能改成我当时提供的
方案。 只能 让oracle 挨个过滤, 但是这里不矛盾, 因为让oracle 挨个过滤索引。过滤完 让其 回表 到 二级分区中, (如果是11g 不需要建索引, 具体原因省略....)
于是 建索引 oc(oc_time, 地市) local. 看是矛盾的索引, 索引字段 全是 分区字段,oc_time 是 一级分区, 地市是 二级分区。 而且还是分区索引。 其实一点也不矛盾。
实际的效果 select count(*) from table_oc where 地市=南京 and oc_time = func_getmax_oc_time('table_oc', '南京市') and 。。。。。。 0.2s
对比之前的20s 完爆!!
大赞.....
至此 OC 表分区改造 完成。