根据时间字段导入数据的问题总结 (r6笔记第6天)
在之前的博文中介绍过如何通过exchange partition,split partition达到快速的数据切换,对于上百G的大表来说,速度都在秒级完成
对于大分区重新分区来说,上面的步骤已经够用了,但是对于数据清理来说,工作才刚刚开始,这是一种逻辑的数据清理,因为目前分区表中重新分区后没有数据,对于历史数据可以选择按照分区逻辑使用insert append的方式进行数据导入。
因为分区规则是按照时间字段,所以在数据导入的时候犯了一个错误,就是简单使用下面的形式来导入数据。
Insert /*+append*/ into TEST_LOG select * from LOG_CLNUP where time =to_date('20150721','YYYYMMDD');
简单以为这种情况会吧2015年7月21日的数据导入,但是从测试情况来说,数据量是在少得厉害,才发现其实这种情况下,默认是会使用0时0分0秒的情况。
我们把随便一个日期进行按日期格式化,然后使用精细化的格式输出。
SQL> select to_char(to_date('2014-10-05','yyyy-mm-dd'),'yyyy-mm-dd hh24:mi:ss') from dual;
TO_CHAR(TO_DATE('20
-------------------
2014-10-05 00:00:00
当然了,这个错误是一个低级错误,我们来看我们要做的正事。
分区规则是按照月份,即每个月都有一个对应的分区,则我们计划使用下面的格式来插入数据。
Insert /*+append*/ into TEST_LOG select * from LOG_CLNUP where time between to_date('20150721','YYYYMMDD')and to_date('20150722','YYYYMMDD') ;
按照这样的逻辑应该是没有问题的。不过还是有一定的隐患,后面会单独说。 按照表的数据量,每天的增量数据都在百万,千万,所以按照天来导入还是比较合理的,如果按照月,可能时间会很长,而且不好控制。所以按照天来进行数据导入就需要使用动态sql。 第一个思路就是使用Pl/sql来做。比如对于表TEST_LOG我们这么做,其实还有好几个类似的表。方法雷同。
begin
for i in 4..110 loop
dbms_output.put_line('select sysdate-'||to_number(i+1)||' from dual;');
dbms_output.put_line('Insert /*+append*/ into TEST_LOG select * from LOG_CLNUP where time between to_date(to_char(sysdate-'||to_number(i+1)||','||chr(39)||'yyyymmdd'||chr(39)||'),'||chr(39)||'YYYYMMDD'||chr(39)||') and to_date(to_char(sysdate-'||i||','||chr(39)||'yyyymmdd'||chr(39)||'),'||chr(39)||'YYYYMMDD'||chr(39)||');'||chr(10)||'commit;');
end loop;
end;
/
这种情况下会生成相应的语句来动态插入。 比如
SYSDATE-31
-------------------
2015-06-20 17:30:23
我们就根据sysdate-i的方式来得到相应的日期。这种方式相对来说也能接受,不过比如你在晚上10点运行脚本,结果过了凌晨,这个时候sysdate就会发生变化,有些日子的数据很可能就会导入两次。所以说这种方式也是不够合理的。就算在当天完成,你去查看sysdate-i的时候也不是很方便,至少我通过这个不能很快知道我要插入数据的日期。还得推算,有的月31天,有的月30天。。。
所以相对还是这种方式要好一些。
Insert /*+append*/ into TEST_LOG partition(P_2015_07) select * from LOG_CLNUP where time between to_date('20150701','YYYYMMDD') and to_date('20150702','YYYYMMDD');
如果希望使用动态sql来完成,可以这么做。
set linesize 200
set serveroutput on
declare
tmp_date_a varchar2(30);
tmp_date_b varchar2(30);
tmp_partition_name varchar2(30);
begin
for i in 4..110 loop
select to_char(sysdate-i,'yyyymmdd') into tmp_date_a from dual;
select to_char(sysdate-(i+1),'yyyymmdd') into tmp_date_b from dual;
select 'P_'||to_char(sysdate-(i+1),'yyyy_mm') into tmp_partition_name from dual;
dbms_output.put_line('Insert /*+append*/ into TEST_LOG partition('||tmp_partition_name||') select * from LOG_CLNUP where time between to_date('||chr(39)||tmp_date_b||chr(39)||','||chr(39)||'YYYYMMDD'||chr(39)||') and to_date('||chr(39)||tmp_date_a||chr(39)||','||chr(39)||'YYYYMMDD'||chr(39)||');'||chr(10)||'commit;');
end loop;
end;
/
在绝大多数的场景里这种数据导入方式是没有问题的,但是有一种场景会报下面的错误。比如
Insert /*+append*/ into TEST_LOG partition(P_2015_06) select * from LOG_CLNUP where time between to_date('20150630','YYYYMMDD') and to_date('20150701','YYYYMMDD')
*
ERROR at line 1:
ORA-14401: inserted partition key is outside specified partition
这个问题还是在时间戳上出了问题,因为时间戳跨分区了。所以在检查的时候会有一些问题。
可以这么改。
Insert /*+append*/ into M_START_LOG partition(P_2015_06) select * from M_START_LOG_CLNUP where time between to_date('20150630 00:00:00','YYYYMMDD hh24:mi:ss') and to_date('20150630 23:59:59','YYYYMMDD hh24:mi:ss');
这种方式就可以了。如果希望该成这种方式也可以,脚本变化不大,我就不列举了。
所以通过这个通过时间戳导入数据的案例来看,还是有不少的坑的,还是需要不断验证,大胆猜想,小心求证。
- Oracle数据库重做日志及归档日志的工作原理说明
- 用vs.net2010做flex/flash/as3开发
- python中input()与raw_input()的区别到底是啥?
- VB下中文URL编码问题的解决
- 让ZeGraph在X方向上填满
- 中国区块链技术和产业发展论坛举行——区块链应用发展尚需时日
- silverlight获取外部数据的另一种选择:FluorineFx
- 存储状态数据
- Oracle数据库设置为归档模式的操作方法
- flash/flex 与 FluorineFx通讯之Hello World!
- 苹果CEO首次泄露出自动驾驶汽车的相关战略信息
- Linux下绑定网卡的操作记录
- flash开发中如何实现界面代码分离
- flex中使用swc实现更好的界面代码分离
- 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 数组属性和方法
- 一些Redis很实用的工作技巧
- 设计模式(Design Patterns)Java版
- 一个PHP高性能、多并发、restful的工具库(基于multi_curl)
- Spring框架的设计模式
- 最全Kafka 设计与原理详解【2017.9全新】
- 【数学建模】模拟退火算法介绍及实现
- Proxy系统架构升级
- Kafka快速上手(2017.9官方翻译)
- 【动手学深度学习笔记】之Pytorch实现线性回归
- 【动手学深度学习笔记】之softmax回归
- 一文全面梳理各种锁机制
- 【动手学深度学习笔记】之图像分类数据集(Fashion-MNIST)
- 探讨缓存行与伪共享
- Stream 流解读
- 3 分钟生成一个单元测试报告,这个样式爱了