ORACLE中的睡眠功能

时间:2010-04-01 15:45:40

标签: sql oracle plsql oracle11g

我需要在ORACLE中执行SQL查询需要一定的时间。 所以我写了这个函数:

CREATE OR REPLACE FUNCTION MYSCHEMA.TEST_SLEEP
(
TIME_  IN  NUMBER
)
RETURN INTEGER IS
 BEGIN
   DBMS_LOCK.sleep(seconds => TIME_);
RETURN 1;
 EXCEPTION
   WHEN OTHERS THEN
   RAISE;
   RETURN 1;
END TEST_SLEEP;

我以这种方式打电话

SELECT TEST_SLEEP(10.5) FROM DUAL

但要工作,我需要为程序所有者设置DBMS_LOCK的授权。

如何在不使用DBMS_LOCK.sleep函数的情况下重写此函数?

11 个答案:

答案 0 :(得分:39)

除了授予对DBMS_LOCK.sleep的访问权限之外,这将有效,但这是一个可怕的黑客攻击:

IN_TIME INT; --num seconds
v_now DATE;

-- 1) Get the date & time 
SELECT SYSDATE 
  INTO v_now
  FROM DUAL;

-- 2) Loop until the original timestamp plus the amount of seconds <= current date
LOOP
  EXIT WHEN v_now + (IN_TIME * (1/86400)) <= SYSDATE;
END LOOP;

答案 1 :(得分:21)

创建一个只执行锁定并将其安装到使用dbms_lock(USERA)“信任”的其他用户的过程,授予USERA访问dbms_lock的权限。

然后只授予USERB访问此功能的权限。然后他们不需要能够访问DBMS_LOCK

(确保在运行之前系统中没有usera和userb)

以具有dbms_lock的grant privs的用户身份进行连接,并可以创建用户

drop user usera cascade;
drop user userb cascade;
create user usera default tablespace users identified by abc123;
grant create session to usera;
grant resource to usera;
grant execute on dbms_lock to usera;

create user userb default tablespace users identified by abc123;
grant create session to userb;
grant resource to useb

connect usera/abc123;

create or replace function usera.f_sleep( in_time number ) return number is
begin
 dbms_lock.sleep(in_time);
 return 1;
end;
/

grant execute on usera.f_sleep to userb;

connect userb/abc123;

/* About to sleep as userb */
select usera.f_sleep(5) from dual;
/* Finished sleeping as userb */

/* Attempt to access dbms_lock as userb.. Should fail */

begin
  dbms_lock.sleep(5);
end;
/

/* Finished */

答案 2 :(得分:7)

如果在“sqlplus”中执行,则可以执行主机操作系统命令“sleep”:

!sleep 1

host sleep 1

答案 3 :(得分:4)

有关程序包装的Java代码的内容是什么?简单而且工作正常。

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED SNOOZE AS
public final class Snooze {
  private Snooze() {
  }
  public static void snooze(Long milliseconds) throws InterruptedException {
      Thread.sleep(milliseconds);
  }
}

CREATE OR REPLACE PROCEDURE SNOOZE(p_Milliseconds IN NUMBER) AS
    LANGUAGE JAVA NAME 'Snooze.snooze(java.lang.Long)';

答案 4 :(得分:3)

实现同步机制会更好。最简单的方法是在第一个文件完成后写一个文件。所以你有一个哨兵文件。

因此外部程序会查找存在的sentinel文件。当它发生时,它知道它可以安全地使用真实文件中的数据。

执行此操作的另一种方法(类似于某些浏览器在下载文件时的操作方式)是将文件命名为base-name_part,直到文件完全下载,然后在最后将文件重命名为base-name。 通过这种方式,外部程序无法看到&#34;文件直到完成。这种方式不需要重写外部程序。哪种情况可能最适合这种情况。

答案 5 :(得分:3)

从Oracle 18c开始,您可以使用 DBMS_SESSION.SLEEP 程序:

  

此过程将会话暂停指定的时间段。

DBMS_SESSION.sleep
所有会话均可使用

DBMS_LOCK.sleep,无需额外拨款。 请注意,WITH FUNCTION已弃用。

如果您需要简单的查询睡眠,可以使用WITH FUNCTION my_sleep(i NUMBER) RETURN NUMBER BEGIN DBMS_SESSION.sleep(i); RETURN i; END; SELECT my_sleep(3) FROM dual;

var start = picker.startDate.format('YYYY-MM-DD');
var end = picker.endDate.format('YYYY-MM-DD');

答案 6 :(得分:1)

如果您的11G上安装了Java,那么您可以在java类中执行它并从PL / SQL中调用它,但我不确定它是否也不需要特定的授权来调用java。

答案 7 :(得分:1)

似乎java过程/函数可以工作。但是,为什么不在应用程序架构或具有此授权的管理员帐户之类的用户下编译您的功能,只需授予您的开发者帐户执行权限。这样就可以使用定义者权利。

答案 8 :(得分:1)

您可以使用DBMS_PIPE.SEND_MESSAGE的消息对于管道来说太大,例如5秒延迟将XXX写入管道,该管道只能使用5秒超时接受一个字节,如下所示

dbms_pipe.pack_message('XXX');<br>
dummy:=dbms_pipe.send_message('TEST_PIPE', 5, 1);

但那需要DBMS_PIPE的拨款,所以也许没有更好的。

答案 9 :(得分:1)

有一篇关于这个主题的好文章:PL/SQL: Sleep without using DBMS_LOCK帮助了我。我使用自定义包裹的Option 2。提出的解决方案是:

  

选项1:APEX_UTIL.sleep

     

如果安装了APEX,您可以使用公开包APEX_UTIL中的“暂停”程序。

     

示例 - “等待5秒钟”:

SET SERVEROUTPUT ON ;
BEGIN
    DBMS_OUTPUT.PUT_LINE('Start ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
    APEX_UTIL.PAUSE(5);
    DBMS_OUTPUT.PUT_LINE('End   ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
END;
/
  

选项2:java.lang.Thread.sleep

     

另一个选项是使用Java类“Thread”中的“sleep”方法,您可以通过提供简单的PL / SQL包装程序轻松使用该方法:

     

注意:请记住,“Thread.sleep”使用毫秒!

--- create ---
CREATE OR REPLACE PROCEDURE SLEEP (P_MILLI_SECONDS IN NUMBER) 
AS LANGUAGE JAVA NAME 'java.lang.Thread.sleep(long)';

--- use ---
SET SERVEROUTPUT ON ;
BEGIN
    DBMS_OUTPUT.PUT_LINE('Start ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
    SLEEP(5 * 1000);
    DBMS_OUTPUT.PUT_LINE('End   ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
END;
/

答案 10 :(得分:1)

您可以按以下方式使用DBMS_ALERT软件包:

CREATE OR REPLACE FUNCTION sleep(seconds IN NUMBER) RETURN NUMBER
AS
    PRAGMA AUTONOMOUS_TRANSACTION;
    message VARCHAR2(200);
    status  INTEGER;
BEGIN
    DBMS_ALERT.WAITONE('noname', message, status, seconds);
    ROLLBACK;
    RETURN seconds;
END;
SELECT sleep(3) FROM dual;