Run parallel jobs in oracle - oracle

I have a table jobs which is as follows:
JOB_ID STATUS
1 N
2 N
3 N
4 N
5 N
6 N
7 N
8 N
9 N
10 N
11 N
12 N
What I have to do is select 4 job ids at once,set their status to 'Y' and as soon as 1 job is completed another should start running. At any instance, there must be 4 jobs running.
I did research on how to achieve and most of the documents suggested using scheduler jobs. However, I could not figure out how to do it.
Here is a code sample of what I have done:
CREATE OR REPLACE PROCEDURE sp_processTask
(
JobID NUMBER
)
AS
vblSQL VARCHAR2(32767);
vJobID NUMBER;
BEGIN
vJobID:=JobID;
EXECUTE IMMEDIATE'insert into job_logs values('''||vJobID||''',sysdate,sysdate)';
vblSQL:='UPDATE jobs
SET status=''Y''
WHERE job_ID='||vJobID;
EXECUTE IMMEDIATE(vblSQL);
Dbms_Output.put_line(vblSQL);
END;
/
And then passing 4 different job ids at once as follows:
BEGIN
sp_processTask(1);
sp_processTask(2);
sp_processTask(3);
sp_processTask(4);
END;
What should I do to pass another job id as soon as one flag is set to 'Y'? I am using oracle.

Related

Pessimistic lock per page on 2 instances

I have a scheduler which runs on 2 instances, the purpose is to allow the two instances to parallel process the task to gain in time/performance.
I'm using the pessimistic lock on oracle db, with skip locked in order not to block parallel process and allow the lock per page, so that each instance processes a different page.
#Transactional
#Scheduled(cron = ...)
public void process() {
Pageable pageRequest = PageRequest.of(0, 100);
Page<Event> pages = eventRepository.findAll(pageRequest);
while(!pages.isLast()){
pageRequest.next();
pages.forEach(this::processEvent);
pages = eventRepository.findAll(pageRequest);
}
pages.forEach(this::processEvent);
}
EventRepository
#Lock(LockModeType.PESSIMISTIC_WRITE)
#QueryHints({QueryHint(name= "javax.persistence.lock.timeout", value = "-2")})
Page<Event> findAll(Pageable pageable);
what happens is when the first instance applies the lock (on a page), the second instance can't see anything in the table, and the first continues to process all the pages.
I tried to initiate a new transaction in the service (propagation = REQUIRE_NEW) but in vain.
what is missing so that each instance locks one page in one transaction, and if there is an error, it should rollback only the page which has been processed ?
Thank you in advance
By default, a simple SKIP LOCKED query is going to grab everything it can based on the size of the fetch, eg
Session 1
SQL> create table t as
2 select rownum r from dual
3 connect by level <= 10;
Table created.
SQL>
SQL> select * from t
2 for update skip locked;
R
----------
1
2
3
4
5
6
7
8
9
10
10 rows selected.
Session 2
SQL> select * from t
2 for update skip locked;
no rows selected
Session 1 grabbed (and locked) everything that was fetched, leaving nothing for session 2. If you want concurrent access then you need your code to limit the size of the fetch to something you would consider reasonable for your functionality needs, eg I'll use PLSQL but the same concept applies for any language:
Session 1
SQL> set serverout on
SQL> declare
2 rows_to_process sys.odcinumberlist;
3 cursor C is
4 select * from t
5 for update skip locked;
6 begin
7 open c;
8 fetch c bulk collect into rows_to_process limit 5 ;
9 for i in 1 .. rows_to_process.count loop
10 dbms_output.put_line(rows_to_process(i));
11 end loop;
12 close c;
13 end;
14 /
1
2
3
4
5
Session 2
SQL> declare
2 rows_to_process sys.odcinumberlist;
3 cursor C is
4 select * from t
5 for update skip locked;
6 begin
7 open c;
8 fetch c bulk collect into rows_to_process limit 5 ;
9 for i in 1 .. rows_to_process.count loop
10 dbms_output.put_line(rows_to_process(i));
11 end loop;
12 close c;
13 end;
14 /
6
7
8
9
10

How to use CASE-operator for generating different sequences as per condition given

I want to generate a sequence by matching the condition given. I've two sequences in the case condition and depending on the test condition the query should generate the respective sequence. However even though the output is correct both the sequences are being generated and resulting in missed sequence issue. Is there any way that only the success test condition is executed. Below is the query used in oracle DB.
select CASE
WHEN :x=7
THEN seq1.NEXTVAL
ELSE seq2.NEXTVAL
END output from dual;
Suppose I pass x input as 7, I will get nextvalue of seq1 as output which is correct, however the nextvalue for seq2 is also generated in back end and missed the next time sequence is generated.
I need this condition for auditing.
You already know what's going on with your code. See if this helps.
First, create both sequences:
SQL> create sequence seq1;
Sequence created.
SQL> create sequence seq2;
Sequence created.
Now, create two functions, one for each sequence:
SQL> create or replace function f1 return number as begin return seq1.nextval; end;
2 /
Function created.
SQL> create or replace function f2 return number as begin return seq2.nextval; end;
2 /
Function created.
Run the select statement several times; once with input value 7 and several times with other values. But, don't select directly from the sequence - use functions instead:
SQL> select case when &x = 7 then f1
2 else f2
3 end result
4 from dual;
Enter value for x: 7
old 1: select case when &x = 7 then f1
new 1: select case when 7 = 7 then f1
RESULT
----------
1
SQL> /
Enter value for x: 2
old 1: select case when &x = 7 then f1
new 1: select case when 2 = 7 then f1
RESULT
----------
1
SQL> /
Enter value for x: 3
old 1: select case when &x = 7 then f1
new 1: select case when 3 = 7 then f1
RESULT
----------
2
SQL> /
Enter value for x: 4
old 1: select case when &x = 7 then f1
new 1: select case when 4 = 7 then f1
RESULT
----------
3
SQL> /
Enter value for x: 5
old 1: select case when &x = 7 then f1
new 1: select case when 5 = 7 then f1
RESULT
----------
4
OK; let's now check sequence's values:
SQL> select seq1.currval, seq2.currval from dual;
CURRVAL CURRVAL
---------- ----------
1 4
Aha! They aren't the same as they were using your code (i.e. having sequences in the select statement). Therefore, this might be a workaround for your problem.
However, sequences aren't to be used if you want gapless list of numbers. They will provide uniqueness, that's for sure, but - you most probably can't avoid gaps.

how to generate a deadlock scenario in Oracle?

I've been stuck on a Lab question for the last four hours because I generally don't understand what it wants, even with extensive research and flipping through endless slides. EDIT the prologue in question is a dbcreate.sql which creates a series of tables, and then a dbload.sql which inserts values into given tables.
The given question is
Implement in PL/SQL the database transactions that operate on the sample database created in Prologue step and such that their concurrent processing leads to dadeadlock situation. Save the transactions in SQL scripts solution1-1.sql and solution1-2.sql
I feel someone on this site could explain this in a way I can understand! Thank you for your help
EDIT theres a second part to this question
Simulate a concurrent processing of the transaction such that it will lead to a deadlock.
To simulate a concurrent processing of the database transactions use a PL/SQL procedure
SLEEP from the standard PL/SQL package DBMS_LOCK. By "simulation of concurrent
execution" we mean that the first transaction does a bit of work, then it is delayed for a
certain period of time and in the same period of time another transaction is processed.
Finally, after a delay the first transaction completes its job.
The simplest way (untested code):
CREATE OR REPLACE PROCEDURE doUpd ( id1 IN NUMBER, id2 IN NUMBER ) IS
BEGIN
UPDATE tableA set colA = 'upd1' where id = id1;
dbms_lock.sleep (20);
UPDATE tableA set colA = 'upd2' where id = id2;
END;
/
Then run in session 1:
execute doUpd( 21, 12 );
Immediate in session 2:
execute doUpd( 12, 21 );
What we're doing is updating 2 rows of but is a different order.
We would hope that the time between between the updates would be small enough not avoid a deadlock. But if we want to simulate a deadlock, we need add a delay so that we can fire off the updates in another session.
In the example above, session 1 will update the rows with id = 21 , then wait for 20 seconds, then update the row with id 12.
Session 2 will update the rows with id = 12 , then wait for 20 seconds, then update the row with id 21. If session 2 starts whilst session 1 is 'sleeping' we should get a deadlock.
In time order, provided you are quick with starting the session 2 job, you should be aiming for this:
Session 1: UPDATE tableA set colA = 'upd1' where id = 21;
Session 1: sleep 20
Session 2: UPDATE tableA set colA = 'upd1' where id = 12;
Session 2: sleep 20
Session 1: UPDATE tableA set colA = 'upd2' where id = 12; -- blocked until session 2 commit/rollback
Session 2: UPDATE tableA set colA = 'upd2' where id = 21; -- blocked until session 1 commit/rollback
Session 1 and 2 are now deadlocked.
For the first part of your question you can use also this example without DBMS_LOCK package:
CREATE TABLE T1 (c INTEGER, v INTEGER);
INSERT INTO T1 VALUES (1, 10);
INSERT INTO T1 VALUES (2, 10);
COMMIT;
Open session 1
Open session 2
In session 1 execute update t1 set v = v + 10 where c = 1;
In session 2 execute update t1 set v = v + 10 where c = 2;
In session 1 execute update t1 set v = v + 10 where c = 2;
In session 2 execute update t1 set v = v + 10 where c = 1;
Session 1 raises an ORA-00060: deadlock detected while waiting for resource

DBMS_JOB.SUBMIT ORACLE 11g 5 jobs submitted together but 1st job takes unusually longer than rest of 4 jobs although total records processed are same

I am submitting 5 jobs using below code but 1 st jobs takes around an hour more than rest of 4 jobs although number of records processed are same.
loop
V_SEQID := V_SEQID + 1;
DBMS_JOB.SUBMIT(jobNUMBER, 'package_name.'||v_process||'('||l_processid||','''||i_currentrundate||''','''||l_userid||''','''||automanualflag||''','''||l_machinename||''','||i_seqid||','||v_seqid||','||v_min||','||v_sequenceidto||','||v_Batchno||','||G_batch_seq_no||','''||l_tab_delimiter||''');',
SYSDATE,
NULL,
FALSE);
end loop;

How to automate a test in Oracle without using Java?

So I have a stored procedure that needs to be run to grab a daily sum of values (based off day) in the database. Is there an automated approach to do this comparison within Oracle? I was looking around online and couldn't find any examples...
The script I will run to execute the Stored Procedure is as follows:
execute sum_daily;
Some Sample Data is as follows:
Value_ID Value_Tx Value_Type
1 5 A
2 2 A
3 7 B
4 5 C
5 3 C
6 1 D
7 7 F
Expected Value (Inserted by the Stored Procedure):
Sum Value_Type
14 A | B
8 C
1 D
7 F
Is there a way I can test ('automatically' via a script (PL-SQL?)) whether or not the expected values match up with the results inserted by the stored procedure.
Thanks in advance!

Resources