Lock-Free Reservation #2

2023. 4. 17.·Oracle/Performance

개요

지난 글에 이어 2,000개의 세션에서 1,000개의 티켓을 예약하는 시나리오를 가정하고 Lock-Free Reservation, Pessimistic Locking, FOR UPDATE SKIP LOCKED 방식의 성능을 측정해보겠습니다. 참고로 Oracle 23c Free는 2 코어만 지원하므로 향후 추가 테스트가 필요할 것으로 보입니다.

 

Lock-Free Reservation

Lock-Free Reservation 방식을 테스트를 위해 아래와 같이 테이블을 생성하겠습니다.

-- 1
ALTER TABLE t1 MODIFY (c2 NOT RESERVABLE);

DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;

CREATE TABLE t1 (
    c1 NUMBER
  , c2 NUMBER RESERVABLE
  , CONSTRAINT t1_pk PRIMARY KEY (c1)
  , CONSTRAINT t1_c1 CHECK (c2 >= 0)
);

CREATE TABLE t2 (c1 TIMESTAMP, c2 NUMBER);

INSERT INTO t1 VALUES (1, 1000);
COMMIT;

 

Lock-Free Reservation 방식은 아래와 같은 방식으로 예약을 처리합니다. 예약에 필요한 작업에 0.1초가 소요된다고 가정합니다.

-- 2
CREATE OR REPLACE PROCEDURE p1 (i_v1 IN NUMBER)
IS
    e_check_constraint_violated EXCEPTION;
    PRAGMA EXCEPTION_INIT (check_constraint_violated, -2290);
    v1 NUMBER;
BEGIN
    UPDATE t1 SET c2 = c2 - 1 WHERE c1 = 1;
    DBMS_SESSION.SLEEP (0.1); -- do something
    INSERT INTO t2 VALUES (SYSTIMESTAMP, i_v1);
    COMMIT;
EXCEPTION
    WHEN e_check_constraint_violated THEN
        ROLLBACK;
END;
/

 

DBMS_JOB 패키지로 동시에 2000개의 예약 작업을 수행하겠습니다.

-- 3
ALTER SYSTEM SET job_queue_processes = 2000;

DECLARE
    v_job NUMBER;
    v_next_date DATE := SYSDATE + INTERVAL '20' SECOND;
BEGIN
    FOR i IN 1 .. 2000 LOOP
        DBMS_JOB.SUBMIT (v_job, 'P1 (' || i || ');', v_next_date);
        COMMIT;
    END LOOP;
END;
/

ALTER SYSTEM RESET job_queue_processes;

 

아래 쿼리로 결과를 확인할 수 있습니다. 수행 시간은 10초, 초당 평균 예약 건수는 100건입니다.

-- 4-1
SELECT COUNT (*) AS cnt
     , MIN (c2) AS min_c2
     , MAX (c2) AS max_c2
     , MAX (c1) - MIN (c1) AS elapsed
  FROM t2;

 CNT MIN_C2 MAX_C2 ELAPSED
---- ------ ------ --------------------------
1000      1   1006 +000000000 00:00:10.341758

1개의 행이 선택되었습니다.

-- 4-2
SELECT   TO_CHAR (c1, 'MI:SS') AS c1
       , COUNT (*) AS cnt
    FROM t2
GROUP BY TO_CHAR (c1, 'MI:SS')
ORDER BY 1;

C1    CNT
----- ---
00:01  69
00:02 103
00:03  92
00:04 105
00:05 110
00:06  97
00:07  90
00:08  87
00:09  80
00:10 103
00:11  64

11 행이 선택되었습니다.

 

Pessimistic Locking

Pessimistic Locking 방식을 테스트하기 위해 아래와 같이 테이블을 생성하겠습니다.

-- 5
DROP TABLE t3 PURGE;
DROP TABLE t4 PURGE;

CREATE TABLE t3 (
    c1 NUMBER
  , c2 NUMBER
  , CONSTRAINT t3_pk PRIMARY KEY (c1)
  , CONSTRAINT t3_c1 CHECK (c2 >= 0)
);

CREATE TABLE t4 (c1 TIMESTAMP, c2 NUMBER);

INSERT INTO t3 VALUES (1, 1000);
COMMIT;

 

Pessimistic Locking 방식은 아래와 같은 방식으로 예약을 처리합니다. 

-- 6
CREATE OR REPLACE PROCEDURE p2 (i_v1 IN NUMBER)
IS
    v1 NUMBER;
BEGIN
    SELECT c1 INTO v1 FROM t3 FOR UPDATE;

    IF v1 >= 0 THEN
        UPDATE t3 SET c2 = c2 - 1 WHERE c1 = 1;
        DBMS_SESSION.SLEEP (0.1); -- do something
        INSERT INTO t4 VALUES (SYSTIMESTAMP, i_v1);
        COMMIT;
    ELSE
        ROLLBACK;
    END IF;
END;
/

 

DBMS_JOB 패키지로 동시에 2000개의 예약 작업을 수행하겠습니다.

-- 7
ALTER SYSTEM SET job_queue_processes = 2000;

DECLARE
    v_job NUMBER;
    v_next_date DATE := SYSDATE + INTERVAL '20' SECOND;
BEGIN
    FOR i IN 1 .. 2000 LOOP
        DBMS_JOB.SUBMIT (v_job, 'P2 (' || i || ');', v_next_date);
        COMMIT;
    END LOOP;
END;
/

ALTER SYSTEM RESET job_queue_processes;

 

아래 쿼리로 결과를 확인할 수 있습니다. 수행 시간은 102초, 초당 평균 예약 건수는 10건입니다.

-- 8-1
SELECT COUNT (*) AS cnt
     , MIN (c2) AS min_c2
     , MAX (c2) AS max_c2
     , MAX (c1) - MIN (c1) AS elapsed
  FROM t4;

 CNT MIN_C2 MAX_C2 ELAPSED
---- ------ ------ --------------------------
1000      1   1015 +000000000 00:01:42.083347

1개의 행이 선택되었습니다.

-- 8-2
SELECT   TO_CHAR (c1, 'MI:SS') AS c1
       , COUNT (*) AS cnt
    FROM t4
GROUP BY TO_CHAR (c1, 'MI:SS')
ORDER BY 1;

C1    CNT
----- ---
00:01   7
00:02  10
00:03  10
00:04   9
00:05  10
00:06  10
00:07  10
00:08  10
00:09   9
00:10  10
...
103 행이 선택되었습니다.

 

FOR UPDATE SKIP LOCKED

FOR UPDATE SKIP LOCKED 방식을 테스트하기 위해 아래와 같이 테이블을 생성하겠습니다.

-- 9
DROP TABLE t5 PURGE;

CREATE TABLE t5 (
    c1 NUMBER
  , c2 NUMBER
  , c3 TIMESTAMP
  , c4 NUMBER
  , CONSTRAINT t5_pk PRIMARY KEY (c1, c2)
)
ORGANIZATION INDEX;

INSERT INTO t5 (c1, c2) SELECT 1, ROWNUM FROM XMLTABLE ('1 to 1000');
COMMIT;

 

FOR UPDATE SKIP LOCKED 방식은 아래와 같은 방식으로 예약을 처리합니다. 

-- 10
CREATE OR REPLACE PROCEDURE p3 (i_v1 IN NUMBER)
IS
BEGIN
    FOR f1 IN (SELECT *
                 FROM t5
                WHERE c1 = 1
                  AND c3 IS NULL
                  FOR UPDATE SKIP LOCKED)
    LOOP
        BEGIN
            UPDATE t5 SET c3 = SYSTIMESTAMP, c4 = i_v1 WHERE c1 = f1.c1 AND c2 = f1.c2;
            DBMS_SESSION.SLEEP (0.1); -- do something
            COMMIT;
        EXCEPTION
            WHEN OTHERS THEN
                ROLLBACK;
        END;
        
        EXIT;
    END LOOP;
END;
/

 

DBMS_JOB 패키지로 동시에 2000개의 예약 작업을 수행하겠습니다.

-- 11
ALTER SYSTEM SET job_queue_processes = 2000;

DECLARE
    v_job NUMBER;
    v_next_date DATE := SYSDATE + INTERVAL '20' SECOND;
BEGIN
    FOR i IN 1 .. 2000 LOOP
        DBMS_JOB.SUBMIT (v_job, 'P3 (' || i || ');', v_next_date);
        COMMIT;
    END LOOP;
END;
/

ALTER SYSTEM RESET job_queue_processes;

 

아래 쿼리로 결과를 확인할 수 있습니다. 수행 시간은 10초, 초당 평균 예약 건수는 100건입니다.

-- 12-1
SELECT COUNT (*) AS cnt
     , MIN (c4) AS min_c4
     , MAX (c4) AS max_c4
     , MAX (c3) - MIN (c3) AS elapsed
  FROM t5;

 CNT MIN_C4 MAX_C4 ELAPSED
---- ------ ------ --------------------------
1000      1   1001 +000000000 00:00:09.361067

1개의 행이 선택되었습니다.

-- 12-2
SELECT   TO_CHAR (c3, 'MI:SS') AS c3
       , COUNT (*) AS cnt
    FROM t5
GROUP BY TO_CHAR (c3, 'MI:SS')
ORDER BY 1;

C3     CNT
----- ----
00:01   80
00:02  100
00:03   94
00:04   97
00:05  137
00:06  123
00:07  111
00:08   88
00:09  120
00:10   50

10 행이 선택되었습니다.
저작자표시 비영리 변경금지 (새창열림)
'Oracle/Performance' 카테고리의 다른 글
  • V$MYSTAT 뷰
  • WITH 절에 대한 FPD 쿼리 변환 (WCFPD)
  • Direct Load 기능 개선
  • UNION ALL에 대한 Pushing Group By
정희락
정희락
2007년부터 Oracle Database 성능 최적화에 관심을 가져왔습니다. 현재 한국오라클 Engineered Systems Solution Engineering 팀에서 Solution Engineer로 근무하고 있습니다. 이 블로그는 개인적인 연구 목적으로 운영되며 Oracle 사의 공식적인 입장을 대변하지 않습니다.
  • 정희락
    TunA
    정희락
  • 전체
    오늘
    어제
    • 분류 전체보기 (201)
      • Oracle (173)
        • SQL (33)
        • PLSQL (10)
        • Performance (74)
        • Administration (37)
        • Installation (3)
        • Utilities (1)
        • JSON (8)
        • Vector (7)
      • Exadata (15)
      • SQL*Plus (2)
      • Linux (5)
      • Resources (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 도서

    • 불친절한 SQL 프로그래밍
    • 불친절한 PL/SQL 프로그래밍
  • 링크

    • Connor McDonald
    • Frits Hoogland
    • Jonathan Lewis
    • Julian Dontcheff
    • Julian Dyke
    • Kun Sun
    • Maria Colgan
    • Martin Bach
    • Mike Dietrich
    • Tanel Poder
  • 공지사항

  • 인기 글

  • 태그

    12c
    19c
    21c
    23ai
    case study
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
정희락
Lock-Free Reservation #2
상단으로

티스토리툴바