强制SQL在限定时间内返回结果

浏览: 2022
SQL

设计出发点:

客户的流水线上会有N个工人,每个工人守在流水线的一个岔路上。
这时要对每个工人的作业量进行平衡划分,就需要对每个工人的手工剩余工作量进行统计,然后把新的作业流向手头工作量少的工人手里。

但假如统计的时间很长,流水线上的作业还没来得及分配岔口号,就会一直走到直线的岔口上,结果导致直线的岔口工作量很大,而其它岔口却很空闲。
这时候就可以强制SQL统计在限定时间内必须返回结果;如果限定时间不能得到查询结果,则可以忽略统计而考虑立刻分配随机的岔口号已分流新的工作量。

 

实现思路:

下面列出整个逻辑的实现过程:
1)模拟需要各种时间来得到结果的代码:

create or replace function send_number ( id number) return number as
  v_result  number;
begin
  dbms_lock.sleep(id);
  return id;
end send_number;


–可根据输入参数,来模拟需要固定时间的查询

如:下面查询就需要4秒来得到结果

SQL> select send_number(4) from dual;
 
SEND_NUMBER(4)
————–
             4
 
Executed in 4.041 seconds

2)生成agent进程来执行发布的查询,agent进程从mc$agent中获得查询的语句,然后将结果传到mc$pipe管道中

create or replace procedure pipe_agent is
  n         number;
  v_result  number;
  i_sql     varchar2(4000);
begin
  while 1>0 loop
     i_sql:=null;
     v_result:=dbms_pipe.receive_message( pipename => 'mc$agent');
      if v_result=0 then
         while dbms_pipe.next_item_type>0 loop
         exit when i_sql is not null;
              dbms_pipe.unpack_message(i_sql);
         end loop;
      end if;
     dbms_output.put_line(i_sql);
     execute immediate i_sql into n;
     dbms_pipe.pack_message(item => n);
     v_result:=dbms_pipe.send_message(pipename => 'mc$pipe');
  end loop;
end pipe_agent;


3)函数pipe_return用于从mc$pipe中获得查询结果,如果在5秒内得到的话,就返回正常结果,如果超时,则返回空
即使之后查询得到

create or replace function pipe_return(i_sql varchar2)  return number as
  v_message  number;
  v_result   number;
begin
    v_message:=null;
    dbms_pipe.purge(pipename => 'mc$agent');
    dbms_pipe.purge(pipename => 'mc$pipe');
    dbms_pipe.pack_message(item => i_sql);
    v_result:=dbms_pipe.send_message(pipename => 'mc$agent');
    v_result:=dbms_pipe.receive_message( pipename => 'mc$pipe',
                                         timeout => 5);
      if v_result=0 then
         while dbms_pipe.next_item_type>0 loop
         exit when v_message is not null;
              dbms_pipe.unpack_message(v_message);
         end loop;
      /*else
      如果超时,说明发布的SQL查询超时;
      则发动另一个agent进程,以便以后的查询使用
      这里作为演示,不涉及更复杂的情况
      */
      end if;
   dbms_output.put_line(v_message);
   return v_message;
end pipe_return;


4)演示
打开一个会话,发送agent
begin
  pipe_agent;
end;

另起一个会话,进行演示
注意:实际需要的查询sql语句,作为pipe_return的参数传入
a)不超时的查询

SQL> SQL> select pipe_return('select send_number(2) from dual') from dual;
 
PIPE_RETURN('SELECTSEND_NUMBER
——————————
                             2
 
Executed in 2.012 seconds
 

b)超时的查询


SQL> select pipe_return('select send_number(6) from dual') from dual;
 
PIPE_RETURN('SELECTSEND_NUMBER
——————————
 
Executed in 5.024 seconds
推荐 0
本文由 newkoa 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册