查看: 6142|回复: 6

删除数据引发ERROR 1213 (40001) at line 7: Deadlock found when trying

[复制链接]
论坛徽章:
18
授权会员
日期:2005-10-30 17:05:33美羊羊
日期:2015-03-04 14:48:58马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11紫蜘蛛
日期:2012-02-21 15:06:16嫦娥
日期:2012-02-21 15:05:212012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282009日食纪念
日期:2009-07-22 09:30:00数据库板块每日发贴之星
日期:2009-02-26 01:01:03
跳转到指定楼层
1#
发表于 2011-8-27 17:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
3抬在线高并发主机系统全部linux  a b c
c 为数据库服务器(mysql 5.0.45)。  a b 为web服务器.
c 做一个500万表的存储过程删除旧数据的时候,有时候会引发
( 用存储过程删除大表 。循环 每次1万条提交)ERROR 1213 (40001) at line 7: Deadlock found when trying 、

大致原因是c 做该表删除的时候,a b 同时还是每秒都在插入批数据到c 表中, 该表为innodb 引擎 无pk.
索引少.  推测是删除每次1万条的时候,innodb的默认cluster引擎数据数据指针移位 与插入的新数据有冲突.行锁冲突
每秒这个表新增数据从几十到几百.(我删除的时候是负载最低时候 每秒不到200条新增)

在测试机器基本上几个月看不到1次,在线
有2台在线服务器其中1台压力很大的机器(8g)的半个月可以看到1次这个ERROR 1213 (40001) at line 7: Deadlock found when trying 、
另外1台压力小机器(12g)半年看不到1次.

提交记录数据从10万参考io 降到1万, 但是偶尔还是能发现ERROR 1213 (40001) at line 7: Deadlock found when trying 、
整个删除机制能用但总是不能断ERROR 1213 (40001) at line 7: Deadlock found when trying?  

不知道有没有更好的方法来除掉这个Deadlock ?

[ 本帖最后由 liyihongcug 于 2011-8-27 17:10 编辑 ]
论坛徽章:
52
2015年新春福章
日期:2015-03-06 11:57:312012新春纪念徽章
日期:2012-02-13 15:12:252012新春纪念徽章
日期:2012-02-13 15:12:25生肖徽章2007版:龙
日期:2012-02-07 10:33:22生肖徽章2007版:龙
日期:2012-02-07 10:33:22生肖徽章2007版:龙
日期:2012-02-07 10:33:22生肖徽章2007版:龙
日期:2012-02-07 10:33:22生肖徽章2007版:龙
日期:2012-02-07 10:33:22生肖徽章2007版:龙
日期:2012-02-07 10:32:552012新春纪念徽章
日期:2012-02-07 09:59:35
2#
发表于 2011-8-27 19:48 | 只看该作者

回复 #1 liyihongcug 的帖子

该表为innodb 引擎 无pk............先给此表增加一个自增序列,5.0.45有了自增序列在做INSERT的时候有可能稍微慢一点,跟AUTO-INCREMENT全局锁释放机制有关系


若非一直大规模插入,不会出现性能瓶颈

存过过程,根据主键去删除C表的数据....不要1W一条提交一次,事务越大,越容易造成死锁的发生,为此,建议100条DELETE提交一次....

使用道具 举报

回复
论坛徽章:
18
授权会员
日期:2005-10-30 17:05:33美羊羊
日期:2015-03-04 14:48:58马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11紫蜘蛛
日期:2012-02-21 15:06:16嫦娥
日期:2012-02-21 15:05:212012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282009日食纪念
日期:2009-07-22 09:30:00数据库板块每日发贴之星
日期:2009-02-26 01:01:03
3#
 楼主| 发表于 2011-8-29 14:00 | 只看该作者
去年内存加到8g。 测试删除1万不到1秒的
不能用主键 。 因为用存储过程删除大表(是2个表的join删除。主键不是一个id, 这个业务相对还是很复杂的 )
用了2台mysql缓存库(web) 1台中心历史库

初期删除数据是2000提交, 后来发现他写人有时候几百。这样删太少有时候几分钟过去 数据不仅没有减少 反倒增加------这个确实是真的

使用道具 举报

回复
论坛徽章:
31
ITPUB十周年纪念徽章
日期:2011-09-27 16:32:49复活蛋
日期:2011-08-29 16:40:11蛋疼蛋
日期:2011-09-27 17:33:29双黄蛋
日期:2011-09-27 17:32:572011新春纪念徽章
日期:2011-02-18 11:43:352010广州亚运会纪念徽章:羽毛球
日期:2010-12-20 14:07:192010广州亚运会纪念徽章:游泳
日期:2010-11-18 16:21:47兰博基尼
日期:2013-07-30 13:51:34日产
日期:2013-07-29 10:18:002013年新春福章
日期:2013-02-25 14:51:24
4#
发表于 2011-8-29 14:48 | 只看该作者
如果可以忽略Deadlock ,
可以存储过程中加上DECLARE Handler定义错误的处理办法;处理的过程可以定义为继续执行和中断

使用道具 举报

回复
论坛徽章:
18
授权会员
日期:2005-10-30 17:05:33美羊羊
日期:2015-03-04 14:48:58马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11紫蜘蛛
日期:2012-02-21 15:06:16嫦娥
日期:2012-02-21 15:05:212012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282009日食纪念
日期:2009-07-22 09:30:00数据库板块每日发贴之星
日期:2009-02-26 01:01:03
5#
 楼主| 发表于 2011-8-29 15:10 | 只看该作者
找到原因了。
不可以忽略的
如果可以忽略Deadlock ,
可以存储过程中加上DECLARE Handler定义错误的处理办法;处理的过程可以定义为继续执行和中断

因为实际测试发现有死锁的时候她会继续向下执行其他sql语句我的存储过程是 这样的

主存储过程
for 循环几千次
调用辅助存储过程 ---------------------------该存储过程一次删除1万

实际是独立的辅助存储过程发生死锁
我是在 shell 代码里调用这个存储过程的 。  他发生死锁但是实际上他还会继续向下执行其他 脚本。

现在思考改如何让这个shell 一旦有死锁马上退出。不在执行下面的 其他 脚本内容。 如果shell脚本或者存储过程能够实在有错误就退出不再执行下面内容就好了

[ 本帖最后由 liyihongcug 于 2011-8-29 15:13 编辑 ]

使用道具 举报

回复
论坛徽章:
18
授权会员
日期:2005-10-30 17:05:33美羊羊
日期:2015-03-04 14:48:58马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11紫蜘蛛
日期:2012-02-21 15:06:16嫦娥
日期:2012-02-21 15:05:212012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282009日食纪念
日期:2009-07-22 09:30:00数据库板块每日发贴之星
日期:2009-02-26 01:01:03
6#
 楼主| 发表于 2011-8-29 18:59 | 只看该作者
MySQL存储过程 ERROR Handler 异常处理
问题样例:当insert失败时,我希望将其记录在日志文件中,

       》》在这里需要创建一个主键表,以及一个外键表,我们使用的是Innodb ,因此外键关联检查是打开的,当我向外键表中插入
           非主键表中的值时,动作将会失败,创建的数据表如下:
    create table t2(s1 int primary key)engine=innodb;//
           create table t3(s1 int,
                      key(s1),
       foreign key (s1) references t2(s1))engine=innodb;//
    create table error_log(error_message char(80));//

1. 建立一个过程,第一个语句 DECLARE EXIT HANDLER是用来处理异常的,意思是如果错误 1216发生,这个程序将会在错误记录表中插入一行,
   EXIT的意思是 当动作成功提交后推出这个复合语句。
     create procedure p22(parameter int)
       begin
          declare exit Handler for 1452
     insert into error_log values(concat('Time: ',current_date,'.Foreign key reference failure for value=',parameter));
          insert into t3 values(parameter);
       end;//

2. 申明异常处理的语法 DECLARE HANDLER syntax:
       DECLARE {EXIT|CONTINUE} HANDLER FOR {error_number|{SQLSTATE error-string}|condition} SQL Statement
   上面就是错误处理的用法,也就是一段当程序出错后自动触发的代码,MYSQL允许两种处理器,一种是exit处理,另外一种是 continue处理,与exit
   不同的是在于他执行后,原主程序仍然继续运行,那么该复合语句就没有出口了。

----continue处理的例子:
      create table t4(s1 int primary key);//
      create procedure p23()
       begin
         declare continue handler for SQLSTATE '23000' set @x2=1;
  set @x=1;
  insert into t4 values (1);
  set @x=2;
  insert into t4 values(1);
  set @x=3;
         select @x, @x2;
       end;//
       call p23();//

---- rollback(回滚事务),定义自己的错误处理名字 declare '错误处理名' condition for SQLSTATE'23000';
      create procedure p24()
       begin
         declare ViolationSelf condition for SQLSTATE'23000';
  DECLARE EXIT HANDLER for ViolationSelf rollback;
  start transaction;
  insert into t2 values(1);
         insert into t2 values(1);
  commit;
       end;//


/********************************************  Cursor游标  **********************************************************/

游标实现功能的摘要: 声明游标, 打开游标,从游标里读取,关闭游标
      DECLARE cursor-name CURSOR FOR SELECT ······
      OPEN cursor-name;
      FETCH cursor-name INTO variable;
      CLOSE cursor-name;

1. create procedure p25(out return_val int)
    begin
      DECLARE a,b,c int;
      DECLARE cur_1 CURSOR for select s1 from t;
      DECLARE continue handler for not found set b=1;
       open cur_1;
       set c=0;
       repeat
         fetch cur_1 into a;
  until b=1
       end repeat;
       close cur_1;
       set return_val=a;
    end;//

2.    create procedure p25_1(out return_val int)
    begin
      DECLARE a,b,c int;
      DECLARE cur_1 CURSOR for select s1 from t;
      DECLARE continue handler for not found set b=1;
       open cur_1;
       set c=0;
       lable_1:loop
         fetch cur_1 into a;
  if b=1 then
           leave lable_1;
  end if;
  set c=c+1;
       end loop;
       close cur_1;
       set return_val=c;
    end;//

    create procedure p34(in va int)
    begin
       delete from t where s1=va;
    end;//


http://www.docin.com/p-68861166.html
http://www.111cn.net/database/11 ... 9b42e2754a69e5d.htm
Error Handler Examples
Here are some examples of handler declarations:
If any error condition arises (other than a NOT FOUND ), continue execution after setting l_error=1 :
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET l_error=1;
If any error condition arises (other than a NOT FOUND ), exit the current block or stored program after issuing a ROLLBACK statement and issuing an error message:
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Error occurred – terminating';
END;
If MySQL error 1062 (duplicate key value) is encountered, continue execution after executing the SELECT statement (which generates a message for the calling program):
DECLARE CONTINUE HANDER FOR 106 2
SELECT 'Duplicate key in index';
If SQLSTATE 23000 (duplicate key value) is encountered, continue execution after executing the SELECT statement (which generates a message for the calling program):
DECLARE CONTINUE HANDER FOR SQLSTATE '23000'
SELECT 'Duplicate key in index';
When a cursor fetch or SQL retrieves no values, continue execution after setting l_done=1 :
DECLARE CONTINUE HANDLER FOR NOT
FOUND
SET l_done=1;
Same as the previous example, except specified using a SQLSTATE variable rather than a named condition:
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000 '
SET l_done=1;
Same as the previous two examples, except specified using a MySQL error code variable rather than a named condition or SQLSTATE variable:
DECLARE CONTINUE HANDLER FOR 1329
SET l_done=1;

错误处理例子
有几种错误处理的声明形式:
§ 如果任何错误(不是 NOT FOUND ) , 设置 l_error 为 1 后继续执行:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET l_error=1;
§ 如果发生任何错误(不是 NOT FOUND), 执行 ROLLBACK和产生一条错误消息后退出当前块或存储过程。
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Error occurred – terminating';
END;
§ 如果 MySQL 1062错误 (重复的健值 )发生,执行 SELECT语句(向调用程序发一条消息)后继续执行
DECLARE CONTINUE HANDER FOR 106 2
SELECT 'Duplicate key in index';
§ 如果 SQLSTATE 2300错误 (重复的健值 )发生,执行 SELECT语句(向调用程序发一条消息)后继续执行
DECLARE CONTINUE HANDER FOR SQLSTATE '23000'
SELECT 'Duplicate key in index';
§ 当游标或者 SQL 选择语句没有返回值时,设置 l_done=1 后继续执行
DECLARE CONTINUE HANDLER FOR NOT
FOUND
SET l_done=1;
§ 此例除了用 SQLSTATE 变量而不是命名条件以外,跟前一个例子一样
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000 '
SET l_done=1;
§ 此例除了用 MySQL 的错误码变量而不是命名条件或者 SQLSTATE 变量以外,跟前两个例子一样
DECLARE CONTINUE HANDLER FOR 1329
SET l_done=1;

http://www.jb51.net/article/20513.htm

http://www.360doc.com/content/11/0623/16/61497_129060932.shtml

http://www.phper-seoer.com/php/176.html
定义错误:

为错误定义一个名称,语法为:

DECLARE error_name CONDITION FOR condition_value;

declare 定义一个变量

error_name:自定义的错误的名字

condition_value可以是两种情况:

第一:直接写错误号,如 1305;

错误代码





第二:写sqlstate错误号: 如

SQLSTATE '42000';

sqlstate错误号

错误处理

语法为:

DECLARE handler_type HANDLER FOR condition_value


begin


...


end;


handler_type: 处理的过程。
    CONTINUE 继续执行未完成的存储过程,直至结束。(常用,默认)
  | EXIT 出现错误即自动跳出所在的begin不再执行后面的语句。


condition_value: 处理的触发条件
    SQLSTATE [VALUE] sqlstate_value 不用说了,就是上面提到的第二中方法,也是最常用的错误定义,自己去查错误列表吧。
  | condition_name 我们刚刚定义的那个名字errorname就是用在这里的。
  | SQLWARNING 代表所有以01开头的错误代码
  | NOT FOUND 表所有以02开头的错误代码,当然也可以代表一个游标到达数据集的末尾。
  | SQLEXCEPTION 代表除了SQLWARNING和NOT FOUND 的所有错误代码。
  | mysql_error_code 错误编号,上面的第一种方法,不过同样可以在错误列表从中查到,是我比较常用的。



例子:

create procedure error_test()

begin

#定义错误,1305是调用了错误的存储过程

declare errname condition for 1305;

declare continue handler for errname

begin

select 'no that procedure' as error;

end;

call aaa();end;

备注:

MySQL ERROR CODE 列表

如果需要查看更多的错误列表可以直接到MySQL安装路径下。

比如我的/usr/local/mysql/share/mysql/errmsg.txt

说明:SQLSTATE [VALUE] sqlstate_value这种格式是专门为ANSI SQL 和 ODBC以及其他的标准.

并不是所有的MySQL ERROR CODE 都映射到SQLSTATE。

使用道具 举报

回复
论坛徽章:
31
ITPUB十周年纪念徽章
日期:2011-09-27 16:32:49复活蛋
日期:2011-08-29 16:40:11蛋疼蛋
日期:2011-09-27 17:33:29双黄蛋
日期:2011-09-27 17:32:572011新春纪念徽章
日期:2011-02-18 11:43:352010广州亚运会纪念徽章:羽毛球
日期:2010-12-20 14:07:192010广州亚运会纪念徽章:游泳
日期:2010-11-18 16:21:47兰博基尼
日期:2013-07-30 13:51:34日产
日期:2013-07-29 10:18:002013年新春福章
日期:2013-02-25 14:51:24
7#
发表于 2011-8-29 21:38 | 只看该作者
楼主研究的不错

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表