昨天下午技术部JAVA开发人员报告说 线上数据库无法删除数据,要我查看下数据库是否有什么锁住. 我还以为是死锁或者是什么阻塞之类了.
折腾下没有发现!
叫它把语句发来,他就把表名,而且是截图发过来的!
根据表名去找 删除的语句
SELECT SQL_ID,PIECE,SQL_TEXT
FROM V$SQLTEXT_WITH_NEWLINES
WHERE SQL_ID IN(
SELECT SQL_ID
FROM V$SQLTEXT_WITH_NEWLINES
WHERE SQL_TEXT LIKE '%table_name%')
ORDER BY SQL_ID,PIECE;
发现DELETE开头的语句 共3条 通过语句ID 找出变量
select * from v$sql_bind_capture where sql_id in ('fpkt91ujqu853');
结果是:
gquw3xgbqvu13:
delete from paynum p WHERE INSTR(:1,','||PL_ID||',')>0
2014-3-12 17:44:13
,3251,3250,3248,3247,
2014-3-11 11:56:18
,3249,
b5yjgrqx6j2dm:
delete from paynum paynum WHERE INSTR(:1,''||PL_ID||'')>0
2014-3-13 17:45:02
,3319,
fpkt91ujqu853:
delete from paynum_ELEMENT e WHERE INSTR(:1,','||e.ple_pl_id||',')>0
2014-3-13 17:45:02
,3319,
从上面看 删除paynum有两条不同的SQL语句 第一个估计是旧的,第二个是最近上线的.
根据变量的值 可以了解 先删除 关联表 输入变量 ',3319,' 然后删除PAYNUM表 同样输入变量',3319,'
我们同样可以看出来参数:1 不仅可以输入单个变量值,还可以输入一串变量的值 比如 ',3251,3250,3248,3247,'
从数据表查询3319值的记录 关联表 paynum_ELEMENT 已经被删除,而 PAYNUM 还存在 !
我们综合下
delete from paynum paynum WHERE INSTR(',3319,',''||PL_ID||'') > 0
对于这样的语句 做为地球普通人的我实在难以理解和猜透. 通过自身努力终于理解了它,来之汪星的写法!
select pl_id, INSTR(',3319,',''||PL_ID||'') from paynum;
这样看出先生产个虚拟列,其值 是PL_ID和3319的比较值. 然后这个值是大于0 则删除;
我测试下 它确实能删除记录. 不过线上的行为就表现如下
PL_ID INSTR('3319',''||PL_ID||'')
1 3
31 2
33 1
331 1
3319 1
2279 0
2282 0
2281 0
2280 0
INSTR
(源字符串, 目标字符串, 起始位置, 匹配序号)
在Oracle/PLSQL中,instr函数返回要截取的字符串在源字符串中的位置。只检索一次,就是说从字符的开始
发现了什么没?对没错误 狗屎的家伙 居然写反了 INSTR(',3319,',''||PL_ID||'')
正常写法是INSTR(''||PL_ID||'', ',3319,')
正常设计是:
delete from paynum paynum where paynum.pl_id=to_number(:?)