DB2 locking and concurrency is a critical part of DB2 as well as batch performance. Batch update jobs processing large amounts of data will need to have restart logic through the use of the COMMIT statement and a program data save area. This will identify the restart point. Commit frequency should be an input parameter where possible, and not hard-coded in the program. See the following points to make a program Restartable:
a) declare 2 cursors to select rows to be updated in the table. Code an order by clause for the columns of the unique index. The first cursor will select the rows we want.
e.g.Table for Restart is
CREATE TABLE CHKPT_RSTRT ( PROGRAM_NAME CHAR(8) NOT NULL, ITERATION CHAR(4) NOT NULL, COMMIT_FREQUENCY SMALLINT NOT NULL WITH DEFAULT, NO_OF_COMMITS SMALLINT NOT NULL WITH DEFAULT, CHECKPOINT_TIME TIMESTAMP NOT NULL WITH DEFAULT, CHECKPOINT_AREA CHAR(254) NOT NULL WITH DEFAULT, PRIMARY KEY (PROGRAM_NAME,ITERATION) ) IN DATABASE.TABLE ; CREATE UNIQUE INDEX XCHKPRST (PROGRAM_NAME,ITERATION) CLUSTER;
QUERY EXEC SQL DECLARE PBNPRLV_CSR1 CURSOR FOR SELECT CNTRL_NO, BPRO_NO, BNPRLV_NO, PBNH_EFF_DT FROM PBNPRLV ORDER BY CNTRL_NO,BPRO_NO, PBNH_EFF_DT END-EXEC.
The second cursor is for use after issuing commits and restarts processing. We have to reposition the cursor by using where clause that reflects the order by on the primary key.
EXEC SQL DECLARE PBNPRLV_CSR1 CURSOR FOR SELECT CNTRL_NO, BPRO_NO, BNPRLV_NO, PBNH_EFF_DT FROM PBNPRLV WHERE ((CNTRL_NO= :CHKPT-CNTRL-NO AND BPRO_NO = :CHKPT-BPRO-NO AND PBNH_EFF_DT> :CHKPT- PBNH-EFF-DT) OR (CNTRL_NO = :CHKPT-CNTRL-NO AND BPRO_NO > :CHKPT-BPRO-NO ) OR (CNTRL_NO > : CHKPT-CNTRL-NO)) AND CNTRL_NO >= : CHKPT-CNTRL-NO ORDER BY CNTRL_NO, BPRO_NO, PBNH_EFF_DT END-EXEC.
b) select the row from CHKPT-RESTART table for the program and iteration being processed.
c) If it is the first time through and CHECKPOINT_AREA contains data, the program is restarted. Move appropriate values from CHECKPOINT_AREA to host variable used in the second cursor and open it.
d) Fetch the row from the opened cursor.
e) If fetch is successful increment the WS variable that counts successful fetches.
f) Perform UPDATE for PBNPRLV row that was fetched.
g) If the fetch counter equals the COMMIT_FREQUENCY, perform a commit paragraph. This paragraph should increment and Update NO_OF_COMMITS and CHECKPOINT_AREA column with data retrieved from the table and set CHECKPOINT_TIME to the current timestamp and issue a COMMIT and reset the fetch counter to zero.
h) After commit, the cursor will be closed unless WITH HOLD option is specified.
i) When update processing is complete, reset the values of the columns in the CHKPT_RSTRT table to their original default value.
We can use the DSNTIAR subroutine to convert an SQLCODE into a text message. The syntax is
CALL 'DSNTIAR' USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.
We did a search in MPROD2 for C37BAT31 (Batch COBOL) and the modules that use DSNTIAR are in the attached list. After calling DSNTIAR we get the system text message in array ERROR-MESSAGE for SQLCODE in SQLCA.
Let’s say the WORKING-STORAGE variables defined for DSNTIAR are
01 WS010-MISC-FIELDS. 05 WS010-SQLCODE PIC +9(05). 05 WS010-MSG-LINE PIC X(120) VALUE SPACES. 05 WS010-SUBSCRIPT PIC 9(02) VALUE ZERO. 05 WS010-TEXT-LENGTH PIC S9(9) COMP VALUE +120. 05 WS010-DB2-ERROR-MESSAGE. 10 WS010-MSG-LENGTH PIC S9(4) COMP VALUE +960. 10 WS010-MSG-TEXT PIC X(120) OCCURS 8 TIMES.
The code for calling DSNTIAR is
CALL 'DSNTIAR' USING SQLCA, WS010-DB2-ERROR-MESSAGE, WS010-TEXT-LENGTH The code for displaying error message returned by DSNTIAR is PERFORM VARYING WS010-SUBSCRIPT FROM 1 BY 1 UNTIL WS010-SUBSCRIPT > 8 IF WS010-MSG-TEXT (WS010-SUBSCRIPT) > SPACES DISPLAY WS010-MSG-TEXT (WS010-SUBSCRIPT) END-IF END-PERFORM.
After calling DSNTIAR we have to call ‘CEE3ABD’ or ‘ABEND’ to stop processing inside DB2 handler or Application Programming Interface(API).
Utilization of dynamic SQL – DB2 locking and concurrency
While this has its advantages, it cannot be administered via a DBA. Also, with some technologies, excessive catalog locking conflicts with DBA activity. Utilize this in reporting only environments where absolutely necessary. Provide an easy method to capture SQL and possibly EXPLAIN the access paths. If not reporting, use Stored Procedures or APIs.
Host variable – DB2 locking and concurrency
Many times, a variable not correctly defined will lead to errors that are difficult to detect. Where appropriate, use DCLGEN variables produced from the system catalog.
LOCK TABLE or DDL in the program – DB2 locking and concurrency
These cause issues with concurrency. Avoid these unless the DDL is for Declared Temporary Tables.
Call the DBA with vague DB2 error – DB2 locking and concurrency
INCLUDE the SQLCA. Use appropriate error code logic after each SQL call. Provide all the error information given by calling the DSNTIAR program or using GET DIAGNOSTICS (V8) or using Java methods that provide detailed information
Moving a numeric constant to the length field of a VARCHAR data type – DB2 locking and concurrency
Causes the row to be excessively large wasting DASD and causing extraneous I/Os.
EXEC SQL SET: calc-length = LENGTH(RTRIM(:host-var)) END-EXEC MOVE calc-length TO LL-field (in Cobol 49 level)
∙ FOR READ/FETCH ONLY or WITH UR for retrieval only cursors.
∙ OPTIMIZE when you know the accurate number of rows that will be fetched
∙ ORDER BY only when the sequence is important
∙ WITH HOLD statement to prevent COMMIT from destroying the cursor position in batch Programs.
∙ Select only those fields that you truly need
∙ Use only DCLGEN variables as predicates
While declaring CURSOR in handler we should use OPTIMIZE FOR n ROWS, if we want to pass only n rows from DB2 handler back to calling program. In this case, DB2 handler only fetches n rows into the intermediate result table. The syntax is
DECLARE C1 CURSOR FOR SELECT * FROM PACS_TRANS_TRACK OPTIMIZE FOR 5000 ROWS FOR FETCH ONLY
OPTIMIZE FOR tells DB2 to proceed under the assumption that at most a total of integer rows are to be retrieved from the result table. Without this clause, DB2 would assume that all rows of the result table are to be retrieved, and would optimize accordingly. Optimizing for integer rows, if at most this number of rows are fetched, could improve performance.
E.g.
We want to fetch PRCTR_CD, CTLHX_NM, and CTLHX_EFF_DT from CTLHX table with the descending order of CTLHX_EFF_DT.
EXEC SQL DECLARE CTLHX_CSR CURSOR FOR SELECT PRCTR_CD, CTLHX_NM, CTLHX_EFF_DT FROM CTLHX WHERE CNTRL_NO =: CNTRL-NO AND CTLHX_SUPRCD_DTS ='0001-01-01-00.00.00.000000' AND CTLHX_EFF_DT <=: CTLHX-EFF-DT ORDER BY CTLHX_EFF_DT DESC FETCH FIRST 1 ROW ONLY WITH UR END-EXEC
As this is retrieval only so we have used WITH UR option. Here the order is important so we used the ORDER BY clause. As if we use DCLGEN variables. As we are interested in retrieving the first row so we have used the clause FETCH FIRST 1 ROW ONLY clause. We have used literal ‘0001-01-01-00.00.00.000000’ so that optimizer will know at BIND time the values.
A well-maintained product backlog is crucial for successful product development. It serves as a single…
Incremental value to the customer refers to the gradual delivery of small, functional parts of…
A Product Market refers to the group of potential customers who might be interested in…
The Professional Agile Leadership - Evidence-Based Management (PAL-EBM) certification offered by Scrum.org is designed for…
The Professional Agile Leadership (PAL I) certification, offered by Scrum.org, is designed to equip leaders…
Choosing the right Scrum Master Certification depends on your current experience and career goals. If…