【问题标题】:Nested while loop taking more time than nested cursor嵌套 while 循环比嵌套游标花费更多时间
【发布时间】:2017-09-26 19:12:04
【问题描述】:

我在从两个 sql 语句中获取数据后插入 n 行。到目前为止,我使用了两种方法,第一种是 Cursor,另一种是 While 循环。

嵌套游标:

    begin
    declare userId,taskId int default 0;
    declare userCnt int default 0;
    declare c1 cursor for select us_id from us_uxusermaster ;
    declare continue handler for not found set userCnt=1;
    open c1;
    CheckId: loop
    fetch c1 into userId;
    if userCnt=1
    then 
        leave CheckId;
    end if;
            Select pl.pl_minTarget into target from pl_planlist pl inner join ap_affiliateplan ap inner join us_uxusermaster us on Find_in_set(pl.pl_id,us.us_planListId) and ap.ap_id =us.us_taskPlanId where us_id=userId and pl.pl_serviceName=2;
                Begin
                DECLARE taskId int default 0;
                Declare taskCnt int default 0;
                Declare t1 cursor for select tk.tk_id  from tk_taskmaster tk where tk.tk_activeTime=AddDate(Current_date(),1)  and tk_actStatus=0 and tk_status=1 limit target;
                Declare continue handler for not found set taskCnt=1;
                open t1;
                CheckTask: loop
                fetch t1 into taskId;
                if taskCnt=1
                then
                leave CheckTask;
                end if;

                    insert into ut_userstask(ut_tk_id,ut_us_id,ut_edtm,ut_eby) values (taskId,userId,current_timestamp,'Via-Event');
                end loop checkTask;
                close t1;
                End;
    end loop CheckId;
    close c1;

    end;

While 循环:

    begin
declare taskName,taskCode,description,url,userLevel,TaskStatus,TaskActStatus,Steps,taskId,userId varchar(50);

declare activationTime,deActivationTime datetime;

Declare flag,flag2,counts,counts2 int default 0; 
Drop Temporary Table if exists temptrigg;
Set @rownumber=0;
Set @rownumber2=0;
create temporary table  temptrigg as(select * from (select (@rownumber := @rownumber + 1) AS newrow, us_id from us_uxusermaster) AS xst);
select count(*) into counts from temptrigg;
while(flag<counts)
Do
Set flag=flag+1;
Select us_id into userId from temptrigg where newrow=flag;

Drop Temporary Table if exists temptrigg2;
Create temporary table temptrigg2 as(select * from(select (@rownumber2 := @rownumber2 + 1) as newrow2,tk.tk_id  from tk_taskmaster tk where tk.tk_activeTime=Current_date()  and tk_actStatus=0 and tk_status=1)as xst);
Select count(*) into Counts2 from temptrigg2;
While(flag2<Counts2)
Do
Set flag2=flag2+1;
Select tk_id into taskId from temptrigg2 where newrow2=flag2;

    insert into ut_userstask(ut_tk_id,ut_us_id,ut_edtm,ut_eby) values (taskId,userId,current_timestamp,'Via-Event');

End While;
End While;

end

这里的问题是while循环比游标花费的时间是双倍的。我对它未来的结果感到困惑。通过替换嵌套的while循环跟随光标会不会很好。

插入 425 行游标需要 23.05 秒,而 while 循环需要 46 秒。这两个时间对我来说都太多了。有没有其他方法可以提高性能。

如果有的话会很高兴知道的。

【问题讨论】:

  • 你试过缩进你的代码吗?这将使它更容易阅读。无论如何,带有 while 循环的版本是在循环内创建和删除临时表。我并不惊讶它变慢了。我真的很惊讶它的速度只有 2 倍。
  • 到目前为止,最快的方法是使用您想要的所有内容构建单个 select 语句,然后使用 insert into ut_userstask(...) select (...) from ... 插入值。
  • @GolezTrol 有多个用户和多个任务,我必须插入所有任务。所以它不能存放在桌子上,因为我觉得那里会很乱。这就是我使用光标的原因
  • 除了limit target 之外,我还不清楚为什么您不能这样做,这似乎您希望每个用户有一个(不同的?)限制。有ways to solve that,我认为可以将三个选择加入一个选择并在单个插入语句中使用该选择。我有点不愿意发布它,因为我不确定我是否没有错过任何东西......

标签: mysql while-loop cursor


【解决方案1】:

我不确定我是否抓住了您在其中的每张支票(尤其是limit),但如果您可以将其挤入单个插入中会节省很多......像这样选择:

Insert into ut_userstask(ut_tk_id,ut_us_id,ut_edtm,ut_eby)
Select 
  tk.tk_id,
  us.us_id,
  current_timestamp,
  'Via-Event'
from pl_planlist pl 
inner join ap_affiliateplan ap 
inner join us_uxusermaster us on ap.ap_id = us.us_taskPlanId 
inner join tk_taskmaster tk on tk.tk_activeTime=AddDate(Current_date(),1) and tk_actStatus=0 and tk_status=1
where 
  pl.pl_serviceName=2
  and Find_in_set(pl.pl_id,us.us_planListId)

要记住的其他事项:确保您有正确的索引并尽量避免使用 FIND_IN_SET 之类的函数。这通常表明您的数据库没有足够规范化,并且使用起来很慢,因为它绕过了列上可用的任何索引。

即使您不能将所有内容放在一个选择中,循环通过主游标(例如获取用户)并为游标的每一行执行 insert..select 可能仍然更快。

【讨论】:

  • 我已经尝试过了,但它不会,因为在 where 子句中会有多个用户 ID,它不会让我返回结果。
  • 可以从 where 子句中删除该检查,因为它已经隐含在内部连接中。查询已修改。
  • 是的,稍作修改就可以了。谢谢你的主意。请投票。
  • 很高兴知道。也够快?
猜你喜欢
  • 2020-04-07
  • 2016-12-08
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多