运维技巧 - 活用临时表隔离冷热数据

编辑手记:Oracle给了我们很多工具,在日常数据库管理中活用这些工具方可发挥最大效能。

作者简介: 张洪涛 富士康 DBA

在数据库监控过程中发现考勤数据库上Employees_ControlData存储过程执行时间需20分钟。这个存储过程逻辑很简单,就是打开一个游标,做LOOP循环,再删除重复数据,结构如下:

CREATE OR REPLACE PROCEDURE Employees_ControlData IS tmpVar NUMBER(6); tmpVar1 NUMBER(6); tmpVar2 NUMBER (6); tmpVar3 NUMBER(6); CURSOR EMP_NO IS SELECT WORKNO FROM ZZ_EMPLOYEES; BEGIN --LINE 12行 FOR USERID INEMP_NO LOOP ...... END LOOP;

--Line128行,删除重复数据

Delete .... ; COMMIT; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; WHEN OTHERS THEN -- Consider logging the error and then re-raise RAISE; END Employees_Controldata;

ZZ_EMPLOYEES有4万多笔数据,LOOP也会执行4万多次。AWR报告与GridControl监控都显示效能瓶颈在LOOP循环中六处SQL,再看一下LOOP循环中六处问题SQL:

--Line14行

SELECT COUNT(*) INTO tmpVar FROM CPYTGL.EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO ANDTO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='F' AND INOROUT_TIME >SYSDATE-3 AND ROWNUM<6;

--Line38行

INSERT INTOEMPLOYEE_CONTROL_EXCEPTION SELECT DISTINCT * FROM EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='F' AND INOROUT_TIME >SYSDATE-3;

--Line49行

INSERT INTOEMPLOYEE_CONTROL_EXCEPTION SELECT DISTINCT * FROM EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='F' AND INOROUT_TIME >SYSDATE-3 AND INOROUT_TIME NOTIN (SELECT INOROUT_TIME FROM EMPLOYEE_CONTROL_EXCEPTION WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME, 'YYYY/MM/DD')= TO_CHAR(SYSDATE-2, 'YYYY/MM/DD') AND TYPE='F' AND INOROUT_TIME >SYSDATE-3);

--Line72行

SELECT COUNT(*) INTO tmpVar1 FROM CPYTGL.EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO ANDTO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='L' AND INOROUT_TIME >SYSDATE-3 AND ROWNUM<6;

--Line82行

INSERT INTO EMPLOYEE_CONTROL_EXCEPTION SELECT DISTINCT * FROM EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='L' AND INOROUT_TIME >SYSDATE-3;

--Line87行

INSERT INTO EMPLOYEE_CONTROL_EXCEPTION SELECT DISTINCT * FROM EMPLOYEE_CONTROL WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND TYPE='L' AND INOROUT_TIME >SYSDATE-3 AND INOROUT_TIME NOTIN(SELECTINOROUT_TIME FROM EMPLOYEE_CONTROL_EXCEPTION WHERE EMP_NO = USERID.WORKNO AND TO_CHAR(INOROUT_TIME, 'YYYY/MM/DD')= TO_CHAR(SYSDATE-2, 'YYYY/MM/DD') AND TYPE='L' AND INOROUT_TIME >SYSDATE-3);

这六处SQL都查询了EMPLOYEE_CONTROL考勤信息表。此表已有近两亿笔数据,根据INOROUT_TIME字段进行分区,并对相关字段建立了索引。

CREATE INDEX EMPLOYEE_CONTROL_EMPNOINOROUT ON EMPLOYEE_CONTROL (TO_CHAR("INOROUT_TIME",'YYYY/MM/DD'),EMP_NO) LOCAL; SQL> SELECT column_name 2 FROM dba_part_key_columns 3 WHERE name = 'EMPLOYEE_CONTROL'; COLUMN_NAME -------------------------------------------------------------------------------- INOROUT_TIME SQL> SELECT num_rows 2 FROM dba_tables 3 WHERE table_name = 'EMPLOYEE_CONTROL'; NUM_ROWS ---------- 193585044

EMPLOYEE_CONTROL考勤信息表至少需保留一年数据备查。六条SQL已加INOROUT_TIME >SYSDATE-3条件,执行计划中可进行分区裁剪,删减数据这条路行不通。

WHERE中的条件也正确使用了索引,似乎所有常规优化方法都已用上,如何才能进一步提升存储过程LOOP循环执行速度?

我们再分析这六条SQL,在WHERE条件中都出现了对EMPLOYEE_CONTROL表以下限定条件:

TO_CHAR(INOROUT_TIME,'YYYY/MM/DD')= TO_CHAR(SYSDATE-2,'YYYY/MM/DD') AND INOROUT_TIME >SYSDATE-3 AND TYPE='L' AND TYPE='F'

存储过程实际要读取的只有一天的数据,这部分数据一般只有10万笔为热点数据。如果我们先把此部分数据单独读出,在LOOP循环中就可只读取临时表内容,避免4万次读取有两亿笔数据的EMPLOYEE_CONTROL考勤资料表。

依此思路,我们先建立一个临时表,并为临时表EMP_NO字段添加索引:

CREATE GLOBAL TEMPORARY TABLE CPYTGL.EMPLOYEE_CONTROL_TEMP ON COMMIT DELETE ROWS AS SELECT * FROMCPYTGL.EMPLOYEE_CONTROL WHERE 1 = 0; CREATE INDEX CPYTGL.EMPLOYEE_CONTROL_TEMP_NOON CPYTGL.EMPLOYEE_CONTROL_TEMP (EMP_NO);

再在存储过程头部将符合条件的数据取出:

INSERT INTO cpytgl.EMPLOYEE_CONTROL_TEMP SELECT* FROM CPYTGL.EMPLOYEE_CONTROL WHERE TO_CHAR (INOROUT_TIME, 'YYYY/MM/DD') = TO_CHAR(SYSDATE - 2, 'YYYY/MM/DD') AND INOROUT_TIME > SYSDATE- 3 AND TYPE IN('F', 'L');

这样就可改写消耗资源的六条SQL查询临时表。以第14行SQL为例,需改写为:

--Line14行

SELECT COUNT (*) INTO tmpVar FROM cpytgl.EMPLOYEE_CONTROL_TEMP WHERE EMP_NO = USERID.WORKNO AND TYPE = 'F' AND ROWNUM< 6;

LOOP循环中六条SQL改为查询10万笔记录的临时表后,存储过程只需1分钟即可跑完。相较之前20分钟运行时间有大幅度提升。

此例核心为使用临时表隔离冷热数据。DBA一次调优不一定能想出最佳方法,通过对应用的不断深入观察,以及Oracle工具的合理使用,加上一点点灵光一现那些看似解决不了的难题都可一一化解。

原文发布于微信公众号 - 数据和云(OraNews)

原文发表时间:2017-07-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java呓语

第13.1.1章 语法解释ALTER DATABASE

ALTER DATABASE 允许修改数据库的特征,所有关于数据库的特征都存储在db.opt文件中。你必须先具备该数据库的ALTER特权,才能完成对数据库的AL...

721
来自专栏java工会

十个mysql语句的优化方法

1946
来自专栏PHP在线

MySQL DELETE语句和TRUNCATE TABLE语句的区别

MySQL DELETE语句和TRUNCATE TABLE语句功能相似,但是二者究竟有何区别呢?下文就将为您分析MySQL DELETE语句和TRUNCATE ...

37014
来自专栏Theo Tsao

Ionic3学习笔记(六)存储之使用 SQLite

2891
来自专栏跟着阿笨一起玩NET

(3)合并列值与分拆列值

在SQL中分拆列值和合并列值老生常谈了,从网上搜刮了一下并记录下来,以便不时之需 :)

741
来自专栏互联网开发者交流社区

SQL触发器实例(上)

1494
来自专栏PhpZendo

使用 MySQL Scheduler 和 Event 周期性创建数据表

使用 MySQL Scheduler 和 Event 周期性创建数据表,下面提供的是按月建表计划任务及事件通过 ON SCHEDULE EVERY 1 MINU...

1632
来自专栏撸码那些事

MySQL——索引优化实战

上篇文章中介绍了索引的基本内容,这篇文章我们继续介绍索引优化实战。在介绍索引优化实战之前,首先要介绍两个与索引相关的重要概念,这两个概念对于索引优化至关重要。

884
来自专栏数据分析

[数据库基础]——编码标准之结构

数据库是由若干表构成,表是由数据行构成,数据行由若干列组成。由于数据库这样的结构,这就要求我们在构成数据库表时,需要注意一些问题。现在提出一些注意的问题。 1....

3175
来自专栏乐沙弥的世界

SQL基础--> 数据处理(DML、RETURNING、MERGE INTO)

--=================================================

852

扫码关注云+社区