DBMS_SESSION.SLEEP 프로시저의 정밀도는 1/100 초입니다. 정밀도가 1/1000 초(ms)인 Thread.Sleep 메서드 (Java.Lang)의 1/10 수준으로 낮은 정밀도로 인해 정확한 스케쥴링을 구현하기 어렵습니다.
Amount of time, in seconds, to suspend the session. The smallest increment can be entered in hundredths of a second; for example, 1.95 is a legal time value.
특히 주의할 점은 DBMS_SESSION.SEELP 프로시저의 입력 값을 반올림됨으로써 대기 시간이 증가할 수 있다는 것입니다. 아래는 DBMS_SESSION.SEELP 프로시저를 테스트한 결과입니다. 입력 값이 반올림되는 것을 확인할 수 있습니다. 참고로 DBMS_LOCK.SLEEP 프로시저도 DBMS_SESSION.SLEEP 프로시저와 동일하게 동작합니다.
-- 1-1
BEGIN
FOR i IN 1 .. 100 LOOP
DBMS_SESSION.SLEEP (0.004);
END LOOP;
END;
/
Elapsed: 00:00:00.14
-- 1-2
BEGIN
FOR i IN 1 .. 100 LOOP
DBMS_SESSION.SLEEP (0.005);
END LOOP;
END;
/
Elapsed: 00:00:01.14
-- 1-3
BEGIN
FOR i IN 1 .. 100 LOOP
DBMS_SESSION.SLEEP (0.01);
END LOOP;
END;
/
Elapsed: 00:00:01.14
-- 1-4
BEGIN
FOR i IN 1 .. 100 LOOP
DBMS_SESSION.SLEEP (0.015);
END LOOP;
END;
/
Elapsed: 00:00:02.14
-- 1-5
BEGIN
FOR i IN 1 .. 100 LOOP
DBMS_SESSION.SLEEP (0.02);
END LOOP;
END;
/
Elapsed: 00:00:02.14
아래는 1초 단위로 데이터를 프로파일링하는 예제입니다. 작업 시간(0.015초)를 제외한 시간을 대기하지만 입력 값이 반올림되어 프로파일링 시작 시간이 점점 지연되는 것을 확인할 수 있습니다. 이로 인해 일정 시간이 지나면 동일한 초 단위에 2개의 프로파일링 시작 시간이 기록될 수 있습니다. (예를 들어 00:01.001, 00:01.999)
-- 2
SET SERVEROUT ON
DECLARE
v_begin_time TIMESTAMP;
v_time NUMBER;
BEGIN
v_begin_time := TRUNC (SYSTIMESTAMP, 'MI') + NUMTODSINTERVAL (ROUND (EXTRACT (SECOND FROM SYSTIMESTAMP)) + 1, 'SECOND');
WHILE v_begin_time >= SYSTIMESTAMP LOOP
DBMS_SESSION.SLEEP (0.01);
END LOOP;
FOR i IN 1 .. 30 LOOP
v_time := DBMS_UTILITY.GET_TIME;
DBMS_OUTPUT.PUT_LINE (LPAD (i, 2, '0') || ': ' || TO_CHAR (SYSTIMESTAMP, 'SS.FF3'));
DBMS_SESSION.SLEEP (0.015); --> run time
DBMS_SESSION.SLEEP (GREATEST (1 - ((DBMS_UTILITY.GET_TIME - v_time) / 100), 0)); --> runtime excluding run time
END LOOP;
END;
/
01: 28.014
02: 29.029
03: 30.045
04: 31.060
05: 32.075
06: 33.091
07: 34.090
08: 35.090
09: 36.090
10: 37.090
11: 38.090
12: 39.089
13: 40.089
14: 41.089
15: 42.089
16: 43.088
17: 44.088
18: 45.088
19: 46.088
20: 47.087
21: 48.087
22: 49.087
23: 50.102
24: 51.102
25: 52.102
26: 53.102
27: 54.101
28: 55.101
29: 56.101
30: 57.101
PL/SQL procedure successfully completed.
아래 예제는 지정한 시간까지 0.01초를 반복적으로 대기하는 방식을 사용합니다. 프로파일링 시작 시간이 지연되지 않는 것을 확인할 수 있습니다.
-- 3
SET SERVEROUT ON
DECLARE
v_begin_time TIMESTAMP;
PROCEDURE prc_sleep (i_time IN TIMESTAMP)
IS
BEGIN
WHILE i_time >= SYSTIMESTAMP LOOP
DBMS_SESSION.SLEEP (0.01);
END LOOP;
END;
BEGIN
v_begin_time := TRUNC (SYSTIMESTAMP, 'MI') + NUMTODSINTERVAL (ROUND (EXTRACT (SECOND FROM SYSTIMESTAMP)) + 1, 'SECOND');
WHILE v_begin_time >= SYSTIMESTAMP LOOP
DBMS_SESSION.SLEEP (0.01);
END LOOP;
FOR i IN 1 .. 30 LOOP
DBMS_OUTPUT.PUT_LINE (LPAD (i, 2, '0') || ': ' || TO_CHAR (SYSTIMESTAMP, 'SS.FF3'));
DBMS_SESSION.SLEEP (0.015); --> run time
prc_sleep (v_begin_time + NUMTODSINTERVAL (i * 1, 'SECOND')); --> sleep until a specific time
END LOOP;
END;
/
01: 20.002
02: 21.001
03: 22.001
04: 23.001
05: 24.001
06: 25.016
07: 26.016
08: 27.016
09: 28.015
10: 29.015
11: 30.015
12: 31.015
13: 32.014
14: 33.014
15: 34.014
16: 35.014
17: 36.013
18: 37.013
19: 38.013
20: 39.013
21: 40.013
22: 41.012
23: 42.012
24: 43.012
25: 44.012
26: 45.011
27: 46.011
28: 47.011
29: 48.010
30: 49.010
PL/SQL procedure successfully completed.