今天遇到一个有意思的案例,一开发同事告诉我他删除一个表的记录非常慢,已经快1个多小时了还没有完成。而且删除的记录只有1百多条。真是大跌眼镜的一件事情。最后发现该表与多个表有外键关联关系(这个表即是主表、又是从表),最后我禁用引用该表的外键约束后。一秒内删除了记录。然后启用外键约束关系。下面记录、分析一下解决过程的思路(下面是在测试环境的记录,数据量不一样)。

我去处理这个问题时,首先怀疑可能是SQL的阻塞、触发器、外键约束、高水位线等因素中的某一个导致DELETE操作慢,于是我打算一个一个排除,我先试着删除一条记录,然后去检查SQL的阻塞情况,结果使用下面SQL语句并没有发现SQL被阻塞。于是SQL的阻塞导致DELETE慢的原因被我排除了。

SELECT '节点 ' || A.INST_ID || ' SESSION ' || A.SID || ',' || A_S.SERIAL# ||

       ' 阻塞了 节点 ' || B.INST_ID || ' SESSION ' || B.SID || ',' || B_S.SERIAL# BLOCKINFO,

       A.INST_ID,

       A_S.SID,

       A_S.SCHEMANAME,

       A_S.MODULE,

       A_S.STATUS,

       A.TYPE LOCK_TYPE,

       A.ID1,

       A.ID2,

       DECODE(A.LMODE,

              0,

              'NONE',

              1,

              NULL,

              2,

              'ROW-S (SS)',

              3,

              'ROW-X (SX)',

              4,

              'SHARE (S)',

              5,

              'S/ROW-X (SSX)',

              6,

              'EXCLUSIVE (X)') LOCK_MODE,

       

       '后为被阻塞信息' ,

       B.INST_ID BLOCKED_INST_ID,

       B_S.SID BLOCKED_SID,

       B.TYPE BLOCKED_LOCK_TYPE,

       DECODE(B.REQUEST,

              0,

              'NONE',

              1,

              NULL,

              2,

              'ROW-S (SS)',

              3,

              'ROW-X (SX)',

              4,

              'SHARE (S)',

              5,

              'S/ROW-X (SSX)',

              6,

              'EXCLUSIVE (X)') BLOCKED_LOCK_REQUEST,

       B_S.SCHEMANAME BLOCKED_SCHEMANAME,

       B_S.MODULE BLOCKED_MODULE,

       B_S.STATUS BLOCKED_STATUS,

       B_S.SQL_ID BLOCKED_SQL_ID,

       OBJ.OWNER BLOCKED_OWNER,

       OBJ.OBJECT_NAME BLOCKED_OBJECT_NAME,

       OBJ.OBJECT_TYPE BLOCKED_OBJECT_TYPE,

       CASE

          WHEN B_S.ROW_WAIT_OBJ# <> -1 THEN

             DBMS_ROWID.ROWID_CREATE(1,

                                     OBJ.DATA_OBJECT_ID,

                                     B_S.ROW_WAIT_FILE#,

                                     B_S.ROW_WAIT_BLOCK#,

                                     B_S.ROW_WAIT_ROW#) 

          ELSE 

            '-1' 

          END BLOCKED_ROWID, --THE BLOCKED ROWID

       DECODE(OBJ.OBJECT_TYPE,

              'TABLE',

              'SELECT * FROM ' || OBJ.OWNER || '.' || OBJ.OBJECT_NAME ||

              ' WHERE ROWID=''' ||

              DBMS_ROWID.ROWID_CREATE(1,

                                      OBJ.DATA_OBJECT_ID,

                                      B_S.ROW_WAIT_FILE#,

                                      B_S.ROW_WAIT_BLOCK#,

                                      B_S.ROW_WAIT_ROW#) || '''',

              NULL)  BLOCKED_DATA_QUERYSQL

  FROM GV$LOCK     A,

       GV$LOCK     B,

       GV$SESSION  A_S,

       GV$SESSION  B_S,

       DBA_OBJECTS OBJ

 WHERE A.ID1 = B.ID1

   AND A.ID2 = B.ID2

   AND A.BLOCK > 0 --BLOCK THE OTHER SQL

   AND B.REQUEST > 0

   AND ((A.INST_ID = B.INST_ID AND A.SID <> B.SID) OR

       (A.INST_ID <> B.INST_ID))

   AND A.SID = A_S.SID

   AND A.INST_ID = A_S.INST_ID

   AND B.SID = B_S.SID

   AND B.INST_ID = B_S.INST_ID

   AND B_S.ROW_WAIT_OBJ# = OBJ.OBJECT_ID(+)

 ORDER BY A.INST_ID,A.SID;

接下来,我检查了该表的的触发器,结果并没有发现DELETE触发器。也就是说DELETE操作并不会触发任何触发器。触发器导致DELETE慢的怀疑也可以排除掉了。

SELECT * FROM DBA_TRIGGERS WHERE TABLE_NAME='INV_LOCATION_PALLETS'

我用show_space检查了一下这个表的高水位线,发现并没有问题,不需要收缩高水位线。高水位线这个因素也可以排除了。只剩下外键约束的影响了。于是检查了一下有哪些表是该表的从表,如下所示

SELECT /*+RULE*/ D.CONSTRAINT_NAME PK_NAME,

                 D.TABLE_NAME 

                 || '.' 

                 || D.COLUMN_NAME  PK_COLUMN,

                 A.CONSTRAINT_TYPE,

                 B.CONSTRAINT_NAME FK_NAME,

                 B.TABLE_NAME 

                 || '.' 

                 || B.COLUMN_NAME  FK_COLUMN

FROM   DBA_CONSTRAINTS A 

       JOIN DBA_CONS_COLUMNS B 

         ON A.CONSTRAINT_NAME = B.CONSTRAINT_NAME

            AND A.OWNER = B.OWNER

       JOIN DBA_CONSTRAINTS C 

         ON A.R_CONSTRAINT_NAME = C.CONSTRAINT_NAME

            AND A.R_OWNER = C.OWNER

       JOIN DBA_CONS_COLUMNS D 

         ON C.CONSTRAINT_NAME = D.CONSTRAINT_NAME

            AND C.OWNER = D.OWNER

WHERE  D.TABLE_NAME = 'INV_LOCATION_PALLETS' 

有时候也可以用下面语句查看引用这个表的外键引用关系

SELECT * FROM DBA_CONSTRAINTS WHERE R_CONSTRAINT_NAME='PK_INV_LOCATION_PALLETS'

如上所示,INV_LOCATION_PALLETS这个表有三个从表,而这里面有个表的记录很大,大概2千多万。所以导致DELETE操作很慢。

我们可以用跟踪当前会话,查看一下DELETE操作,就会发现它会去处理从表,检查从表有没有对应的记录,而这个外键刚好也没有索引(下面是使用tkprof命令格式化的内容)。在这篇Delete the data on the table very slow(删除数据慢)博客里面跟深入的介绍、分析了删除表删除数据慢的原因。在此不做过多赘述了。

DELETE INVENTORY.INV_LOCATION_PALLETS  

WHERE

 PALLET_ID =1039928

 

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          3         26           1

Fetch        0      0.00       0.00          0          0          0           0

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

total        2      0.00       0.01          0          3         26           1

 

Misses in library cache during parse: 1

Optimizer mode: ALL_ROWS

Parsing user id: 5  

 

Rows     Row Source Operation

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

      1  DELETE  INV_LOCATION_PALLETS (cr=752149 pr=735050 pw=0 time=7550289 us)

      1   INDEX UNIQUE SCAN PK_INV_LOCATION_PALLETS (cr=3 pr=0 pw=0 time=38 us)(object id 59532)

 

********************************************************************************

 

select /*+ all_rows */ count(1) 

from

 "INVENTORY"."INV_REQ_HD" where "TO_PALLET_ID" = :1

 

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        1      0.75       0.74      70540      78205          0           1

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

total        3      0.75       0.74      70540      78205          0           1

 

Misses in library cache during parse: 0

Optimizer mode: ALL_ROWS

Parsing user id: SYS   (recursive depth: 1)

 

Rows     Row Source Operation

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

      1  SORT AGGREGATE (cr=78205 pr=70540 pw=0 time=743169 us)

      0   TABLE ACCESS FULL INV_REQ_HD (cr=78205 pr=70540 pw=0 time=743155 us)

 

********************************************************************************

 

select /*+ all_rows */ count(1) 

from

 "INVENTORY"."INV_REQ_HD" where "FROM_PALLET_ID" = :1

 

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        1      0.69       0.67      70528      78205          0           1

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

total        3      0.69       0.68      70528      78205          0           1

 

Misses in library cache during parse: 0

Optimizer mode: ALL_ROWS

Parsing user id: SYS   (recursive depth: 1)

 

Rows     Row Source Operation

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

      1  SORT AGGREGATE (cr=78205 pr=70528 pw=0 time=680000 us)

      0   TABLE ACCESS FULL INV_REQ_HD (cr=78205 pr=70528 pw=0 time=679987 us)

 

********************************************************************************

 

select /*+ all_rows */ count(1) 

from

 "INVENTORY"."INV_REQ_LINES" where "TO_PALLET_ID" = :1

 

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        1      3.30       3.23     296991     297868          0           1

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

total        3      3.30       3.23     296991     297868          0           1

 

Misses in library cache during parse: 0

Optimizer mode: ALL_ROWS

Parsing user id: SYS   (recursive depth: 1)

 

Rows     Row Source Operation

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

      1  SORT AGGREGATE (cr=297868 pr=296991 pw=0 time=3232134 us)

      0   TABLE ACCESS FULL INV_REQ_LINES (cr=297868 pr=296991 pw=0 time=3232122 us)

 

********************************************************************************

 

select /*+ all_rows */ count(1) 

from

 "INVENTORY"."INV_REQ_LINES" where "FROM_PALLET_ID" = :1

 

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.00       0.00          0          0          0           0

Fetch        1      2.94       2.88     296991     297868          0           1

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

total        3      2.94       2.88     296991     297868          0           1

 

Misses in library cache during parse: 0

Optimizer mode: ALL_ROWS

Parsing user id: SYS   (recursive depth: 1)

 

Rows     Row Source Operation

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

      1  SORT AGGREGATE (cr=297868 pr=296991 pw=0 time=2885783 us)

      0   TABLE ACCESS FULL INV_REQ_LINES (cr=297868 pr=296991 pw=0 time=2885772 us)

 

********************************************************************************

 

begin

  sys.dbms_output.get_line(line => :line, status => :status);

end;

 

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        4      0.00       0.00          0          0          0           0

Execute      4      0.00       0.00          0          0          0           4

Fetch        0      0.00       0.00          0          0          0           0

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

total        8      0.00       0.00          0          0          0           4

 

Misses in library cache during parse: 0

Optimizer mode: ALL_ROWS

Parsing user id: 5  

 

参考资料

http://www.anbob.com/archives/1962.html/comment-page-1

ORACLE DELETE数据慢的案例的更多相关文章

  1. 关于 Oracle 的数据导入导出及 Sql Loader (sqlldr) 的用法

    在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法: 1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中2. 建立数据库间的 ...

  2. Oracle 删除数据后释放数据文件所占磁盘空间

    测试的时候向数据库中插入了大量的数据,测试完成后删除了测试用户以及其全部数据,但是数据文件却没有缩小.经查阅资料之后发现这是 Oracle “高水位”所致,那么怎么把这些数据文件的大小降下来呢?解决办 ...

  3. mysql数据库delete数据时不支持表别名

    今天在帮同事查看一条删除的SQL语句执行出错的问题 SQL语句如下: 1 DELETE FROM LEAD_SYSTEM_MENU_ORG_REF as t WHERE t.resourceid='4 ...

  4. Android清除本地数据缓存代码案例

    Android清除本地数据缓存代码案例 直接上代码: /*  * 文 件 名:  DataCleanManager.java  * 描    述:  主要功能有清除内/外缓存,清除数据库,清除shar ...

  5. 转】mysql数据库delete数据时不支持表别名

    原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4012853.html 感谢! 今天在帮同事查看一条删除的SQL语句执行出错的问题 SQL语句如下: 1 DELE ...

  6. 关于oracle误删数据的恢复

    与数据打交道,免不了会误删一些数据,之后还commit了,连回滚的机会都没了,而更糟糕的是你又没有备份,这种事终于在今天被我不幸的遇上了... 唯一一点值得欣慰的是,我删除表记录的时候,时间不长,一天 ...

  7. oracle误删除数据的恢复方法

    学习数据库时,我们只是以学习的态度,考虑如何使用数据库命令语句,并未想过工作中,如果误操作一下,都可能导致无可挽回的损失.当我在工作中真正遇到这些问题时,我开始寻找答案. 今天主要以oracle数据库 ...

  8. [转]oracle误删数据的恢复

    与数据打交道,免不了会误删一些数据,之后还commit了,连回滚的机会都没了,而更糟糕的是你又没有备份,这种事终于在今天被我不幸的遇上了... 唯一一点值得欣慰的是,我删除表记录的时候,时间不长,一天 ...

  9. Win环境下Oracle小数据量数据库的物理备份

    Win环境下Oracle小数据量数据库的物理备份 环境:Windows + Oracle 单实例 数据量:小于20G 重点:需要规划好备份的路径,建议备份文件和数据库文件分别存在不同的存储上. 1.开 ...

随机推荐

  1. golang开发环境配置及Beego框架安装

    配置环境:Windows7推荐IDE:LiteIDEGO下载地址:http://www.golangtc.com/downloadBeego开发文档地址:http://beego.me/docs/in ...

  2. my SQL下载安装,环境配置,以及密码忘记的解决,以及navicat for mysql下载,安装,测试连接

    一.下载 在百度上搜索"mysql-5.6.24-winx64下载" 二.安装 选择安装路径,我的路径“C:\Soft\mysql-5.6.24-winx64” 三.环境配置 计算 ...

  3. C#动态调用WCF接口,两种方式任你选。

    写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这 ...

  4. 大型网站提速关键技术(页面静态化,memcached,MySql优化)(一)

    一:关键技术介绍: 衡量是否为大型网站的要素: A:PV值(page views 页面浏览量) 访问量大: 带来的问题:1:流量大 -->解决方案:增加带宽,优化程序(视频和图片较浪费带宽,尽量 ...

  5. Web 上传图片加水印

    上传图片加水印 需要使用控件FileUpload 上传按钮Image控件展示上传的图片,页面中拖入三个控件 <form id="form1" runat="serv ...

  6. 【Win10开发】如何在页面之间传值

    我们知道UWP是通过不同的页面来展示不同的内容的,那么我们该怎么进行页面之间的传值呢? 首先我们在MainPage里面写一个ListView来展示一些英文单词. List<English> ...

  7. Entity Framework 6 开发系列 目录

    2014 年开始接触 Entity Framework 6 也快两年,用它已经沉淀了一个成熟架构,也用来开发了不少大大小小的产品和项目,直到这段时间,才真正有时间来回顾,重新学习它,为让大家更加了解E ...

  8. iOS开发之CocoaPods的安装与使用

    前言部分 iOS开发时,项目中会引用许多第三方库,CocoaPods(https://github.com/CocoaPods/CocoaPods) 可以用来方便的统一管理这些第三方库. 一.安装 由 ...

  9. C#基础-压缩文件及故障排除

    C#压缩文件可以使用第三方dll库:ICSharpCode.SharpZipLib.dll: 以下代码能实现文件夹与多个文件的同时压缩.(例:把三个文件夹和五个文件一起压缩成一个zip) 直接上代码, ...

  10. should be mapped with insert="false" update="false

    SSH项目出现了 should be mapped with insert="false" update="false 错误,仔细检查后发现,是两个不同的属性映射了表中的 ...