生产库故障分析(主外键和DML性能分析)

原创 转载请注明出处

(我的学习笔记)   

公司生产库2009年06月18日,出现批处理(JOB)阻塞了大量的用户操作,具体表现就是大量的表备锁做,并且CPU资源消耗达到了60%,让整个系统变慢,此时间长达30分钟。

出现问题后,我首先查看了系统使用有大事物的存在:

select username,opname,

round(((totalwork-sofar)/totalwork),4)*100 "pct_remaining"

from V$session_Longops

WHERE TIME_REMAINING >0;

看到有大的的FULL SCAN 也就是全表扫描存在,当然这样也看不出来问题的所在,然后进行了4点到5点的AWRRPT,报告截图如下

WORKLOAD REPOSITORY report for


DB Name


DB Id


Instance


Inst num


Release


RAC


Host


GELCPRO


4091276223


GELCPRO


1


10.2.0.1.0


NO


D0-LNXDB01

 


 


Snap Id


Snap Time


Sessions


Cursors/Session


Begin Snap:


26795


18-Jun-09 15:00:32


46


11.3


End Snap:


26796


18-Jun-09 16:00:56


45


6.8


Elapsed:


 


60.40 (mins)


 


 


DB Time:


 


63.25 (mins)


 


 

 

Top 5 Timed Events


Event


Waits


Time(s)


Avg Wait(ms)


% Total Call Time


Wait Class


CPU time


 


3,733


 


98.4


 


ARCH wait on SENDREQ


502


934


1,861


24.6


Network


log file parallel write


8,365


107


13


2.8


System I/O


log file sync


4,470


62


14


1.6


Commit


control file parallel write


2,717


17


6


.4


System I/O

 

可以看到数据库的负载是比较重的,而且问题出现时CPU大量消耗,感觉有CPU密集型的语句正在运行

然后查看TOP CPU SQL,和TOP time sql

 

SQL ordered by Elapsed Time

  • Resources reported for PL/SQL code includes the resources used by all SQL statements called by the code.
  • % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100

Elapsed Time (s)


CPU Time (s)


Executions


Elap per Exec (s)


% Total DB Time


SQL Id


SQL Module


SQL Text


1,788


1,785


121


14.78


47.11


0sf192fw73ds9


 


DECLARE job BINARY_INTEGER := ...


1,780


1,779


1


1779.55


46.89


7s2s60d6c6tk7


 


begin pkg_ls_chl_com.p_backgro...


1,279


1,279


1


1279.34


33.71


cw1bax526a9am


 


DELETE T_COMMISION_INFO CI WHE...


1,137


1,125


114,068


0.01


29.95


3t3c1ju68qvkc


 


select /*+ all_rows */ count(...

 

 

SQL ordered by CPU Time

  • Resources reported for PL/SQL code includes the resources used by all SQL statements called by the code.
  • % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100

CPU Time (s)


Elapsed Time (s)


Executions


CPU per Exec (s)


% Total DB Time


SQL Id


SQL Module


SQL Text


1,785


1,788


121


14.75


47.11


0sf192fw73ds9


 


DECLARE job BINARY_INTEGER := ...


1,779


1,780


1


1778.72


46.89


7s2s60d6c6tk7


 


begin pkg_ls_chl_com.p_backgro...


1,279


1,279


1


1279.08


33.71


cw1bax526a9am


 


DELETE T_COMMISION_INFO CI WHE...


1,125


1,137


114,068


0.01


29.95


3t3c1ju68qvkc


 


select /*+ all_rows */ count(...

 

根据报告可以确定问题语句的大概范围。

 

 

1、DECLARE job BINARY_INTEGER := :job; next_date DATE := :mydate; broken BOOLEAN := FALSE; BEGIN pkg_life_public_back_process.p_run(2, 2); :mydate := next_date; IF broken THEN :b := 1; ELSE :b := 0; END IF; END;

2、begin pkg_ls_chl_com.p_background_cal_commision(:1, :2, :3); end;

3、DELETE T_COMMISION_INFO CI WHERE CI.AGGREGATION_ID = :B1

4、select /*+ all_rows */ count(1) from "GELC_PROD"."T_COMMISSION_FEE" where "COMMISION_ID" = :1

 

 

其实前面两个语句也许不是问题的重点,然后通过日志挖掘挖掘日志4点到5点的时候日志切换最频繁的时候时间大概在5分钟以内切换的3个日志,发现出现了大量的DML语句,主要集中在两个表上

 

select seg_name,count(seg_name) count from v$logmnr_contents group by seg_name order by  count;

SEG_NAME                         COUNT

---------------------------------------

T_STAND_PREM_DETAIL              2028

T_SESSION_TRACE                  2096

SEQ$                             11245

T_PERFORMANCE_INFO               109267

T_COMMISION_INFO                 157757

AUD$                             249216

这里给出了最后6行,而AUD$是审计表,T_PERFORMANCE_INFO在AWRRPT中并没有设计到,可以确定T_PERFORMANCE_INFO虽然DML次数多但是没有引起性能问题,剩下的就是T_COMMISION_INFO了,进一步查看:

SQL> select substrb(sql_redo,1,50) su,count(substrb(sql_redo,1,50)) te from v$logmnr_contents where SEG_NAME='T_COMMISION_INFO'

  2  group by substrb(sql_redo,1,50) order by te ;

 

SU                                                         TE

-------------------------------------------------- ----------

update "GELC_PROD"."T_COMMISION_INFO" set "COMM_ST       4609

delete from "GELC_PROD"."T_COMMISION_INFO" where "         14503

update "GELC_PROD"."T_COMMISION_INFO" set "MONEY"       23081

Unsupported                                                 25651

insert into "GELC_PROD"."T_COMMISION_INFO"("COMMIS      89913

 

这里出现了AWRRPT中指出的语句delete from "GELC_PROD"."T_COMMISION_INFO" where ",所以我确定真正的性能问题出在这里,因为日志挖掘和AWRRPT同时出现这样的语句。

 

进一步分析发现T_COMMISION_INFO表的数据量是比较大了10W以上,当然这里我觉得也不是问题所在,单一的一张表进行DELETE也不会出现如此的等待,然后我想可能是此表中的主键关联了大量的子表,在进行删除的时候,每一条记录中的主键都会去匹配子表,如果主表中的记录在子表中有引用,就会报错,如果没有引用才能被删除,这样如果子表的外键中不存在相应的索引就会进行全表扫描,引起大量的等待,而且会锁住子表,最初看到的多个表被锁住,也许就是这样引起的,当然如果一切成立最初看到的大事物的全表扫描,也是因为子表的全表扫描引起的。

通过语句

select CONSTRAINT_NAME,TABLE_NAME from dba_constraints where CONSTRAINT_TYPE='R' AND R_CONSTRAINT_NAME='PK_T_COMMISION_INFO';

发现了确实有6张表都引用了此表中的主键,这样没删除一条数据就会去全表扫描这6张表,

T_COMMISSION_FEE   

T_COUNT_DEPT_AWARD

T_PRODUCT_COMMISION

T_COMMISION_DETAIL

T_ADJUST_AWARD

T_REMAIN_COMM   

其中T_COMMISSION_FEE 有10w多条数据

T_PRODUCT_COMMISION 有3W多条数据

 

为了证明问题确实出在这里,在开发环境中我也做了试验,在T_COMMISSION_FEE插入了4W多条数据,然后开启SQL_TRACE后,用TKPROF进行格式化查看,

我使用的语句是

delete gelcdev216.T_COMMISION_INFO where COMMISION_ID>50000;

虽然这条语句报错了但是丝毫没有引向结果。

当T_COMMISSION_FEE 中 COMMISION_ID没有加索引的情况下,这条语句重启动到失败共耗时8秒,

并且TKPROF报告看到了这样的情况

select /*+ all_rows */ count(1)

from

 "GELCDEV216"."T_COMMISSION_FEE" where "COMMISION_ID" = :1

 

 

call     count       cpu    elapsed       disk      query    current        rows

------- ------  -------- ---------- ---------- ---------- ----------  ----------

Parse        1      0.00       0.00          0          0          0           0

Execute   1274      0.02       0.03          0          0          0           0

Fetch     1274      7.91       7.75          0     718536          0        1274

------- ------  -------- ---------- ---------- ---------- ----------  ----------

total     2549      7.94       7.79          0     718536          0        1274

 

这个消耗是比较严重的,而且我只是做的其中很小的一部分,而且

select /*+ all_rows */ count(1)  from "GELCDEV216"."T_COMMISSION_FEE" where "COMMISION_ID" = :1

正是在AWRRPT中出现的

select /*+ all_rows */ count(1) from "GELC_PROD"."T_COMMISSION_FEE" where "COMMISION_ID" = :1

就是因为大量的进行一致性验证而导致的语句,当然起初看到的全表扫描也是对子表的全表扫描,况且大量的锁出现部分也是由于这里的问题。

当我在T_COMMISSION_FEE 中 COMMISION_ID建立索引过后运行同样的语句

delete gelcdev216.T_COMMISION_INFO where COMMISION_ID>50000;

 

时间只是0.5秒,而且在TKPROF中也不会出现相应扫描子表的语句,因为现在会去扫描新建的索引。

 

所以我觉得解决这个问题的方法就是在相应的数据较大的子表中建立索引,避免出现全表扫描,也不会去锁表,因为现在扫描的仅仅是索引中的块而已。方法及如下:

CREATE  INDEX  ****  ON T_COMMISSION_FEE(COMMISION_ID);

CREATE  INDEX  ****  ON T_PRODUCT_COMMISION(COMMISION_ID);

 

也许一条DELETE不会引起性能问题,但是如果进行批量的DELETE那小小的问题将会被放大很多。。。

时间: 2024-09-11 05:22:26

生产库故障分析(主外键和DML性能分析)的相关文章

[20151231]主外键与空表.txt

[20151231]主外键与空表.txt --主外键的测试例子很多,今天做一个特别的,外部键表为空,也会出现阻塞吗?测试看看. 1.建立环境: SCOTT@book> @ &r/ver1 PORT_STRING                    VERSION        BANNER ------------------------------ -------------- -------------------------------------------------------

[20160719]主外键与延迟约束2.txt

[20160719]主外键与延迟约束2.txt --前几天遇到的问题,因为开发没有在2个存在主外键上的表上建立约束,导致主表记录删除了,而外表数据还在. --主要开发有需求要删除主表的记录,由于条件写错,导致以上情况出现.实际上oracle支持延迟约束,只有提交的时候才会检查. --自己通过例子说明: 1.环境: SCOTT@book> @ &r/ver1 PORT_STRING                    VERSION        BANNER ---------------

[20151231]主外键与空表(12c).txt

[20151231]主外键与空表(12c).txt --主外键的测试例子很多,今天做一个特别的,外部键表为空,也会出现阻塞吗?测试看看. 1.建立环境: SCOTT@test01p> @ver1 PORT_STRING                    VERSION        BANNER                                                                               CON_ID --------------

[20160616]IOT与主外键.txt

[20160616]IOT与主外键.txt https://ilmarkerm.eu/blog/2016/06/interesting-difference-in-foreign-key-locking-behavior-between-heap-and-index-organized-tables --许多人都知道主外键引起的阻塞或者死锁,如果主表是IOT呢? IOT实际上一种特殊的索引结构,测试看看. 1.环境: SCOTT@book> @ &r/ver1 PORT_STRING    

城市,区县,地址,没有主外键区分,没有父级ID,所以数据在一个表如何实现级联查询?

问题描述 城市,区县,地址,没有主外键区分,没有父级ID,所以数据在一个表如何实现级联查询? 城市,区县,地址,没有主外键区分,没有父级ID,所以数据在一个表如何实现级联查询? 解决方案 一般这样的情况都是三张表.如果你要放在一张表里面,那么你肯定会有一个父级ID的呀.不然怎么区分,怎么级联? 解决方案二: 都在一个表,我也很纳闷,接手的项目数据库是这样,表示压力好大 解决方案三: 一般不是全在一张表,用level和parentId来区分关联:就是三张表,parentId关联. 没有parent

在PowerDesigner中设计物理模型1——表和主外键

原文:在PowerDesigner中设计物理模型1--表和主外键 在PD中建立物理模型由以下几种办法: 直接新建物理模型. 设计好概念模型,然后由概念模型生成物理模型. 设计好逻辑模型,然后由逻辑模型生成物理模型. 使用逆向工程的方法,连接到现有的数据库,由数据库生成物理模型. 物理模型能够直观的反应出当前数据库的结构.在数据库中的表.视图.存储过程等数据库对象都可以在物理模型中进行设计.由于物理模型和数据库的一致性,接下来以数据库对象和物理模型对象的对应来一一介绍: 表 新建物理模型时需要指定

数据库该如何设计 主外键应该怎么建

问题描述 数据库该如何设计 主外键应该怎么建 现在想做一个类似糗事百科的网站 数据库不知道怎么弄 求大神帮忙! 解决方案 简单来说,主键就是在1对多关系中1的那个,外键就是多的那个.比如两个表:User表有id,Topic表有userid,那么前者是主键,后者是外键. 解决方案二: 其实要做得简单的话,直接几个表就OK了 一个糗事记录表 ID 内容 一个糗事详细记录表 ID 内容 分类(热门.精华.....) 其他一些需要加的内容 踩还是赞 一个评论表 ID 楼层 评论内容 图片路径 踩还是赞

C# 数据库dataGridView刷新数据和主外键判断

本文主要讲诉在使用VS2012+SQL Server数据库做系统中,通常会遇到几个问题.使用dataGridView控件在修改.删除.插入数据后,怎样刷新数据显示操作后的结果.同时在对数据操作时通常会判断数据的主键是否存在或重复,判断外键是否重复,这几个问题我推荐使用函数的形式完成,同时推荐一个操作格式,下面将详细介绍. 一.dataGridView刷新数据 如下图所示,在数据库中删除一个数据或插入一个数据,我们都希望能够在左边的dataGridView控件中显示操作后的内容,而使用dataGr

powerdesigner-【新兵营】PowerDesigner中如何生成的Ldm只有主外键

问题描述 [新兵营]PowerDesigner中如何生成的Ldm只有主外键 大家好!我想请问下PowerDesigner中如何生成的Ldm只有主外键,例如这样的![图片说明](http://img.ask.csdn.net/upload/201602/17/1455699737_92325.jpg) 每张表都只显示外键跟主键,并且表明他们的关系, 谢谢大家!祝大家新年快乐! 解决方案 用的比较少:看看这个文章吧!http://blog.csdn.net/zhang6622056/article/