mysql数据库,版本:mysqld-6.0.0-alpha-community-nt-debug
通过VC以ADO方式调用mysql的存储过程,在数据量比较少时能够正常执行,在运行一段时间后数据量比较大(单表约40万条)就出现问题。以下的异常通过_ConnectionPtr的GetDescription()方法得到:
[MySQL][ODBC 3.51 Driver][mysqld-6.0.0-alpha-community-nt-debug]Failed to load routine factory.proc_tjtb. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6)
数据库名factory,过程名proc_tjtb。但是在控制台下通过call proc_tjtb(xxx,xxx,xxx)调用能正常执行,只是所花费的时间要比数据量少时多很多。
哪位遇到过类似问题,请问如何解决?存储过程proc_tjtb中主要部分如下:
select 'now is to loop';/* !!!输出信息-调试用;Release版本删除 */
select CONCAT('统计起始时间: ', startTime ),' - ',CONCAT('统计截止时间: ', statisticEndTime );/* !!!输出信息-调试用;Release版本删除 */
/*-----------------------------------------------------------------------*/
set loopNum = 0;
/*统计(startTime ,statisticEndTime]的时间段*/
set t0  = 0;
loop_while: while t0 < statisticEndTime do /* 注意:不包括“=”,相等时退出*/
set loopNum = loopNum + 1;
select CONCAT('循环次数:' , loopNum);/* !!!输出信息-调试用;Release版本删除 */
select CONCAT(CONCAT('在( ', startTime ),CONCAT(',', statisticEndTime ),']内统计');/* !!!输出信息-调试用;Release版本删除 */ /* 在开始时刻之后,找播出时段内第一个时刻 t0*/
select '在开始时刻之后,找播出时段内第一个时刻 t0...';/* !!!输出信息-调试用;Release版本删除 */
set t0 = NULL;
set  @sqlstr = concat(' insert into tmp_crtime (s_crtime)   select  min(s_crtime)  as s_crtime   from  ',
@tableName, '  where  s_crtime >  ?  and s_crtime <=  ?  and f_all_bad = 1;'); PREPARE stmt1 FROM  @sqlstr;
set @bgdt = startTime;
set @eddt = statisticEndTime;
EXECUTE stmt1 using @bgdt, @eddt; 

select min(s_crtime) into t0 from tmp_crtime;
delete from tmp_crtime; /*清空临时表中的查询结果*/
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */ /* 如果没有找到播出时段,退出 */
if ISNULL (t0)   then
select '没有找到播出时段,程序退出';/* !!!输出信息-调试用;Release版本删除 */
leave loop_while;
end if;
select CONCAT('找到的播出时段内第一个时刻 t0:', t0);/* !!!输出信息-调试用;Release版本删除 */ /* 在@t0之后、@statisticEndTime之前,找非播出时段的开始时刻t1,t0<t1<=et。如果没有,则t1是播出时段(t0后,@statisticEndTime前)的最后时刻 */
select '在t0之后,找非播出时段的开始时刻t1...';/* !!!输出信息-调试用;Release版本删除 */

set t1 = NULL;
set  @sqlstr = concat(' insert into tmp_crtime (s_crtime)   select  min(s_crtime)  as s_crtime   from   ',
@tableName, '  where  s_crtime >  ?  and s_crtime <=  ?  and f_all_bad = 0;'); PREPARE stmt1 FROM  @sqlstr;
set @bgdt = t0;
set @eddt = statisticEndTime;
EXECUTE stmt1 using @bgdt, @eddt; 
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */ select s_crtime into t1 from tmp_crtime;
delete from tmp_crtime; /*清空临时表中的查询结果*/

/* 如果没有非播出时段,则t1是播出时段(t0后,@statisticEndTime前)的最后时刻 */
if ISNULL ( t1 ) then
select '没有非播出时段,则t1=播出时段(t0,statisticEndTime]的最后一个时刻';/* !!!输出信息-调试用;Release版本删除 */
set  @sqlstr = concat(' insert into tmp_crtime (s_crtime)   select  max(s_crtime)  as s_crtime   from  ',
@tableName, '  where  s_crtime >  ?  and s_crtime <=  ?  and f_all_bad = 1;');
PREPARE stmt1 FROM  @sqlstr;
set @bgdt = t0;
set @eddt = statisticEndTime;
EXECUTE stmt1 using @bgdt, @eddt;
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */

select s_crtime into t1 from tmp_crtime;
delete from tmp_crtime; /*清空临时表中的查询结果*/

/* 如果 t1 = t0 则说明已经到统计表的最后,且该时段只有一条记录,退出 */
if t1 = t0 then
select '已经到统计表的最后,且该时段只有一条记录';/* !!!输出信息-调试用;Release版本删除 */
leave loop_while;
end if;
end if;

/*-----------------------------------------------------------------------*/
/* 在[t0,t1]之间进行统计时段*/
select CONCAT ('在[t0 = ' ,t0,  ',   t1 = ', t1 , ']之间进行统计时段');/* !!!输出信息-调试用;Release版本删除 */

/* 令tjST1=t0 */
set tjST1 = t0;
set @sub_loop_num = 0;
loop_sub_while: while tjST1 <  t1 do
set @sub_loop_num = @sub_loop_num + 1;
select concat('子循环次数:',@sub_loop_num);/* !!!输出信息-调试用;Release版本删除 */

/* 设置各个字段状态的默认值为1 */
set field1Flag = 1;
set field2Flag = 1;
set field3Flag = 1;

/* 查 tjST1时刻的播出状态:正常?非正常? */
select CONCAT('查 tjST1(', tjST1,')时刻的播出状态...');/* !!!输出信息-调试用;Release版本删除 */
set @sql1 = ' insert into tmp_crtime (f1';
set @sql2 = concat('select ', fieldName1);
if !ISNULL(fieldName2) then
set  @sql1 = concat(@sql1, ',f2');
set @sql2 = concat(@sql2, ',' , fieldName2);
if !ISNULL(fieldName3) then
set  @sql1 = concat(@sql1, ',f3');
set @sql2 = concat(@sql2,  ',' ,fieldName3);
end if;
end if; set @sql1 = concat(@sql1, ')  ');
set @sql2 = concat(@sql2, ' from ',@tableName, '  where  s_crtime  =  ?  and s_crtime <=  ?  and f_all_bad = 1;');
set @sqlstr = concat(@sql1, @sql2); PREPARE stmt1 FROM  @sqlstr;
set @bgdt = tjST1;
set @eddt = statisticEndTime;
EXECUTE stmt1 using @bgdt, @eddt;
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */

select f1,f2,f3 into field1Flag,field2Flag,field3Flag from tmp_crtime;
delete from tmp_crtime; /*清空临时表中的查询结果*/

select  field1Flag,field2Flag,field3Flag;/* !!!输出信息-调试用;Release版本删除 */
/* 字段2和3如果为空,则设置为默认值1 */
if isnull(field2Flag) then
set field2Flag = 1;
end if;

if isnull(field3Flag) then
set field3Flag = 1;
end if;

/* 因为设置了默认值“1”,故可以这样获得tjST1时刻的播出状态 */
if (field1Flag = 1) and (field2Flag = 1) and (field3Flag = 1) then
set broFlag = 1;
select concat('tjST1时刻(', tjST1,')的播出状态:1');/* !!!输出信息-调试用;Release版本删除 */
else
set broFlag = 0;
select concat('tjST1时刻(', tjST1,')的播出状态:0');/* !!!输出信息-调试用;Release版本删除 */
end if;

/* 找tjST2(tjST1<tjST2<=t1)且状态与@broFlag相反的最近一个时刻 */
set @sql1 = ' insert into tmp_crtime (s_crtime)  ';
set @sql2 = concat(' select min(', @tableName, '.s_crtime)  as s_crtime   from ', @tableName ,'  where s_crtime >  ?  and s_crtime <= ?  and f_all_bad = 1  ');
if broFlag = 1 then
set @sql2 = concat(@sql2,' and (', fieldName1, ' = 0  ');
if !ISNULL(fieldName2) then
set @sql2 = concat(@sql2, ' or ', fieldName2 , ' = 0 ');
if !ISNULL(fieldName3) then
set @sql2 = concat(@sql2, ' or  ', fieldName3, ' = 0 ');
end if;
end if;
else
set @sql2 = concat(@sql2,' and ( ', fieldName1, ' = 1 ');
if !ISNULL(fieldName2) then
set @sql2 = concat(@sql2, ' and ', fieldName2, ' = 1');
if !ISNULL(fieldName3) then
set @sql2 = concat(@sql2, ' and ', fieldName3, ' = 1');
end if;
end if;
end if;

set @sql2 = CONCAT(@sql2,  ' ); ');
set @sqlstr = CONCAT(@sql1,  @sql2); PREPARE stmt1 FROM  @sqlstr;
set @bgdt = tjST1;
set @eddt = t1;
EXECUTE stmt1 using @bgdt, @eddt;
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */

select s_crtime into tjST2 from tmp_crtime;/* !!!输出信息-调试用;Release版本删除 */
delete from tmp_crtime; /*清空临时表中的查询结果*/

/*如果没有找到,则tjST2 = t1*/
if ISNULL( tjST2 ) then
select concat('没有找到tjST2(tjST1<tjST2<=t1)且状态与broFlag相反的最近一个时刻,设置tjST2为t1=', t1);/* !!!输出信息-调试用;Release版本删除 */
set tjST2 = t1;
end if;

/* [tjST1,tjST2]、状态为broFlag的一个时段入库 */
set  @sqlstr = concat('INSERT INTO 停播统计(machine,isWell,startTime,endTime) VALUES(?, ?,? , ?);');
PREPARE stmt1 FROM  @sqlstr;
set @mch = machinename;
set @isWell = broFlag;
set @bgdt = tjST1;
set @eddt = tjST2;
EXECUTE stmt1 using @mch,@isWell,@bgdt, @eddt; 
DEALLOCATE PREPARE stmt1;/* 别忘记释放资源 */
select concat('一个时段入库:[tjST1= ',tjST1, ',tjST2 =',tjST2);/* !!!输出信息-调试用;Release版本删除 */

/* tjST2为新的时段的开始进行搜索 */
set tjST1 = tjST2;
end while loop_sub_while;

/*重新设置开始时刻*/
set startTime = t1; /*下一次开始时段是本次停播的结束时段*/
end while loop_while; select loopNum;/* !!!输出信息-调试用;Release版本删除 */ select 'before exit_proc';/* !!!输出信息-调试用;Release版本删除 */
leave exit_proc ;

end exit_proc ; 

解决方案 »

  1.   

    检查一下你的MYSQL的 wait_timeout 参数。
      

  2.   

    有多少用户?
    ODBC 3.51 Driver更新为5.12试试
      

  3.   

    这类错误不好排除。原因也是多样的。
    ADO on ODBC,不一定稳定。另,你的这个ODBC驱动是最新版本的吗?最好能与你的mysql6.0-alpha版本相匹配。
    再者,从不建议用户使用什么alpha版本用于开发,本身就是不稳定版本。有一个全局参数在配置文件里:
    max_allowed_packet,你可以调大一点,比如64M之类的。
    但未必能解决问题。ODBC的bug, mysql6.0alpha的bug都有可能。建议:
    使用C-API写一简短的程序来验证是否能工作。如果还是同样的错,基本上就是6.0alpha的bug了。
      

  4.   

    谢谢楼上各位的回复,按照WWWWA的回复升级了ODBC的驱动[版本mysql-connector-odbc-5.1.6-win32],测试ok了。
    再次表示感谢!