Measuring SQL Execution Outliers (to track performance better)
Abstract: It is a real problem to track SQL performance over the life cycle … Monitorin… ·...
Transcript of Abstract: It is a real problem to track SQL performance over the life cycle … Monitorin… ·...
Abstract: It is a real problem to track SQL performance over the life cycle of large Java frame-work based systems.
Anixter solved this problem by developing a process to transfer the Dynamic Statement Cache data into a history table. This table contains a reformatted SQL statement and an Explain Report as well as the statistics columns for captured statements. Within this presentation, you will get a detailed introduction to the components that are needed to create a Dynamic SQL Cache History process.
Speaker Bio: DB2 Database Administration and Programming since 1988. All versions of DB2.
Motorola, 1998-1992 DB2 DBA
Platinum Technology, Inc 1992-1999, DB2 Internal Application using DB2 C/S Applications and Peoplesoft.
CA Technology 2000-2009 DB2 DBA Manager, Managed DB2 SAP 2005-2009.
DB2 Consultant 2009-2010, Database Design and Performance Management, Migrated DB2 V8-V9.
Anixter Inc, 2010-2012 DB2 DBA, Database Design and Performance Management, Migrated DB2 V9-V10.
Member of IBM DB2 z/OS Customer Advisory Board, 2013
1
Objective 1: Discuss the standard flow of SQL performance testing, and
where Anixter’s Dynamic SQL Cache History process adds value.
- Reformat SQL to make it readable, Insert SQL statement, Explain Report and
statistics into the SQL Cache History table
Objective 2: Anixter’s Dynamic SQL History Table Combines a SQL Explain
Report with the Dynamic SQL Statistics.
- Discuss the tables developed by Anixter.
Objective 3: Anixter’s Native Procedures used to process the SQL Cache
History data.
- Review the Building Blocks used to create the SQL Cache History.
Objective 4: Review Historical Test Results.
- Review several SQL statements used to detect areas for review.
Objective 5: Using this process, Anixter was able to discover a variety of
performance issues.
- Poorly performing Java Hibernate Batch logic
- Inconsistent parameter marker usage
- Poorly performing SQL
2
About Anixter
Anixter is a leading global supplier of communications and security products,
electrical and electronic wire and cable, fasteners and other small components.
Anixter helps its customers specify solutions and make informed purchasing
decisions around technologies, applications and relevant standards.
Throughout the world, Anixter provides innovative supply chain management
solutions to reduce customers' total cost of production and implementation.
Founded in 1957 and headquartered near Chicago, Anixter trades on The New
York Stock Exchange under the symbol AXE.
3
4
5
6
7
8
9
10
11
CREATE TABLE EXPLN_STMT_CACHE_TABLE
( STMT_ID INTEGER NOT NULL
, EXPLAIN_TS TIMESTAMP NOT NULL
, EXPLAIN_USER VARCHAR (16) NOT NULL
, COLLID VARCHAR (128) NOT NULL
, SCHEMA VARCHAR (16) NOT NULL
, BIND_QUALIFIER VARCHAR (16) NOT NULL
, PRIMAUTH VARCHAR (16) NOT NULL
, CURSQLID VARCHAR (16) NOT NULL
, TBNAME VARCHAR (32) NOT NULL
, STATEMENT_TYPE VARCHAR (8) NOT NULL
, WHERE1 VARCHAR (40) NOT NULL
, STMT_LENGTH INTEGER NOT NULL
, STMT_TEXT CLOB NOT NULL
, STAT_EXEC INTEGER NOT NULL
, STAT_GPAG INTEGER NOT NULL
, GPAG_EXEC DECIMAL (14, 2) NOT NULL
, STAT_SYNR INTEGER NOT NULL
, STAT_WRIT INTEGER NOT NULL
, STAT_EROW INTEGER NOT NULL
, EROW_EXEC DECIMAL (14, 2) NOT NULL
, STAT_PROW INTEGER NOT NULL
, PROW_EXEC DECIMAL (14, 2) NOT NULL
, STAT_SORT INTEGER NOT NULL
, STAT_INDX INTEGER NOT NULL
, INDX_EXEC DECIMAL (14, 2) NOT NULL
, STAT_RSCN INTEGER NOT NULL
, STAT_PGRP INTEGER NOT NULL
, STAT_ELAP DECIMAL (14, 6) NOT NULL
, ELAP_EXEC DECIMAL (14, 6) NOT NULL
, STAT_CPU DECIMAL (14, 6) NOT NULL
, CPU_EXEC DECIMAL (14, 6) NOT NULL
, STAT_SUS_SYNIO DECIMAL (14, 6) NOT NULL
, STAT_SUS_LOCK DECIMAL (14, 6) NOT NULL
, STAT_SUS_SWIT DECIMAL (14, 6) NOT NULL
, STAT_SUS_GLCK DECIMAL (14, 6) NOT NULL
, STAT_SUS_OTHR DECIMAL (14, 6) NOT NULL
, STAT_SUS_OTHW DECIMAL (14, 6) NOT NULL
, STAT_RIDLIMT INTEGER NOT NULL
, STAT_RIDSTOR INTEGER NOT NULL
, PROGRAM_NAME VARCHAR (128) NOT NULL
, EXPLAIN_REPORT VARCHAR (15000)
, QUERYNO INTEGER NOT NULL WITH DEFAULT
, TABLE_COUNT INTEGER NOT NULL WITH DEFAULT
, COLUMN_COUNT INTEGER NOT NULL WITH DEFAULT
, PARM_COUNT INTEGER NOT NULL WITH DEFAULT
, SQL_HASH BIGINT NOT NULL WITH DEFAULT
) IN DB.TSNAME ;
CREATE AUXILIARY TABLE EXPLN_STMT_CACHE_AUX
IN DB.TSNAMEL
STORES EXPLN_STMT_CACHE_TABLE
COLUMN STMT_TEXT
;
12
CREATE TABLE EXPLN_STMT_BUS_PROCESS
( SQL_HASH BIGINT NOT NULL
, EXPLAIN_TS TIMESTAMP NOT NULL
, BUS_PROCESS VARCHAR (40) NOT NULL
) IN DBNAME.TSNAME
;
CREATE UNIQUE INDEX EXPLN_STMT_BUS_PROCESS_PK
ON EXPLN_STMT_BUS_PROCESS
( SQL_HASH ASC
, EXPLAIN_TS ASC
, BUS_PROCESS ASC )
13
CREATE TABLE SQL_TEXT
( OBJ VARCHAR (12) NOT NULL
, SEQNO INTEGER NOT NULL
, TEXT VARCHAR (31500) NOT NULL
) IN DBNAME.TSNAME
;
14
15
16
CREATE PROCEDURE START_TRACE ()
VERSION VERSION1
RESULT SETS 1
…
SET U_COMMAND = '-START TRACE (MONITOR) CLASS(29) DEST(GTF) IFCID(316, 318)';
SET U_CMD_LEN = LENGTH(U_COMMAND) ;
CALL SYSPROC.ADMIN_COMMAND_DB2 ( U_COMMAND, U_CMD_LEN,
U_PARSE_TYPE, U_MEMBER, U_COMMANDS_EX, U_IFCA_RET,
U_IFCA_RES, U_XS_BYTES , U_GRP_IFCA_RES, U_GRP_XS_BYTES ,
U_RETURNCODE, U_ERR_MSG ) ;
SET U_COMMAND = '-START TRACE (ACCTG) CLASS(3) DEST(GTF) ';
SET U_CMD_LEN = LENGTH(U_COMMAND) ;
CALL SYSPROC.ADMIN_COMMAND_DB2 ( U_COMMAND, U_CMD_LEN,
U_PARSE_TYPE, U_MEMBER, U_COMMANDS_EX, U_IFCA_RET,
U_IFCA_RES, U_XS_BYTES , U_GRP_IFCA_RES, U_GRP_XS_BYTES ,
U_RETURNCODE, U_ERR_MSG ) ;
DSNW127I ?D2B1 CURRENT TRACE ACTIVITY IS -
TNO TYPE CLASS DEST QUAL IFCID
01 STAT 01,03,04,05, SMF NO
01 06
02 MON 29 GTF NO 316,318
03 ACCTG 01 SMF NO
04 ACCTG 03 GTF NO
*********END OF DISPLAY TRACE SUMMARY DATA*********
DSN9022I ?D2B1 DSNWVCM1 '-DIS TRACE' NORMAL COMPLETION
17
CREATE PROCEDURE CAPTURE_STATEMENT_CACHE
( IN IN_PLAN_USERID VARCHAR(8)
, IN IN_PRIMAUTH VARCHAR(8)
, IN IN_SCHEMA VARCHAR(8)
, IN IN_TEST_NAME VARCHAR(50)
)
VERSION VERSION1
ISOLATION LEVEL CS
RESULT SETS 1
LANGUAGE SQL …
SET CURRENT SQLID = P1.V_PLAN_USERID ;
SET V_SQL = 'EXPLAIN STMTCACHE ALL' ;
PREPARE SEL0 FROM V_SQL ;
EXECUTE SEL0 ;
COMMIT;
SET V_SQL = 'Delete from DSN_STATEMENT_CACHE_TABLE ' ||
' where explain_ts = ? ' ||
' AND ( stat_exec = 0 OR ' ||
' NOT ( PRIMAUTH IN ( ? ) AND ( SCHEMA IN ( ? ) OR SCHEMA LIKE ? ) ) ' ||
' ) ' ;
PREPARE SEL0 FROM V_SQL ;
EXECUTE SEL0 USING P1.V_CACHE_TS, P1.V_PRIMAUTH, P1.V_SCHEMA, P1.V_SCHEMA ;
COMMIT;
SET V_SQL = 'Update DSN_STATEMENT_CACHE_TABLE set collid = ? where explain_ts ' ||
' = ? and stat_exec > 0 ' ;
PREPARE SEL0 FROM V_SQL ;
EXECUTE SEL0 USING IN_TEST_NAME, P1.V_CACHE_TS ;
COMMIT ;
SET V_SQL = 'SELECT
COALESCE(MAX(char(EXPLAIN_TS)),space(26)) as EXPLAIN_TS, count(*) as CNT from ' ||
' DSN_STATEMENT_CACHE_TABLE WHERE explain_ts = ? ' ;
PREPARE SEL2 FROM V_SQL ;
OPEN RET_CURSOR USING P1.V_CACHE_TS ;
18
CREATE PROCEDURE EXPLAIN_STATEMENT_CACHE
( IN IN_TS VARCHAR(26)
, IN IN_SCHEMA VARCHAR(8)
, IN IN_PLAN_USERID VARCHAR(8)
)
VERSION VERSION1
ISOLATION LEVEL CS
RESULT SETS 1
LANGUAGE SQL
…
SET CURRENT SQLID = P1.V_PLAN_USERID ;
SET CURRENT SCHEMA = P1.V_PLAN_USERID ;
SET V_SQL = 'WITH CTE1 AS ( SELECT EXPLAIN_TS, STMT_ID FROM ' ||
' T80DBA.EXPLN_STMT_CACHE_TABLE ' ||
' WHERE EXPLAIN_TS = ? ) ' ||
' SELECT A.STMT_ID ' ||
' FROM DSN_STATEMENT_CACHE_TABLE A ' ||
' LEFT JOIN CTE1 B ' ||
' ON A.EXPLAIN_TS = B.EXPLAIN_TS ' ||
' AND A.STMT_ID = B.STMT_ID ' ||
' WHERE A.EXPLAIN_TS = ? ' ||
' AND ( A.SCHEMA = ? OR A.SCHEMA LIKE ? ) ' ||
' AND B.STMT_ID IS NULL ORDER BY 1 ' ;
PREPARE SEL0 FROM V_SQL ;
SET V_EXPL_OK = 0 ;
SET V_EXPL_BAD = 0 ;
SET RTN = 'OPEN CURSOR C0 ' ;
OPEN C0 USING IN_TS, IN_TS, P1.V_SCHEMA, P1.V_SCHEMA ;
C0_LOOP:
LOOP
SET AT_END=0;
SET EXPL_IND=0;
FETCH C0 INTO VSTMT_ID ;
IF AT_END = 1 THEN
LEAVE C0_LOOP;
END IF;
CALL T80DBA.EXPLAIN_DYNAMIC_REPORTS ( IN_TS, P1.VSTMT_ID) ;
ASSOCIATE RESULT SET LOCATOR (LOC_CUR1, LOC_CUR2 )
WITH PROCEDURE T80DBA.EXPLAIN_DYNAMIC_REPORTS ;
ALLOCATE A1 CURSOR FOR RESULT SET LOC_CUR1;
IF EXPL_IND = 1 THEN
SET V_EXPL_BAD = V_EXPL_BAD + 1 ;
ELSE
FETCH A1 INTO P1.V_ROW ;
IF LOCATE('FAILED=0', P1.V_ROW) > 0 THEN
SET V_EXPL_OK = V_EXPL_OK + 1 ;
ELSE
SET V_EXPL_BAD = V_EXPL_BAD + 1 ;
END IF;
END IF;
CLOSE A1 ;
END LOOP;
CLOSE C0;
COMMIT;
SET V_SQL = 'SELECT char(EXPLAIN_TS) as EXPLAIN_TS, count(*) as CNT from ' ||
' T80dba.EXPLN_STMT_CACHE_TABLE WHERE explain_ts = ? ' ||
' Group By Explain_ts ' ||
' UNION ALL ' ||
' SELECT ''EXPLAIN OK COUNT '' , CAST(? as integer) AS CNT FROM SYSIBM.SYSDUMMY1 ' ||
' UNION ALL ' ||
' SELECT ''EXPLAIN BAD COUNT '' , CAST(? AS INTEGER) AS CNT FROM SYSIBM.SYSDUMMY1 ' ;
PREPARE SEL2 FROM V_SQL ;
OPEN RET_CURSOR USING IN_TS, P1.V_EXPL_OK, P1.V_EXPL_BAD ;
19
CREATE PROCEDURE EXPLAIN_DYNAMIC_REPORTS
( IN IN_TS VARCHAR(26)
, IN_STMT_ID INTEGER
)
VERSION VERSION1
ISOLATION LEVEL CS
RESULT SETS 1
LANGUAGE SQL
…
SELECT V1.STMT_ID, V1.EXPLAIN_TS, CHAR(user,16) as EXPLAIN_USER, V1.COLLID, upper(V1.SCHEMA) AS SCHEMA, UPPER(V1.BIND_QUALIFIER) AS BIND_QUALIFIER, V1.PRIMAUTH, V1.CURSQLID, CAST(( CASE WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%UPDATE %' THEN Substr(Substr(ltrim(V1.stmt_text1), 8, 50), 1, Locate(space(1), Substr(ltrim(V1.stmt_text1), 8, 50))) WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%INSERT %' THEN Substr(Substr(ltrim(V1.stmt_text1), 13, 50), 1, Locate(space(1), Substr(ltrim(V1.stmt_text1), 13, 50))) WHEN ( Upper(ltrim(V1.stmt_text1)) LIKE '%SELECT%' OR Upper(ltrim(V1.stmt_text1)) LIKE '%WITH %' OR Upper(ltrim(V1.stmt_text1)) LIKE '%DELETE %' ) THEN Substr( Substr(ltrim(coalesce(V1.stmt_text2,V1.stmt_text1)), Locate(' FROM ', upper(ltrim(coalesce(V1.stmt_text2,V1.stmt_text1))), 1) + 6, 50), 1, Locate(space(1), Substr(ltrim(coalesce(V1.stmt_text2,V1.stmt_text1)) , Locate(' FROM ', upper(ltrim(coalesce(V1.stmt_text2,V1.stmt_text1))), 1) + 6, 50))) ELSE Space(32) END ) AS VARCHAR(32)) AS tab1, ( CASE WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%DELETE %' THEN 'Delete' WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%UPDATE %' THEN 'Update' WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%INSERT %' THEN 'Insert' WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%SELECT%' THEN 'Select' WHEN Upper(ltrim(V1.stmt_text1)) LIKE '%WITH %' THEN 'Select' ELSE Space(8) END ) AS statement_type, CAST (CASE WHEN locate(' QUERYNO ', upper(Coalesce(V1.stmt_text2,V1.stmt_text1))) > 0 THEN t80dba.val2(left(substr(Coalesce(V1.stmt_text2,V1.stmt_text1), locate(' QUERYNO ', upper(Coalesce(V1.stmt_text2,V1.stmt_text1))) + 9),10)) ELSE 0 END AS INTEGER) as QUERYNO, length(V1.stmt_text1) + coalesce(length(rtrim(V1.stmt_text2)),0) as stmt_length, V1.STMT_TEXT1, V1.STMT_TEXT2, V1.STAT_EXEC, V1.STAT_GPAG, V1.GPAG_EXEC, V1.STAT_SYNR, V1.STAT_WRIT, V1.STAT_EROW, V1.EROW_EXEC, V1.STAT_PROW, V1.PROW_EXEC, V1.STAT_SORT, V1.STAT_INDX, V1.INDX_EXEC, V1.STAT_RSCN, V1.STAT_PGRP, V1.STAT_ELAP, V1.ELAP_EXEC, V1.STAT_CPU, V1.CPU_EXEC, V1.STAT_SUS_SYNIO, V1.STAT_SUS_LOCK, V1.STAT_SUS_SWIT, V1.STAT_SUS_GLCK, V1.STAT_SUS_OTHR, V1.STAT_SUS_OTHW, V1.STAT_RIDLIMT, V1.STAT_RIDSTOR, V1.program_name FROM (SELECT s.collid, s.explain_ts, s.stmt_id, CAST(s.SCHEMA as VARCHAR(16)) as SCHEMA, CAST(s.bind_qualifier AS VARCHAR(16)) AS bind_qualifier, CAST(s.primauth AS VARCHAR(16)) AS primauth, CAST(s.cursqlid AS VARCHAR(16)) AS cursqlid, REPLACE(Translate(CAST(s.stmt_text AS VARCHAR(32000)), SPACE(2), x'090A' ) , SPACE(2), SPACE(1)) AS stmt_text1, ( CASE WHEN LENGTH(s.stmt_text) > 32000 THEN replace(translate(cast(substr(s.stmt_text,32001,32000) as varchar(32000)) ,SPACE(2), x'090A' ) ,SPACE(2),SPACE(1) ) ELSE NULL END ) as stmt_text2, s.stat_exec, s.stat_gpag, CAST(Real(s.stat_gpag) / s.stat_exec AS DECIMAL(14, 2)) AS gpag_exec, s.stat_synr, s.stat_writ, s.stat_erow, CAST(Real(s.stat_erow) / s.stat_exec AS DECIMAL(14, 2)) AS erow_exec, s.stat_prow, CAST(Real(s.stat_prow) / s.stat_exec AS DECIMAL(14, 2)) AS prow_exec, s.stat_sort, s.stat_indx, CAST(Real(s.stat_indx) / s.stat_exec AS DECIMAL(14, 2)) AS indx_exec, s.stat_rscn, s.stat_pgrp, CAST(s.stat_elap as DECIMAL(14,6)) as STAT_ELAP, CAST(Real(s.stat_elap) / s.stat_exec AS DECIMAL(14, 6)) AS elap_exec, CAST(s.stat_cpu as DECIMAL(14,6)) as STAT_CPU, CAST(Real(s.stat_cpu) / s.stat_exec AS DECIMAL(14, 6)) AS cpu_exec, CAST(s.stat_sus_synio as DECIMAL(14,6)) AS stat_sus_synio, CAST(s.stat_sus_lock as DECIMAL(14,6)) AS stat_sus_lock, CAST(s.stat_sus_swit as DECIMAL(14,6)) AS stat_sus_swit, CAST(s.stat_sus_glck as DECIMAL(14,6)) AS stat_sus_glck, CAST(s.stat_sus_othr as DECIMAL(14,6)) AS stat_sus_othr, CAST(s.stat_sus_othw as DECIMAL(14,6)) AS stat_sus_othw, s.stat_ridlimt, s.stat_ridstor, s.program_name FROM dsn_statement_cache_table S WHERE s.explain_ts = ? AND s.STMT_ID between ? AND ? AND LENGTH(s.stmt_text) < 62000 AND s.stat_exec > 0 AND NOT EXISTS (select 1 FROM T80DBA.EXPLN_STMT_CACHE_TABLE E WHERE S.explain_ts = E.explain_ts AND S.STMT_ID = E.STMT_ID AND S.COLLID = E.COLLID ) ) AS v1 WITH UR
20
SET CURRENT SCHEMA = V_BIND_QUALIFIER ;
SET V_SQL = CAST (
CAST('EXPLAIN PLAN SET QUERYNO = ' || CHAR(P1.VQRY) || ‘ FOR ' AS CLOB )
|| RTRIM(REPLACE(VSTMT_TEXT1,'&','?'))
|| COALESCE(RTRIM(REPLACE(VSTMT_TEXT2,'&','?')),SPACE(0))
AS CLOB (100K)) ;
PREPARE EXPL FROM V_SQL ;
Several Explain Exceptions are captured…
DECLARE EXPL_EXCEPTION CONDITION FOR SQLSTATE '34000';
DECLARE EXPL_EXCEPTION2 CONDITION FOR SQLSTATE '42610';
DECLARE EXPL_EXCEPTION3 CONDITION FOR SQLSTATE '42609';
DECLARE EXPL_EXCEPTION4 CONDITION FOR SQLSTATE '42815';
DECLARE CONTINUE HANDLER FOR EXPL_EXCEPTION
SET EXPL_IND = 1;
DECLARE CONTINUE HANDLER FOR EXPL_EXCEPTION2
SET EXPL_IND = 1;
DECLARE CONTINUE HANDLER FOR EXPL_EXCEPTION3
SET EXPL_IND = 1;
DECLARE CONTINUE HANDLER FOR EXPL_EXCEPTION4
SET EXPL_IND = 1;
PREPARE EXPL FROM V_SQL ;
IF EXPL_IND = 0 THEN
. . .
END IF
21
IF EXPL_IND = 0 THEN – if explain prepare is successful
EXECUTE EXPL ;
COMMIT ;
SET CURRENT SCHEMA = DEFAULT ; -- Return Schema to Caller
-- Fetch Explain Report SQL
SELECT TEXT INTO P1.V_SQL
FROM T80DBA.SQL_TEXT VALUES
WHERE OBJ = 'EXPLAIN_01'
AND SEQNO = 1 ;
-- Add the QUERYNO into the SQL
SET P1.V_SQL = REPLACE(CAST(P1.V_SQL AS VARCHAR(32000)),'999999',RTRIM(CHAR(P1.VQRY))) ;
PREPARE SEL1 FROM P1.V_SQL ;
SET AT_END=0;
SET V_EXPL = '';
OPEN C1 ;
C1_LOOP:
LOOP
FETCH C1 INTO V_LINE;
IF AT_END = 1 THEN
LEAVE C1_LOOP;
END IF;
SET V_EXPL = V_EXPL || V_LINE || X'25' ;
END LOOP;
CLOSE C1;
CALL T80DBA.SQL_PARSE_CLOB (
CAST ( CAST(RTRIM(VSTMT_TEXT1) AS CLOB)
|| COALESCE(RTRIM(VSTMT_TEXT2), SPACE(0) ) AS CLOB (100 K ))
, VSTMT_TEXT_OUT1 -- Part 1 of formatted SQL Statement
, VSTMT_TEXT_OUT2 ); -- Part 2 of formatted SQL Statement
SET VSTMT_TEXT = CAST(CAST(RTRIM(VSTMT_TEXT_OUT1) AS CLOB) ||
COALESCE(RTRIM(VSTMT_TEXT_OUT2), SPACE(0) ) AS CLOB (100 K) );
SET V_SQL = CAST ( 'Select count(*) from plan_table '
|| ' where queryno = ? and table_type in (''T'', ''M'') ' AS CLOB (100K) ) ;
PREPARE SEL1 FROM V_SQL ;
OPEN C1 USING P1.VQRY ;
FETCH C1 INTO P1.VTABCNT ;
CLOSE C1;
END IF
INSERT INTO T80DBA.EXPLN_STMT_CACHE_TABLE ( STMT_ID, EXPLAIN_TS, EXPLAIN_USER,
COLLID, SCHEMA, BIND_QUALIFIER, PRIMAUTH …..
SET S_COUNT = 'ROWS PROCESSED=' || RTRIM(CHAR(V_COUNT)) || ', EXPLAINS FAILED=' || RTRIM(CHAR(V_EXPL_FAIL)) ;
SET V_SQL = 'SELECT CAST(? AS VARCHAR(100) ) AS LINE FROM SYSIBM.SYSDUMMY1' ;
PREPARE SEL2 FROM V_SQL ;
OPEN RET_CURSOR USING S_COUNT ;
22
Explain Report Columns
Plan_table
Query Number
Parent Block
Query Block
Plan Number
Method
Join Type
Table Name
- Cardinality
- Pages
- Run Stats Date
Correlation Name
Access Type
Matching Index Columns
Total Index Columns
Index Name
- Clustering Index (Yes/No)
- Clustered (Yes/No)
- Levels
- Cluster Ratio
Index is Unique (U/.)
Index Only (Y/.)
Sort New Table (Unique, Join, Orderby, Groupby)
Sort Composite Table (Unique, Join, Orderby, Groupby)
TSLOCKMOD
Prefetch
Column_FN_Eval – Aggregate Function Evaluated
Mixopseq – Multiple Index Operation Sequence
QBLOCK_TYPE – Query Block Type
DSN_STATEMENT_TABLE
Cost Category (A/B)
PROCMS – Estimated Processor Cost
DSN_PREDICATE_TABLE
Stage 1 Predicate Count
Stage 2 Predicate Count
Screening Column Count
Boolean Term Count
After Join Count
During Join Count
Negation Predicate Count
23
24
CREATE PROCEDURE STOP_TRACE ()
VERSION VERSION1
RESULT SETS 1
…
SET U_COMMAND = ‘-STOP TRACE (MONITOR) CLASS(*) ';
SET U_CMD_LEN = LENGTH(U_COMMAND) ;
CALL SYSPROC.ADMIN_COMMAND_DB2 ( U_COMMAND, U_CMD_LEN,
U_PARSE_TYPE, U_MEMBER, U_COMMANDS_EX, U_IFCA_RET,
U_IFCA_RES, U_XS_BYTES , U_GRP_IFCA_RES, U_GRP_XS_BYTES ,
U_RETURNCODE, U_ERR_MSG ) ;
SET U_COMMAND = ‘-STOP TRACE (ACCTG) CLASS(3) ';
SET U_CMD_LEN = LENGTH(U_COMMAND) ;
CALL SYSPROC.ADMIN_COMMAND_DB2 ( U_COMMAND, U_CMD_LEN,
U_PARSE_TYPE, U_MEMBER, U_COMMANDS_EX, U_IFCA_RET,
U_IFCA_RES, U_XS_BYTES , U_GRP_IFCA_RES, U_GRP_XS_BYTES ,
U_RETURNCODE, U_ERR_MSG ) ;
DSNW127I ?D2B1 CURRENT TRACE ACTIVITY IS -
TNO TYPE CLASS DEST QUAL IFCID
01 STAT 01,03,04,05, SMF NO
01 06
03 ACCTG 01 SMF NO
*********END OF DISPLAY TRACE SUMMARY DATA*********
DSN9022I ?D2B1 DSNWVCM1 '-DIS TRACE' NORMAL COMPLETION
25
SELECT STMT_ID, TBNAME, STATEMENT_TYPE, COLUMN_COUNT, TABLE_COUNT, PARM_COUNT, STMT_LENGTH, STMT_TEXT, QUERYNO, EXPLAIN_REPORT, STAT_EXEC, STAT_GPAG, GPAG_EXEC, STAT_SYNR, STAT_WRIT, STAT_EROW, EROW_EXEC, STAT_PROW, PROW_EXEC, STAT_SORT, STAT_INDX, INDX_EXEC, STAT_RSCN, STAT_PGRP, STAT_ELAP, ELAP_EXEC, STAT_CPU, CPU_EXEC, DEC( (STAT_SUS_SYNIO + STAT_SUS_LOCK + STAT_SUS_SWIT + STAT_SUS_OTHR + STAT_SUS_OTHW )/STAT_EXEC , 14, 6) AVG_WAIT, STAT_SUS_SYNIO, STAT_SUS_LOCK, STAT_SUS_SWIT, STAT_SUS_GLCK, STAT_SUS_OTHR, STAT_SUS_OTHW, STAT_RIDLIMT, STAT_RIDSTOR , PROGRAM_NAME, EXPLAIN_TS, COLLID, BIND_QUALIFIER, PRIMAUTH, CURSQLID , PROGRAM_NAME FROM T80DBA.EXPLN_STMT_CACHE_TABLE A WHERE EXPLAIN_TS = IN_TS AND SCHEMA = IN_SCHEMA
ORDER BY GPAG_EXEC DESC ;
26
27
Summary of all test results.
SELECT CHAR(EXPLAIN_TS) AS EXPLAIN_TS,
CAST(COLLID AS CHAR(45) ) AS TEST,
COUNT(*) AS CNT
FROM T80DBA.EXPLN_STMT_CACHE_TABLE
GROUP BY EXPLAIN_TS, COLLID
ORDER BY 1 DESC ;
28
Summary of a test, use this SQL to measure overall DB2 workload.
SELECT CHAR(EXPLAIN_TS) AS TS, COLLID, COUNT(*) AS
STATEMENT_CNT ,
SUM(STAT_EXEC) AS TOTAL_EXECS,
MIN(STAT_EXEC) AS MIN_STAT_EXEC,
MAX(STAT_EXEC) AS MAX_STAT_EXEC,
SUM(STAT_ELAP) AS TOTAL_ELAP,
SUM(STAT_CPU) AS TOTAL_CPU,
SUM(STAT_GPAG) AS TOTAL_GETPAGES
FROM T80DBA.EXPLN_STMT_CACHE_TABLE
WHERE EXPLAIN_TS = '2013-02-19-08.44.48.640000'
GROUP BY CHAR(EXPLAIN_TS), COLLID
ORDER BY TS DESC
WITH UR ;
29
** Summarizing a Test by Table and Statement_Type **
SELECT COLLID, SCHEMA, TBNAME, COUNT(*) AS STATEMENT_CNT ,
SUM(STAT_EXEC) AS TOTAL_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Select' THEN STAT_EXEC ELSE 0 END) AS SELECT_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Update' THEN STAT_EXEC ELSE 0 END) AS UPD_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Insert' THEN STAT_EXEC ELSE 0 END) AS INS_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Delete' THEN STAT_EXEC ELSE 0 END) AS DEL_EXECS,
SUM(STAT_PROW) AS ROWS_PROCESSED,
SUM(STAT_ELAP) AS TOTAL_ELAP, SUM(STAT_CPU) AS TOTAL_CPU,
SUM(STAT_GPAG) AS TOTAL_GETPAGES
FROM T80DBA.EXPLN_STMT_CACHE_TABLE
WHERE EXPLAIN_TS = '2013-02-21-13.25.41.210000'
GROUP BY COLLID , SCHEMA, TBNAME
UNION ALL
SELECT COLLID, SCHEMA, CAST('ZZ TOTALS' AS CHAR(32) ) AS TBNAME, COUNT(*) AS STATEMENT_CNT ,
SUM(STAT_EXEC) AS TOTAL_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Select' THEN STAT_EXEC ELSE 0 END) AS SELECT_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Update' THEN STAT_EXEC ELSE 0 END) AS UPD_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Insert' THEN STAT_EXEC ELSE 0 END) AS INS_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'Delete' THEN STAT_EXEC ELSE 0 END) AS DEL_EXECS,
SUM(STAT_PROW) AS ROWS_PROCESSED,
SUM(STAT_ELAP) AS TOTAL_ELAP, SUM(STAT_CPU) AS TOTAL_CPU,
SUM(STAT_GPAG) AS TOTAL_GETPAGES
FROM T80DBA.EXPLN_STMT_CACHE_TABLE
WHERE EXPLAIN_TS = '2013-02-21-13.25.41.210000'
GROUP BY COLLID , SCHEMA
ORDER BY 1,2,3,4 ;
30
All of the SQL above is for one closing transaction.
A good example of Java Batch logic in an on-line transaction.
8.6 seconds to process about 1500 updates and inserts.
I prototyped a Native Procedure that could process the Inserts/Updates in less
than one second.
Only 1 statement per table was really needed to process each tables Inserts or
Updates.
31
Summarizing by Get Pages descending with BUS_PROCESS Counts
WITH CTE_FN AS (SELECT A.EXPLAIN_TS, A.SQL_HASH,
COUNT(DISTINCT B.BUS_PROCESS) AS BUS_PROCESS_CNT
FROM T80DBA.EXPLN_STMT_CACHE_TABLE A
LEFT JOIN T80DBA.EXPLN_STMT_BUS_PROCESS B
ON A.SQL_HASH = B.SQL_HASH
WHERE A.EXPLAIN_TS = '2013-02-19-08.44.48.640000'
GROUP BY A.EXPLAIN_TS, A.SQL_HASH
HAVING COUNT(DISTINCT B.BUS_PROCESS) > 0 )
SELECT CHAR(A.EXPLAIN_TS) AS TS, A.COLLID, A.SCHEMA, A.TAB1 AS TBNAME,
COALESCE(C.BUS_PROCESS_CNT,0) AS BUS_PROCESS_CNT, COUNT(*) AS STATEMENT_CNT ,
SUM(STAT_EXEC) AS TOTAL_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'SELECT' THEN STAT_EXEC ELSE 0 END) AS SELECT_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'UPDATE' THEN STAT_EXEC ELSE 0 END) AS UPD_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'INSERT' THEN STAT_EXEC ELSE 0 END) AS INS_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'DELETE' THEN STAT_EXEC ELSE 0 END) AS DEL_EXECS,
SUM(STAT_PROW) AS ROWS_PROCESSED,
SUM(STAT_ELAP) AS TOTAL_ELAP, SUM(STAT_CPU) AS TOTAL_CPU,
SUM(STAT_GPAG) AS TOTAL_GETPAGES
FROM T80DBA.EXPLN_STMT_CACHE_TABLE A
LEFT JOIN CTE_FN C
ON A.EXPLAIN_TS = C.EXPLAIN_TS
AND A.SQL_HASH = C.SQL_HASH
WHERE A.EXPLAIN_TS = '2013-02-19-08.44.48.640000'
GROUP BY CHAR(A.EXPLAIN_TS), A.COLLID , A.SCHEMA, A.TAB1, C.BUS_PROCESS_CNT
UNION ALL
SELECT CHAR(A.EXPLAIN_TS) AS TS, COLLID, SCHEMA, CAST('ZZ TOTALS' AS CHAR(32) ) AS TBNAME
, 0 AS BUS_PROCESS_CNT, COUNT(*) AS STATEMENT_CNT ,
SUM(STAT_EXEC) AS TOTAL_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'SELECT' THEN STAT_EXEC ELSE 0 END) AS SELECT_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'UPDATE' THEN STAT_EXEC ELSE 0 END) AS UPD_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'INSERT' THEN STAT_EXEC ELSE 0 END) AS INS_EXECS,
SUM( CASE WHEN STATEMENT_TYPE = 'DELETE' THEN STAT_EXEC ELSE 0 END) AS DEL_EXECS,
SUM(STAT_PROW) AS ROWS_PROCESSED,
SUM(STAT_ELAP) AS TOTAL_ELAP, SUM(STAT_CPU) AS TOTAL_CPU,
SUM(STAT_GPAG) AS TOTAL_GETPAGES
FROM T80DBA.EXPLN_STMT_CACHE_TABLE A
WHERE A.EXPLAIN_TS = '2013-02-19-08.44.48.640000'
GROUP BY CHAR(A.EXPLAIN_TS), COLLID , SCHEMA
ORDER BY 15 DESC ;
32
Summarizing Results by Get Pages descending with BUS_PROCESS Counts
The Totals Line will be the first line, followed by the statements with the
highest Get Pages per execution.
Note the Business Process Count column. This count indicates how many bus
processes the statement was executed in.
33
34
The results of a Call to SELECT_EXPL_DATA will return in Get Pages per
Execution Descending.
The top ten rows returned are generally among the more resource consuming
SQL.
35
The STMT_TEXT and EXPLAIN_REPORT columns can be accessed by
double clicking the ‘…’ in the column cell.
Data Studio wraps the SQL with in the Long Data pop-up box. However, the
SQL is really formatted with line feeds.
36
By double clicking the column headers in Data Studio, the results set will be
sorted ascending or descending.
This test represented a single business transaction test.
Why was stmt_id 283476 executed 4,979 times just for one transaction?
Good question for developers!!
37
Right mouse click in any cell and choose Export Current Results to create and
XML or CSV file.
The XML file format provides a nice format for sending the SQL and Explain
Reports to the development teams.
38
39
40
41
42
Stmt_id 259634 must have issues, This SQL needs to be reviewed!!
43
44
45