作者简介

刘晨

中航信研发中心 运维经理

前言:众所周知对于 OLTP 的交易系统最重要的操作就是数据库的CRUD,数据库层面或者SQL优化的程度,对于整个系统的并发处理能力起到至关重要的作用。

很多朋友都会碰到这样的问题,系统运行初期,数据库层面运转非常稳定,SQL处理能力也很强。当业务发展一定阶段,SQL语句性能变差,导致应用并发处理能力下降,究其原因,可能是资源的问题、环境的问题、还可能是数据库设计的问题。

今天我们选择某个核心交易系统历史过期数据删除的逻辑优化案例。通过一些介绍了解业务发展的不同阶段,旧数据的删除逻辑是如何演进的,以及不同演进过程当中有哪些设计优化的经验。我分为以下四个部分做分享。

一、案例背景


首先我们看一下需求背景,这是一套核心的OLTP的交易系统,这套应用背后有二十几张关联的主子表,表中数据过期数据要及时清理。


开发人员用java写了删除的程序,我们希望每天六点业务高峰期之前完成数据清理工作。

二、问题描述

接下来我们看下问题。随着业务的推广,相应数据删除执行时间逐渐变长,从最开始只需要三十分钟,逐渐增加到两小时、五小时、甚至十几个小时。

经过分析有一张终极情况下5000万记录的子表B,删除效率比较低,属于这个问题的主要矛盾。终极情况下主表A会有2000万数据,存储七天之前到未来两天的数据,子表B关联主表的ID。子表B每天删除七百万,对于主表A来说需要从子表找到需要删除的记录。


同时因为主表A下面有一系列的子表,我们最开始设计是按串型的方式逐一删除每一张子表,再删除主表。

三、细察深剖


我们会从几个阶段来看看针对数据删除的逻辑我们是如何演进的,如何采用不同的方案进行优化。


首先阶段一业务投入初期,业务量非常有限,开发人员使用SQL通过A表筛选出来七天之前的ID记录,然后和子表B做一个关联删除B表中的数据,同时有rownum作为条件,限制一次删除交易的数据量,避免大事务的产生。

因为子查询当中只存在十天的数据,因此采用了全表扫描的执行计划,根据之前的数据量预估推测,它需要执行七百次的A表全表扫描。这个阶段来说业务量有限,数据库的配置比较高,因此执行时间,可以接受。

系统投产初期,数据量很有限,这个阶段,其实任何满足删除逻辑需求的SQL都是可以接受的,但是它的隐患非常明显,因为我们对一张大表执行了全表扫描,执行时间一定会随着数据量的增加而变长。

到了阶段二,业务量有所增加,这时候SQL执行时间也变长了,为了提升效率我们做了一些优化。第一个思路就是能不能少做一些事情,创建一张中间表C,存储的是在主表A中要删除数据的ID值,通过中间表C再和子表B做关联,它和阶段1的差别是什么?阶段1是做700次2000万数据的全表扫描,现在只需要做700次200万数据的全表扫描,并将删除程序改为并行执行,能同时删除多张子表。

相比阶段一,它把对于子表的删除由串型改成了并行,同时全表扫描的数据量有所下降,性能会有一定的提升,但是隐患还在,因为还是对两百万的表进行了全表扫描,执行时间还是随着业务的推广逐渐增加。

到了阶段三,这个时候业务发展比较迅猛,业务量接近终级的状态了,这时候夜维执行时间超出了需求,现在的优化目标就是能不能避免子表全表扫描的操作,我们通过下面四步操作来看一下,首先在创建的中间表C中增加pkid字段,即将原先B表每次批量删除1万条的限制,推至内层循环,以让C表使用索引,避免全表扫描。例如,第一次子查询pkid的字段是1到10001,接下来就是10001到20001。

根据业务的评估,C表中一个ID,对应子表B两到三条。虽然和之前相比一次删除的数据量增加了,但是量级上基本可控。

这个阶段我们的方案通过pkid的索引避免子查询的全表扫描,虽然一次删除B表的数据多了,但相应的执行次数减少了。如果按照我们最初的分析,这种方案应该是比较完美了,可以解决我们之前的问题。

但是,现实和理想是有差距的。我们在上线当晚就报错了,从日志当中看到它抛了一个ORA-01555的错误。这是一个非常经典的错误号。原因就是在做数据检索的时候,有数据变化,我们需要从UNDO检索数据,做一致性读,如果SQL执行空间比较长,UNDO中的镜像就可能被其他事务覆盖,这时候就会抛出ORA-01555的错误。


对于C表它采用了索引范围扫描,用到了索引,但是对于子表B执行了全表扫描,正是因为全表扫描才导致SQL执行时间非常长,才让程序出现了错误。

现在问题来了,是不是因为子查询一万数据太多了?我们尝试将子查询缩小到五千、两千五以及十一个数据,它依然没有改变。偶然的是,我们尝试 1910001到1920001的参数值时,发现执行计划变了,对两表进行了索引扫描,以及嵌套循环连接,这才是我们真正需要的执行计划。

现在问题又来了,这是为什么?通过分析,pkid区间1-10001对应B表a_id的值比较无序,而且间隔较远,pkid区间1910001-1920001对应B表a_id的值比较有序,间隔较近,由此,我们联想到Oracle中Clustering Factor聚簇因子这个概念。他表示的是索引键值的排列顺序,和对应表中数据排列顺序的相近程度。

通过一个索引扫描一张表时需要访问的表的数据块的数量。反映了索引范围扫描可能带来的对整个表访问过程的IO开销情况。如果值越小(接近表的数据块数量),说明表中数据是有序的,同一个索引叶子结点上相邻的索引键值,对应的表中记录可能位于相同的数据块上,(表是按照索引字段的顺序存储),相应根据索引,回表检索数据,就会消耗更少的物理IO。

如果值越大(接近表的行数),说明表中数据是无序的,同一个索引叶子节点上相邻的索引键值,对应的表中记录就可能位于不同的数据块上,(表不是按照索引字段的顺序存储),相应根据索引,回表检索数据,就会消耗更多的物理IO。

我们通过图示,可以更加形象的理解,这张图是聚簇因子比较小的示意图,我们看一个索引叶子节点上,索引键值对应到表的记录,可能位于相同的数据块,组织有序。

这张图是聚簇因子比较大的示意图,同一个索引叶子结点上,相邻的索引键值,对应表中的记录,可能位于不同的恶数据块,组织无序。相同一次检索,回表需要消耗更多的物理IO。

我们再用图示,看下pkid在1-10001和1910001-1920001两个区间,可能的情况,1-10001对应B表待删除a_id索引,可能位于不同的数据块上,1910001-1920001对应B表待删除a_id索引,可能位于有限个相邻的数据块,因此前者检索B表的时候,有可能全表扫描的成本,就要低于索引范围扫描,而后者索引范围扫描的成本,低于全表扫描,所以pkid区间不同,导致B表扫描成本的不同,因此选择了不同的执行计划。

我们知道了原因,应该如何改造?很明显,目标是让B表一次删除的a_id尽量接近。原先C表构造,只是根据时间,将符合条件的A表记录,随机插入C表,现在我们加上order by id,保证插入C表的时候,是按照id字段排序存储,相当于按序构造了表C。

从优化效果来看,子表B在优化之前都需要两个小时到三个小时的删除时间,优化之后,基本上五十分钟就可以完成数据的删除工作。


子表B是属于优化主要矛盾,解决主要矛盾之后,相应夜维的总体执行时间也有所下降,原先需要四个小时以上的时间完成清理,现在仅需要两个半小时时间就可以完成所有数据清的理工作。

上面是我们对数据删除的演进过程进行了说明。

四、总结回顾

最后我们简单总结回顾一下问题。首先我们投产初期,只要SQL语句符合需求,在执行时间上就可以。之后全表扫描的隐患就会逐渐暴露出来,我们通过将串行改为并行,同时增加了pkid字段,旨在使用索引。

但是,实际过程中pkid的数据分布变成了乱序的,进而导致使用索引扫描的成本值非常高,无法使用索引,还出现了ORA-01556的报错。明确了原因之后解决方案也很简单。我们通过指定排序构造中间表,来降低索引访问的成本。

除了这些优化操作外,或许可能有其他的方法,比如使用引用分区特性、删除外键约束并发执行,其实对于一些优化的工作,方法可能不止一种,殊途同归,选择你最熟悉、最易操作的执行就好,毕竟技术是为业务服务的。

通过案例我们也做了一些思考。

第一个就是好架构不是设计出来的,而是演进来的,对于数据库应用的逻辑一样如此,对于不同的阶段,可能会有不同的逻辑调整。

第二点,在优化过程中,首先要抓住主要矛盾,不能眉毛胡子一把抓,要明确主要的矛盾,作为首要的目标去解决。

第三个,就是无论对于开发人员还是架构师来说,我们不能把数据库当做一个黑盒,我们理解越全面、越深入,越可以理解和发现问题。

最后一个就是对于一些性能隐患,是可以提前避免的,例如大表的全表扫描,它的执行时间,一定会随着数据量的增加而增长。

咱们这次会议的主题,是自动化运维、智能运维。对于这些隐患,现在业界也有了像SQL审核工具这种产品,无论是开源的,还是商业的,通过自动化的方式,提前预警。

我们的团队,也在做这方面的探索,正在自研我们自己的数据库智能审核分析平台Sherlock,希望他可以像神探夏洛克一样,帮助我们找出数据库开发的隐患,辅助开发人员、DBA,进行数据库开发的工作,践行DevOps,希望未来有机会,分享出来这方面的工作。以上就是我今天的分享。感谢各位。

AIOps,DevOps?

运维行业的风向标

想知道

2019 运维行业必关注的行业趋势?

4.12-13,我们在深圳等您

点击阅读原文,了解 GOPS 2019 · 深圳站更多精彩

oracle procedures批量删除带索引条件数据很慢_见微知著,数据库应用设计优化浅谈...相关推荐

  1. oracle procedures批量删除带索引条件数据很慢_redis数据结构、持久化、缓存淘汰策略...

    Redis 单线程高性能,它所有的数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题.redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放 ...

  2. 如何在Oracle中批量删除数据

    在一个ORACLE数据库运行过程中,有时候会遇到要批量删除数据的情况,如一个保存历史数据的表中有大量的数据已经不需要保留,要将这部分数据删除. 以下就这种情况可以采取的方法进行讨论. 1.使用TRUN ...

  3. Oracle中大批量删除数据的方法

    批量删除海量数据通常都是很复杂及缓慢的,方法也很多,但是通常的概念是:分批删除,逐次提交. 下面是我的删除过程,我的数据表可以通过主键删除,测试过Delete和For all两种方法,for all在 ...

  4. 6.9 用Python操控数据库(批量删除,百度新闻数据爬取与存储,写入数据时进行去重处理,pandas读取sql数据)

    学习完MySQL数据库的基本操作后,下面来学习如何用Python连接数据库,并进行数据的插入.查找.删除等操作. 6.9.1 用PyMySQL库操控数据库 上一节在phpMyAdmin 中创建了数据库 ...

  5. Oracle中批量删除数据

    在一个ORACLE数据库运行过程中,有时候会遇到要批量删除数据的情况,如一个保存历史数据的表中有大量的数据已经不需要保留,要将这部分数据删除.以下就这种情况可以采取的方法进行讨论.   1.使用TRU ...

  6. Excel批量删除空白单元格数据左移的2种方法

    (方方格子插件) 如图想将各个产品的库存信息汇总到1列,该如何操作呢 一. 1.选中出标题行列外的数据区域 2.Ctrl+G选择定位条件 3.选择空值按钮 4.Ctrl+减号选择右侧单元格左移的操作 ...

  7. oracle数据分布不均,oracle性能优化操作七:索引提高数据分布不均匀时查询效率...

    索引的选择性低,但数据的分布差异很大时,仍然可以利用索引提高效率. A.数据分布不均匀的特殊情况下,选择性不高的索引也要创建. 表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段Di ...

  8. 用户数据表设计借鉴 浅谈数据库用户表结构设计,第三方登录 基于 Token 的身份验证

    最近对用户数据表的设计比较感兴趣,看到了两篇比较好的文章. 浅谈数据库用户表结构设计,第三方登录 转载于: https://www.cnblogs.com/jiqing9006/p/5937733.h ...

  9. oracle 频繁操作删除对索引的影响吗,清除Oracle中无用索引 改善DML性能

    DML性能低下,其中最严重的原因之一是无用索引的存在.所有SQL的插入,更新和删除操作在它们需要在每一行数据被改变时修改大量索引的时候会变得更慢. 许多Oracle 管理人员只要看见在一个SQL 查询 ...

最新文章

  1. 揭秘丨“北京八分钟”里中国制造的科技力量
  2. ajax可以在localhost上用吗_你还不知道跨域问题是怎样造成的吗?
  3. Oracle-知识结构漫谈
  4. UVA-10285 Longest Run on a Snowboard (递推)
  5. 一文了解贪心算法和回溯算法在前端中的应用
  6. 互联网晚报 | 8月11日 星期三 | 苏炳添成为小米品牌代言人;联想企业购正式上线;中国电信A股IPO战略配售结果出炉...
  7. Python3网络爬虫开发实战,IP代理池的维护
  8. koa2:通过Ajax方式上传文件,使用FormData进行Ajax请求
  9. sql server 复制_SQL Server复制(合并)–复制架构更改中的性能问题
  10. 2021年中国云计算软件市场趋势报告、技术动态创新及2027年市场预测
  11. 女孩,请把第一胎留给丈夫!!!
  12. python版js压缩工具
  13. win7无法自动获取dns服务器地址,Win7无法自动获取DNS与IP地址怎么办
  14. 新中大服务器端数据库未能连接,新中大服务器数据库未能连接
  15. 持续造风,快手为品牌、商家提供“保姆式”服务
  16. play框架用起来(1)
  17. 赛效:怎么用改图宝给图片添加水印?
  18. 时间--cd //lastyear
  19. Qt 内存管理与布局管理器
  20. 好评返现如何摆脱平台规则和流量限制

热门文章

  1. Nature综述:真菌的多样性:真菌的高通量测序及鉴定
  2. 扩增子文献笔记2拟南芥根微生物组的结构和组成
  3. numpy使用[]语法索引二维numpy数组中指定指定列之后所有数据列的数值内容(accessing columns in numpy array after specifc column)
  4. pandas从dataframe中删除一个或多个数据列
  5. R语言基础知识详解及概括
  6. R语言广义线性模型Logistic回归模型亚组分析及森林图绘制
  7. pandas读取字典(dict)数据
  8. python代码实现二叉树中最低的公共祖先
  9. 线性判别分析(LDA)和她的家人们
  10. The advantages of SMRT sequencing