web-dev-qa-db-ja.com

ORACLEのスリープ機能

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関数を使用せずにこの関数を書き換えるにはどうすればよいですか?

30
Salvador

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;
41
OMG Ponies

ロックを行うだけのプロシージャを作成し、dbms_lock(USERA)で「信頼されている」別のユーザーにインストールし、dbms_lockへのUSERAアクセスを許可します。

次に、この関数へのUSERBアクセスを許可します。その後、DBMS_LOCKにアクセスできる必要はありません。

(これを実行する前に、システムにuseraとuserbがないことを確認してください)

Dbms_lockの付与特権を持つユーザーとして接続し、ユーザーを作成できます

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 */
22
Matthew Watson

「sqlplus」内で実行すると、ホストオペレーティングシステムコマンド「sleep」を実行できます。

!sleep 1

または

Host sleep 1
7
metatechbe

Oracle 18cからDBMS_SESSION.SLEEPプロシージャを使用できます。

このプロシージャは、指定された期間セッションを一時停止します。

DBMS_SESSION.SLEEP (seconds  IN NUMBER)

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;
5
Lukasz Szozda

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
MacTouch

このトピックに関する良い記事があります: PL/SQL:DBMS_LOCKを使用せずにスリープ 助けてくれました。カスタムパッケージにラップされたオプション2を使用しました。提案されたソリューションは次のとおりです。

オプション1:APEX_UTIL.sleep

APEXがインストールされている場合、公開されているパッケージAPEX_UTILの手順「PAUSE」を使用できます。

例–「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

もう1つのオプションは、Javaクラス「スレッド」からのメソッド「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;
/
3
dominik

同期メカニズムを実装することをお勧めします。最も簡単なのは、最初のファイルが完了した後にファイルを書き込むことです。これで、センチネルファイルができました。

そのため、外部プログラムは、存在するセンチネルファイルを探します。実行すると、実際のファイルのデータを安全に使用できることがわかります。

これを行う別の方法は、一部のブラウザーがファイルをダウンロードするときに行う方法に似ていますが、ファイルが完全にダウンロードされるまでbase-name_partという名前のファイルを作成し、最後にファイルの名前をbase-nameに変更します。このようにして、外部プログラムは、完了するまでファイルを「見る」ことができません。この方法では、外部プログラムを書き直す必要はありません。これはこの状況に最適かもしれません。

3
Bozon

DBMS_PIPE.SEND_MESSAGEは、パイプに対して大きすぎるメッセージで使用できます。たとえば、5秒の遅延の場合、次のように5秒のタイムアウトを使用して1バイトしか受け入れられないパイプにXXXを書き込みます。

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

ただし、その場合はDBMS_PIPEの許可が必要なので、おそらくそれ以上のことはありません。

1
The love dada

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;
1
sealor

Javaが11Gにインストールされている場合、Javaクラスでそれを実行し、PL/SQLから呼び出すことができますが、 Javaを呼び出すための特定の許可も必要ありません。

1

Javaプロシージャ/関数が機能する可能性があります。しかし、アプリケーションスキーマやこの許可を持つ管理者アカウントなどのユーザーの下で関数をコンパイルし、開発者アカウントにそのようにして、定義者権限が使用されます。

1
Kuberchaun