I intended to create a simple load test :
- An ACCOUNT TABLE
- A Procedure Updating the Account Balance
- A Start-Script using Oracle dbms_scheduler to run the procedure in parallel.
Each procedure Call covers the Account_ID 1-16 and increments the Account Balance 500 times. So at the end the Account Balance is 500. For the test-case I run 4 concurrent background jobs per Account ID to increment the Account Balance, I would expect 2000 for each Account ID but the results are in randomly a range of 1850 till 1950; I use SELECT for UPDATE to lock the Account ID to be updated, but it does not work. Any ideas?
The table creation :
DROP TABLE ACCOUNTS;
CREATE TABLE ACCOUNTS ( ACC_ID INTEGER NOT NULL , ACC_BALANCE NUMBER (9,3) DEFAULT 0 NOT NULL , START_TIME TIMESTAMP, END_TIME TIMESTAMP);
ALTER TABLE ACCOUNTS ADD CONSTRAINT ACCOUNTS_PK PRIMARY KEY (ACC_ID);
INSERT INTO ACCOUNTS SELECT ROWNUM , 0 , NULL, NULL FROM DBA_USERS DT WHERE ROWNUM <= 16;
COMMIT WORK;
The Procedure :
CREATE OR REPLACE PROCEDURE Paccount_Test(p_Acc_Id IN INTEGER
,p_Incr IN NUMBER
,p_Num_Incr IN INTEGER
,p_Work_Loops IN INTEGER) IS
Xx INTEGER := 0;
l_Acc_Balance Accounts.Acc_Balance%TYPE;
BEGIN
UPDATE Accounts SET Acc_Balance = 0.0, Start_Time = Systimestamp, End_Time = NULL WHERE Acc_Id = p_Acc_Id;
COMMIT WORK;
FOR Nloops IN 1 .. p_Num_Incr LOOP
SELECT Acc_Balance INTO l_Acc_Balance FROM Accounts WHERE Acc_Id = p_Acc_Id FOR UPDATE;
-- Amoount of work ...
FOR Ii IN 1 .. p_Work_Loops LOOP
Xx := Xx + 1;
END LOOP;
UPDATE Accounts SET Acc_Balance = Acc_Balance + p_Incr WHERE Acc_Id = p_Acc_Id;
COMMIT WORK;
END LOOP;
UPDATE Accounts SET End_Time = Systimestamp WHERE Acc_Id = p_Acc_Id;
COMMIT WORK;
END Paccount_Test;
The Starter Script for 64 Processes, ...
BEGIN
FOR Acc_Id IN 1 .. 64 LOOP
Dbms_Scheduler.Create_Job(Job_Name => 'One_Time_Job' || Acc_Id
,Job_Type => 'PLSQL_BLOCK'
,Job_Action => 'begin paccount_test (p_acc_id => ' || (mod(Acc_Id,16)+1) ||
', p_incr => 1, p_num_incr => 500, p_work_loops => 400000); end;'
,Start_Date => SYSDATE
,Enabled => TRUE
,Auto_Drop => TRUE
,Comments => 'one-time job');
END LOOP;
END;
/
Ich checked DBA_SCHEDULER_JOB_LOG, but did not see any error, also in V$session 64 Background processes were active.
Example Output of SELECT query :
ACC_ID ACC_BALANCE
1 1932,000
2 1900,000
3 1902,000
4 1883,000
5 1910,000
6 1939,000
7 1920,000
8 1910,000
9 1865,000
10 1920,000
11 1916,000
12 1888,000
13 1896,000
14 1909,000
15 1918,000
16 1935,000