通过Snapshot Standby来精确评估SQL性能 (r9笔记第73天)
最近处理了一个需求,比较紧急,映射到数据库层面是需要更新17万id的值,听起来是不少,根据数据架构进行了分析,发现目前是做了分库分表的方式,所以这17万的id在这些分库中都可能存在,而跨部门的数据交付中,也没有做分库的区分,所以拿到的id是一个笼统的概念,即哪个id对应哪个分库没有事先过滤甄别,这个工作就自然而然的下落到了DBA头上。
分库分表的方式,目前有12个分库,是以十二个用户的形式体现出来的,所以如果要整体更新,那么每个分库都需要更新一遍,有匹配的数据就更新,否则忽略。如此一来,更新的数据规模是就有几种计算方式,一种是每个id更新对应一条sql语句,那么语句就有17000*12=2040000条,200多万条, 规模是相当惊人了。执行期间的锁暂且不考虑,光是执行时间在毫秒,百万的基数也会把差距放大。还有一种思路是提供12个sql语句,每个分库各一条sql 语句,把17万的id放入一个临时表中,关联更新,这种方式执行时间肯定相比单条语句要长,但是具体多多少还是未知数。
尤其是线上系统,关键的业务系统,这类的操作就尤其敏感。如果有几种方案,需要给出一个基本的分析和评定,哪种更好,有什么准确的数据呢,主库中是万万使不得,需要有把握再动手。所以我隆重推荐使用Snapshot Standby来实现这类需求,评估性能,预估影响范围和操作时间,在完全一致的数据基础上操作,得到的数据更加有说服力。
我想了几个方案作为备用方案:
方法:
每个id对应1个sql,17万sql*12个分库
方法2:
一个临时表,12个分库,12个sql
方法3:
一个临时表,12个分库,并行执行
方法4:
每个id对应1个sql,12个分库并行执行
这些方案在Snapshot Standby的环境中都可以轻松实现。主要原理是基于闪回日志,而亮点则在于备库可读可写,测试完毕之后可以继续闪回,应用最新的数据变更。而对于上面方案中的临时表,我的考虑是基于外部表,因为本身要把这些数据导入,用完之后还得删除,热插拔的方式更加实惠。
创建外部表的语句如下:
CREATE TABLE test_uin
(uin varchar2(30)
)
ORGANIZATION EXTERNAL
(TYPE ORACLE_LOADER
DEFAULT DIRECTORY batch_query_dir
ACCESS PARAMETERS
(
RECORDS DELIMITED BY NEWLINE
)
LOCATION ('uin.txt')
);
开启备库为Snapshot Standby
DGMGRL> convert database s2test0 to snapshot standby;
Converting database "s2test0" to a Snapshot Standby database, please wait...
Database "s2test0" converted successfully
DGMGRL> show configuration;
Configuration - test0_dg
Protection Mode: MaxPerformance
Databases:
stest032 - Primary database
stest0 - Physical standby database
s2test0 - Snapshot standby database
Fast-Start Failover: DISABLED
Configuration Status:
SUCCESS
首先我测试了临时表通过insert填充数据的步骤,17万的id,用了大概5分钟。由此可想如果是12个分库,17万id更新,那么串行下来,少说也要1个小时,这个对于线上系统来说是很严重的延迟了。
然后我在这个备库中进行关联更新。
原来的语句如下:
update TEST_USER_INFO set status=-99 where uin=?;
改为临时表的结果集来处理。
update TEST_USER_INFO set status=-99 where uin in (select uin from test_uin);
这种方式大概用了30秒的时间就在12个分库顺利完成,平均每个分库大概是2秒钟的执行效率。
如此一来有了很精确的评估,所以实施起来就会很得心应手,而在部署前,得到的临时调整,需要修改的id变为了38万,当然看起来数据翻了一倍,但是执行效率还是杠杠的。大概是30秒就顺利完成。所以通过这种方式还是能够很精准的分析潜在的性能问题,而对于上面逐步分析的集中测试场景,其实有了这些数据就了然于胸。
- C/C++——set的基本操作总结
- PHP基础——字符串的常用操作
- NLP之tfidf与textrank算法细节对比基于结巴分词
- 【Go 语言社区】算法课程 第一季 第4节-汉诺塔
- C/C++——map的基本操作总结
- Python生成词云图,TIIDF方法文本挖掘: 词频统计,词云图
- C/C++——vector的基本操作总结
- 数据库负载急剧提高的应急处理(二) (r9笔记第55天)
- 社团划分——有向图的Label Propagation算法
- Python基础——网络编程
- 分区表的一个持续改进方案(r9笔记第53天)
- python jieba分词(结巴分词)、提取词,加载词,修改词频,定义词库
- MySQL中的NULL和空串比较 (r9笔记第52天)
- Core-periphery decomposition--核心-外围模型R代码整理
- 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 数组属性和方法
- CORS跨域资源共享及解决方案
- Vue 父子组件通信 兄弟组件通信 深层组件通信 方式一览
- Vue使用Element实现增删改查+打包
- 状态管理之Vuex (二) 异步管理
- Spring中AOP相关的API及源码解析,原来AOP是这样子的
- 状态管理之Vuex (一) 基操勿六
- 形式化分析工具(五)使用CAS +语法轻松编写HLPSL规范
- 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
- 太实用了!自己动手写软件——密码验证器的界面实现
- 【TBase开源版测评】深度测评TBase的shard分片和冷热分离存储特性
- Python爬虫练手,一个简单的Python资讯采集案例
- 直播带货软件开发过程中,如何实现图片上传
- 太实用了!自己动手写软件——邮件用户名密码验证
- 太实用了!自己动手写软件——SSH、FTP和SQL server的密码破解
- Kaggle Tweet Sentiment Extraction 第七名复盘