ORACLE DELETE数据慢的案例
今天遇到一个有意思的案例,一开发同事告诉我他删除一个表的记录非常慢,已经快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数据慢的案例的更多相关文章
- 关于 Oracle 的数据导入导出及 Sql Loader (sqlldr) 的用法
在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法: 1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中2. 建立数据库间的 ...
- Oracle 删除数据后释放数据文件所占磁盘空间
测试的时候向数据库中插入了大量的数据,测试完成后删除了测试用户以及其全部数据,但是数据文件却没有缩小.经查阅资料之后发现这是 Oracle “高水位”所致,那么怎么把这些数据文件的大小降下来呢?解决办 ...
- mysql数据库delete数据时不支持表别名
今天在帮同事查看一条删除的SQL语句执行出错的问题 SQL语句如下: 1 DELETE FROM LEAD_SYSTEM_MENU_ORG_REF as t WHERE t.resourceid='4 ...
- Android清除本地数据缓存代码案例
Android清除本地数据缓存代码案例 直接上代码: /* * 文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除shar ...
- 转】mysql数据库delete数据时不支持表别名
原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4012853.html 感谢! 今天在帮同事查看一条删除的SQL语句执行出错的问题 SQL语句如下: 1 DELE ...
- 关于oracle误删数据的恢复
与数据打交道,免不了会误删一些数据,之后还commit了,连回滚的机会都没了,而更糟糕的是你又没有备份,这种事终于在今天被我不幸的遇上了... 唯一一点值得欣慰的是,我删除表记录的时候,时间不长,一天 ...
- oracle误删除数据的恢复方法
学习数据库时,我们只是以学习的态度,考虑如何使用数据库命令语句,并未想过工作中,如果误操作一下,都可能导致无可挽回的损失.当我在工作中真正遇到这些问题时,我开始寻找答案. 今天主要以oracle数据库 ...
- [转]oracle误删数据的恢复
与数据打交道,免不了会误删一些数据,之后还commit了,连回滚的机会都没了,而更糟糕的是你又没有备份,这种事终于在今天被我不幸的遇上了... 唯一一点值得欣慰的是,我删除表记录的时候,时间不长,一天 ...
- Win环境下Oracle小数据量数据库的物理备份
Win环境下Oracle小数据量数据库的物理备份 环境:Windows + Oracle 单实例 数据量:小于20G 重点:需要规划好备份的路径,建议备份文件和数据库文件分别存在不同的存储上. 1.开 ...
随机推荐
- 虚拟机利用Host-only实现在不插网线的情况下,虚拟机与主机实现双向通信,实现ssh连接以及samba服务实现共享
为了不影响其他的虚拟网卡,我们在VMware下在添加一块虚拟网卡: 然后点击Next,选择连接方式: 点击Finish即可. 重新启动虚拟机,如果这是你手动添加的第一块虚拟网卡,那么应该是eth1. ...
- Oracle11g中数据的倒库和入库操作以及高版本数据导入低版本数据可能引发的问题
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在10g之前,传统的导出和导入分别使用EXP工具和IMP工具 ...
- 理解JAVASCRIPT 闭包
最近去面试了一家企业,结果非常灰心丧气,于是周末给自己定了一个目标 学好一门,学精通一门.不求多,只求懂. 最近看到一个概念“闭包”. 什么是闭包呢? 简单一点就是:看得到多和看得到少的区别. 上面这 ...
- jQuery打造智能提示插件
插件根据实际需要在单功能上封装的,实现传入后台数据地址,要保存值的input,前台要传入的参数(过滤条件),来返回下拉提示数据,数据过多可上下滚动选择,选择后显示文本与对应的值,供后台操作,如图: j ...
- SQL Server 2016 SP1 标准版等同企业版?!
上周微软发布了SQL Server的历史性公告:SQL Server 标准版的SP1提供你和企业版一样得功能.你不信的话?可以点击这里. 这改变了整个关系数据库市场,重重打击了Oracle.在今天的文 ...
- jenkins中使用tfs插件做增量的版本发布部署
一 配置介绍 使用jenkins的tfs插件进行,源码的下载,编译,打包的操作,然后使用windows的批处理命令,在局域网内(或者本机)把打包的release包,删除掉web.config,然后靠配 ...
- jquery 文本/html/值
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- virtualbox 虚拟机Ubuntu 传文件-共享
- MySQL 相关总结
MySQL 优秀在线教程 RUNOOB-SQL 教程 MySQL 常用命令 导出操作 -- 某数据库 全部表 结构和数据 mysqldump -h192.168.8.152 -uroot -p man ...
- 一元多项式的乘法与加法运算(C语言)
输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数).数字间以空格分隔. 输出格式: 输出分2行,分别以指数递降方 ...