一条update语句的优化探索(r9笔记第80天)
今天经开发同学反馈,发现有一些update语句阻塞了部分业务流程,为什么说一些而不是一条,是因为这些update语句都在一个存储过程中,语句结构相仿,真有一种一荣俱荣,一损俱损的感觉。而比较纠结的是这样的update语句有差不多10个。从我收到反馈到观察分析,里面的第一条update语句运行了近5个小时,还没有完成,从SQL Monitor的报告来看,似乎进度甚微,按照这个进度,这些语句的执行时间会非常惊人。
我先拿到了一个初步的报告。
概览信息如下:
这条语句从生成的执行计划来看,简直完美,但是执行时间却差强人意,所以由此来看是执行计划出现了巨大的偏差。这个时候SQL Monitor是一个利器,可以真实还原问题时段的执行计划情况。
如果看上面的执行计划,其实看起来消耗也不大,好像都走了索引,在这样的一个评估值的情况下,可见数据集的变化不大。而问题就在于右边的部分。
红色的小框处标出的信息,可以看出实际得到的结果集非常惊人,结果集行数都是4G,这是一个什么级别的概念。所以这个语句的瓶颈就在这个地方。
我们来看看语句:
这个语句看起来还是比较复杂的,两个相关的表都是千万级别,红色的部分就是涉及的关键部分,都涉及到vip_recharge_log这张大表。从执行计划来看是在这里出了问题。
vip_recharge_log对应的索引信息如下:
可以看出这个语句是根据时间字段来做的数据过滤。这种方式为什么性能低效呢,和between的部分有着重大的关系。
时间跨度有多大呢,可以通过如下的表达式来得到一个时间范围。
这是取近半年的数据结果,对于一个OLTP的千万级表来说,全表扫描的代价其实要更低一些。这样SQL在执行的过程中先根据时间字段来过滤得到一个极大的结果集,然后在这个基础上去根据id得到一个极小的结果集。这种方式简直是百害而无一利。如果根据id得到一些客户的信息,因为本身结果集就小很多,在这个基础上再根据时间来过滤,那效率会大大提高,在目前的这个场景中可以看见明显的性能问题。
所以初步的评估就是重构索引。目前的索引是根据时间字段或者根据id来创建索引,其实可以考虑复合索引,根据id,时间字段来过滤数据,成本相对要低很多。所以考虑创建一个新的索引
CREATE INDEX "IDX_VIP_RECHARGE_MIX" ON "VIP_RECHARGE_LOG"
(CN,CHARGE_DATE ) ;
这样数据过滤的效果就会好很多。这个瓶颈能够化解了,其它的几个问题也就引刃而解。
所以在这种场景下,不修改SQL语句,调整索引就预估达到极大的性能提升。而对于此还是需要很谨慎的,我复制了表中的数据,在另外的环境进行了快速的复现,执行计划的效率大大提高。在这个基础上,考虑添加了并行,虽然会消耗服务器的资源,但是能够极大提高效率,这些付出也是合理的。在这些简单调整之后,再次测试运行语句,1分半钟就能够顺利完成。
- Shodan新手入坑指南
- 我用过的——Spring定时任务的几种用法
- CentOs7.3 搭建 SolrCloud 集群服务
- CentOs7.3 搭建 Solr单机服务
- CentOs7.3 搭建 ZooKeeper-3.4.9 Cluster 集群服务
- CentOs7.3 ssh 免密登录
- 基础篇章:关于 React Native 之 Touchable 系列组件的讲解
- 基础篇章:关于 React Native 之 Navigator 组件的讲解
- CentOs7.3 搭建 ZooKeeper-3.4.9 单机服务
- Ubuntu 17.04 编译安装 Nginx 1.9.9
- CentOS7.3 安装 iptables 与详细使用
- CentOs7.3 安装 maven3.5
- 基础篇章:关于 React Native 之 Picker 组件的讲解
- Java8的十大新特性你了解多少呢?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 机器学习第1天:线性回归(代码篇)
- PHP二分查找
- OnClick 的另一种书写
- JVM系列之:JIT中的Virtual Call
- 速读原著-UnixLinux基础(五)
- Celery在Django中的简单应用
- 基于数据库Binlog 的业务系统操作日志实现方案(阿里中间件Canal)
- 速读原著-UnixLinux基础(三)
- 手撸实现UDP和TCP通信
- 3分钟短文 | PHP获取函数参数名,和类定义的常量,都要反射!
- 3分钟短文 | Laravel模型获取最后一条插入记录的ID编号
- 3分钟短文 | Laravel 模型的get find first方法你分清咋用了吗?
- 3分钟短文 ! Laravel拼装SQL子查询的最佳实现
- 对java中的泛型的理解
- 解决elasticsearch集群Unassigned Shards无法reroute的问题