db2 v7 and beyond"
DESCRIPTION
TRANSCRIPT
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
11
DB2 V7 and Beyond:DB2 V7 and Beyond:
How newer DB2 How newer DB2 capabilities can simplify capabilities can simplify
age-old coding age-old coding challenges on Z/os challenges on Z/os
machinesmachines
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
22
IBM focused on the applications IBM focused on the applications developers this time, not just the developers this time, not just the
administrators!administrators!
Newer features of DB2 can really Newer features of DB2 can really help:help:– Simplify programsSimplify programs– Enable granting of previously avoided Enable granting of previously avoided
user requestsuser requests– Improve reliability Improve reliability – Increase table availabilityIncrease table availability– Allow program features on the Allow program features on the
mainframe that users have become mainframe that users have become accustomed to on distributed platformsaccustomed to on distributed platforms
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
33
DB2 V7 and Beyond:DB2 V7 and Beyond:
Mismatched Joins –Mismatched Joins – Now actually possible Now actually possible
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
44
Joining Tables with Joining Tables with Mismatched Data Mismatched Data
TypesTypes In prior versions of DB2 this was a In prior versions of DB2 this was a
severe index killersevere index killer Example:Example:
Table A has CUSTOMER_NBR stored as Table A has CUSTOMER_NBR stored as CHAR(8) but it really only contains CHAR(8) but it really only contains numeric datanumeric dataTable B has the same column but Table B has the same column but stores it as an INTEGERstores it as an INTEGER
You want to join ‘emYou want to join ‘em
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
55
Joining Tables with Joining Tables with Mismatched Data Mismatched Data TypesTypes The old ways:The old ways:
– Create a cross-reference table with both Create a cross-reference table with both columns columns
Maintenance problem and wastes spaceMaintenance problem and wastes space
– Put columns on both tables with both Put columns on both tables with both datatypesdatatypes
Confusing and wastes spaceConfusing and wastes space
– Open a cursor against A, fetch through it, Open a cursor against A, fetch through it, cycling a second cursor against B for each cycling a second cursor against B for each rowrow
Very inefficient and messy to codeVery inefficient and messy to code
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
66
Joining Tables with Joining Tables with Mismatched Data Mismatched Data TypesTypes Newer ways:Newer ways:
– DB2 is much more tolerant now of DB2 is much more tolerant now of what is on the right side of the what is on the right side of the operator (=, <, > etc)operator (=, <, > etc) Most Scalar functions are allowedMost Scalar functions are allowed Concatenation is allowedConcatenation is allowed Mismatched lengths are allowed in Mismatched lengths are allowed in
many casesmany cases
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
77
Joining Tables with Joining Tables with Mismatched Data Mismatched Data TypesTypes In our example of joining two tables with In our example of joining two tables with
mismatched datatypes, we can do some mismatched datatypes, we can do some conversionsconversions
WHERE A.CUST_NBR = WHERE A.CUST_NBR = SUBSTR(CHAR(DIGITS(B.CUST_NBR))),3,8SUBSTR(CHAR(DIGITS(B.CUST_NBR))),3,8))– DIGITS lets us extract the Integer as DIGITS lets us extract the Integer as
characterscharacters WHERE B.CUST_NBR = WHERE B.CUST_NBR =
INTEGER(A.CUST_NBR)INTEGER(A.CUST_NBR)
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
88
Joining Tables with Joining Tables with Mismatched LengthsMismatched Lengths
This also was an index killer in prior This also was an index killer in prior versions of DB2 versions of DB2
Example:Example:Table A has CUSTOMER_NBR stored as Table A has CUSTOMER_NBR stored as CHAR(8) and CUSTOMER_LOC stored CHAR(8) and CUSTOMER_LOC stored as CHAR(4) as CHAR(4) Table B has one column with the two Table B has one column with the two combined CUST_LOC_NBR CHAR(12)combined CUST_LOC_NBR CHAR(12)
You want to join ‘emYou want to join ‘em
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
99
Joining Tables with Joining Tables with Mismatched LengthsMismatched Lengths Again, we can use concatenations or Again, we can use concatenations or
substringssubstrings WHERE A.CUST_NBR = WHERE A.CUST_NBR = SUBSTR(CUST_LOC_NBR,5,8)SUBSTR(CUST_LOC_NBR,5,8)
AND A.CUST_LOC = AND A.CUST_LOC = SUBSTR(CUST_LOC_NBR,1,4)SUBSTR(CUST_LOC_NBR,1,4)
– This will split out the two componentsThis will split out the two components
WHERE B.CUST_LOC_NBR =WHERE B.CUST_LOC_NBR = A.CUST_LOC||A.CUST_NBRA.CUST_LOC||A.CUST_NBR
– This will put the two components togetherThis will put the two components together
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1010
Joining Tables with Joining Tables with Mismatched Data Mismatched Data TypesTypes Remember a few things:Remember a few things:
– Always have the column you want to Always have the column you want to index on to the left of the operatorindex on to the left of the operator
– NEVER put a function on the left of NEVER put a function on the left of the operator if you want indexes to the operator if you want indexes to be usedbe used
– ALWAYS do an EXPLAIN, these tricks ALWAYS do an EXPLAIN, these tricks don’t work in every scenariodon’t work in every scenario
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1111
DB2 V7 and Beyond:DB2 V7 and Beyond:
Nested Table Nested Table Expressions- Cool toy but Expressions- Cool toy but
are they usefulare they useful
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1212
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions What is an NTE?What is an NTE?
– Treating a Select as if it were a tableTreating a Select as if it were a table
SELECT * SELECT *
FROM TABLE (FROM TABLE (
SELECT * FROM SELECT * FROM
TABLE_A A, TABLE_A A,
TABLE_B B)TABLE_B B)
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1313
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions What good are they?What good are they?
– You can do GROUP BYs on the result You can do GROUP BYs on the result of another GROUP BY of another GROUP BY
– You can do incompatible JOINS on You can do incompatible JOINS on multiple tablesmultiple tables
– You can make the DBAs REALLY You can make the DBAs REALLY angry if you are not careful – we’ll angry if you are not careful – we’ll get to that get to that
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1414
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions Let’s do it - Compounded Group By Let’s do it - Compounded Group By
– Get me the number of customers and total big bill amount Get me the number of customers and total big bill amount at each terminal that has at least 1000 bills > 500.00 eachat each terminal that has at least 1000 bills > 500.00 each
SELECT X.TERM, COUNT(*), SUM(X.TOTAL_AMT)SELECT X.TERM, COUNT(*), SUM(X.TOTAL_AMT) FROM TABLE (FROM TABLE ( SELECTSELECT TERMINAL, CUSTOMER, SUM(BILL_AMT), COUNT(*)TERMINAL, CUSTOMER, SUM(BILL_AMT), COUNT(*)
FROM TBL_BILLSFROM TBL_BILLS WHERE BILL_AMT > 500.00WHERE BILL_AMT > 500.00 GROUP BY TERMINAL, CUSTOMERGROUP BY TERMINAL, CUSTOMER HAVING COUNT(*) > 1000HAVING COUNT(*) > 1000 ) AS X(TERM, CUST, TOTAL_AMT, BILL_CNT)) AS X(TERM, CUST, TOTAL_AMT, BILL_CNT) GROUP BY TERMINALGROUP BY TERMINAL
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1515
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions Let’s do it - Incompatible Joins Let’s do it - Incompatible Joins You need to join multiple tables,You need to join multiple tables,
– Two of the tables must be LEFT Two of the tables must be LEFT OUTER JOINED and then you want to OUTER JOINED and then you want to LEFT OUTER JOIN a third table to the LEFT OUTER JOIN a third table to the results of thisresults of this
– How do you do this???? How do you do this???? Nested Table Expressions Nested Table Expressions
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1616
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressionsSelect * Select * FROM TBL_A aFROM TBL_A a left outer join tableleft outer join table ((
select * select * from tbl_b bfrom tbl_b b left outer join tbl_c c left outer join tbl_c c on b.customer_nbr = c.customer_nbron b.customer_nbr = c.customer_nbr ) As x ) As x on a.customer_loc = x.customer_loc on a.customer_loc = x.customer_loc
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1717
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions Lets make a DBA angry!
– Actually, that’s not such a good idea, so lets look at a few things to keep in mind to avoid this
Be aware that NTEs use an area of DB2 called DSNDB07– This is a shared area used by sorts, NTEs,
materialized views and a lot of other things
– This can become a real problem if you are not careful, this area is NOT limitless!
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1818
Real use for NTEs Real use for NTEs Nested Table Nested Table ExpressionsExpressions So, how Do we avoid causing problems?
– Use Indexes, both inside and outside NTE– Use FETCH FIRST nnn ROWS ONLY
This limits the total rows returned, but not the rows on the inside SQL statement
– Carefully craft your select inside the NTE to return a controlled result
Don’t just join both tables and get an NTE with 100000 rows then select off two with the outer select
– If you are not sure you can control it, don’t use it Your scenario might be one to do the old way with a couple
of cursors
– Use EXPLAIN!
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
1919
DB2 V7 and Beyond:DB2 V7 and Beyond:
Taming RIDLIST indexingTaming RIDLIST indexing
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2020
Taming RIDLIST Taming RIDLIST processingprocessing What is it?What is it?
– Every row in a table has a Row Every row in a table has a Row Identifier (RID) which is used Identifier (RID) which is used internally by DB2internally by DB2
– Some SQL really could benefit from Some SQL really could benefit from two different Indexes, but DB2 can two different Indexes, but DB2 can only use one at a time… Until NOW!only use one at a time… Until NOW!
– At the simplest level, a RIDLIST At the simplest level, a RIDLIST index process is simply a join index process is simply a join between two index resultsbetween two index results
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2121
Taming RIDLIST Taming RIDLIST processingprocessing How does it work?How does it work?
– DB2 scans one or more indexes and DB2 scans one or more indexes and creates a temporary result which creates a temporary result which consists of the RIDS of all rows consists of the RIDS of all rows qualifying for each indexqualifying for each index
– It uses these results to rescan It uses these results to rescan looking for the LEFT JOIN of all of the looking for the LEFT JOIN of all of the results (i.e.: rows from each that results (i.e.: rows from each that match ALL criteria)match ALL criteria)
– You then get the desired resultsYou then get the desired results
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2222
Taming RIDLIST Taming RIDLIST processingprocessing Sounds good, how can this help?Sounds good, how can this help?
– Can undo the harm caused by Can undo the harm caused by having ‘OR’s mixed in with ‘AND’s having ‘OR’s mixed in with ‘AND’s on a tableon a table
– Allows a column in one table to be Allows a column in one table to be matched to multiple columns in a matched to multiple columns in a second tablesecond table
– Can make previously unworkable Can make previously unworkable SQL work decentlySQL work decently
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2323
Taming RIDLIST Taming RIDLIST processingprocessing Here’s an exampleHere’s an example
– SELECT * SELECT * FROM TBL_CUST A, TBL_BILL BFROM TBL_CUST A, TBL_BILL B
WHERE A.CUST_NBR = :WS-CUSTWHERE A.CUST_NBR = :WS-CUST AND B.CUST_NBR = A.CUST_NBRAND B.CUST_NBR = A.CUST_NBR AND (A.CUST_LOC = B.LOC_1 ORAND (A.CUST_LOC = B.LOC_1 OR
A.CUST_LOC = B.LOC_2 ORA.CUST_LOC = B.LOC_2 OR A.CUST_LOC = B.LOC_3 ORA.CUST_LOC = B.LOC_3 OR
A.CUST_LOC = B.LOC_4 )A.CUST_LOC = B.LOC_4 )
This can create 4 RIDLISTS against TBL_BILL if each This can create 4 RIDLISTS against TBL_BILL if each “loc” column has an index on TBL B and avoid a scan“loc” column has an index on TBL B and avoid a scan– Previously this would be a tablespace scan against Previously this would be a tablespace scan against
TBL_BILLTBL_BILL
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2424
Taming RIDLIST Taming RIDLIST processingprocessing That’s cool, how can this ever be That’s cool, how can this ever be
bad?bad?– DB2 may choose two indexes that DB2 may choose two indexes that
on their own would return a majority on their own would return a majority of the table, then JOIN them of the table, then JOIN them
– This may result in the equivalent of This may result in the equivalent of two or more full table scans, far two or more full table scans, far worse than using no indexes at allworse than using no indexes at all
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2525
Taming RIDLIST Taming RIDLIST processingprocessing Example:Example:
– Table has 1250000 rowsTable has 1250000 rows Two separate indexes Two separate indexes
– CUST_NBR and BILL_DATECUST_NBR and BILL_DATE I ask for everything for a customer on a dateI ask for everything for a customer on a date
– The customer has 5000 total entries on the tableThe customer has 5000 total entries on the table– There are 60000 total rows for this dateThere are 60000 total rows for this date– This customer has 10 rows on the chosen dateThis customer has 10 rows on the chosen date– RIDLIST would get one result of 5k, another of 60k RIDLIST would get one result of 5k, another of 60k
and join them to get just 10 rowsand join them to get just 10 rows
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2626
Taming RIDLIST Taming RIDLIST processingprocessing How do I know this has happened?How do I know this has happened?
– The only way to know for sure is EXPLAINThe only way to know for sure is EXPLAIN– Watch for is unexpected performance Watch for is unexpected performance
degradation after changes degradation after changes – If you change and/or rebind a program that If you change and/or rebind a program that
was bound on an earlier version of DB2 it may was bound on an earlier version of DB2 it may change access path, even on unchanged SQLchange access path, even on unchanged SQL
You change a report heading and now the program You change a report heading and now the program runs 20 minutes instead of 2…runs 20 minutes instead of 2…
The SQL looks good (no improper functions, has The SQL looks good (no improper functions, has index columns referenced etc) but it really runs bad index columns referenced etc) but it really runs bad ……
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2727
Taming RIDLIST Taming RIDLIST processingprocessing What do I do about it?What do I do about it?
– See if you can add a column to one of the See if you can add a column to one of the indexes to eliminate the need for RIDLISTindexes to eliminate the need for RIDLIST
Check to see if you can add DATE to the Check to see if you can add DATE to the CUSTOMER index, if you can then do itCUSTOMER index, if you can then do it
– Rewrite the SQL to use a different index or Rewrite the SQL to use a different index or different criteriadifferent criteria
– Okay, none of that was possible, what Okay, none of that was possible, what now?now?
Put a Scalar function on the left of the = signPut a Scalar function on the left of the = sign– Remember that this kills indexingRemember that this kills indexing
AND DATE(BILL_DATE) = :WS-BILL-DATEAND DATE(BILL_DATE) = :WS-BILL-DATE
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2828
DB2 V7 and Beyond:DB2 V7 and Beyond:
Difficult CICS PagingDifficult CICS Paging
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
2929
Difficult CICS Paging:Difficult CICS Paging: Descending keys mixed in with Ascending keysDescending keys mixed in with Ascending keys
Users functional request: Users functional request: – A screen to view customer account invoice A screen to view customer account invoice
status – by selected Customer Accountstatus – by selected Customer Account– Have the ability to view “ALL” or just the Have the ability to view “ALL” or just the
“UNPAID” accounts“UNPAID” accounts– Ignore the ENTRY DATE in the sort if the Ignore the ENTRY DATE in the sort if the
screen is in “UNPAID” modescreen is in “UNPAID” mode– Smooth paging (i.e.: Page-Up goes to the Smooth paging (i.e.: Page-Up goes to the
previous page not the top of list)previous page not the top of list)– Dynamic (i.e.: paging keeps up with Dynamic (i.e.: paging keeps up with
database changes)database changes)– 15 lines of detail per page15 lines of detail per page
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3030
Difficult CICS Paging:Difficult CICS Paging: Descending keys mixed in with Ascending keysDescending keys mixed in with Ascending keys
Users Want it Sorted by …Users Want it Sorted by …– Customer Loc Customer Loc AscendingAscending– Paid DatePaid Date Descending !!!Descending !!!– Entry Date Entry Date AscendingAscending
> Ignore in “UNPAID” mode> Ignore in “UNPAID” mode– Invoice NumberInvoice Number AscendingAscending
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3131
Difficult CICS Paging:Difficult CICS Paging:The TableThe Table
CUSTOMER_ACCTCUSTOMER_ACCT CHAR(8)CHAR(8)
CUSTOMER_LOC CUSTOMER_LOC CHAR(4)CHAR(4)
PAID_DATEPAID_DATE DATEDATE
ENTRY_DATE ENTRY_DATE DATEDATE
INVOICE_NUMBERINVOICE_NUMBER CHAR(10)CHAR(10)
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3232
Difficult CICS Paging:Difficult CICS Paging: Descending keys mixed in with Ascending keysDescending keys mixed in with Ascending keys
Older ways of solving this:Older ways of solving this:– Build a TSQ and use external SortBuild a TSQ and use external Sort
Very inefficient if result set is largeVery inefficient if result set is large Not dynamic unless you always rebuild TSQNot dynamic unless you always rebuild TSQ
– Have lots of ‘OR’s in parenthesis with Have lots of ‘OR’s in parenthesis with ‘AND’s‘AND’s
Most likely not indexable at allMost likely not indexable at all
– Have multiple cursors with slightly Have multiple cursors with slightly different WHERE clausedifferent WHERE clause
Not much fun to maintainNot much fun to maintain
– Tell ‘em noTell ‘em no Yeah right…..Yeah right…..
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3333
Difficult CICS Paging:Difficult CICS Paging: Descending keys mixed in with Ascending keysDescending keys mixed in with Ascending keys
Newer ways to solve this:Newer ways to solve this:– ““Derived Columns”Derived Columns”
Use Case Statements and Scalar Use Case Statements and Scalar FunctionsFunctions
– ““Compound Keys”Compound Keys” Build Derived Columns and keys to work Build Derived Columns and keys to work
with themwith them
– Switches in the WHERE clauseSwitches in the WHERE clause
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3434
Derived ColumnsDerived Columns
Can reverse a value to make an Can reverse a value to make an ascending sort result in descending ascending sort result in descending orderorder
Select Select
Digits(Days(‘9999-12-31’) – Days Digits(Days(‘9999-12-31’) – Days (Paid_Date))(Paid_Date))
More current dates will have lower values, More current dates will have lower values, sorting this ascending actually results in a sorting this ascending actually results in a descending sortdescending sort
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3535
Derived ColumnsDerived ColumnsReversing Sort OrderReversing Sort Order
Paid DatePaid Date Derived Value Derived Value OrderOrder
2006-07-182006-07-18 00029195410002919541 11
2006-01-152006-01-15 00029197330002919733 22
2005-02-012005-02-01 00029200810002920081 33
2000-08-022000-08-02 00029217250002921725 44
We sort Ascending by Derived Value and We sort Ascending by Derived Value and the dates come out in Descending the dates come out in Descending order !!!order !!!
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3636
Derived ColumnsDerived ColumnsSelectively ignoreSelectively ignore
In “UNPAID” mode we want to ignore In “UNPAID” mode we want to ignore Entry Date in sort orderEntry Date in sort order
CASECASE WHEN :WS-SCREEN-MODE = ‘U' WHEN :WS-SCREEN-MODE = ‘U' THEN '0001-01-01' THEN '0001-01-01'
ELSE ENTRY_DATEELSE ENTRY_DATE END CASEEND CASE
This causes the column always being ‘0001-This causes the column always being ‘0001-01-01’ in “UNPAID” mode, effectively 01-01’ in “UNPAID” mode, effectively ignoring itignoring it
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3737
Difficult CICS PagingDifficult CICS PagingThe Select ClauseThe Select Clause
SelectSelect Digits(Days(‘9999-12-31’) – Days (Paid_Date)) Digits(Days(‘9999-12-31’) – Days (Paid_Date)) ,CASE,CASE
WHEN :WS-SCREEN-MODE = 'A' WHEN :WS-SCREEN-MODE = 'A' THEN '0001-01-01' THEN '0001-01-01' ELSE Entry_DateELSE Entry_DateEND CASEEND CASE
,Customer_Acct,Customer_Acct ,Customer_Loc ,Customer_Loc ,Paid_Date,Paid_Date ,Entry_Date ,Entry_Date ,Invoice_Number,Invoice_Number
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3838
Difficult CICS PagingDifficult CICS PagingThe Order By The Order By
Order by Order by Customer Loc Customer Loc ,1,1 ,2 ,2 ,Invoice Number,Invoice NumberFETCH FIRST 16 ROWS ONLYFETCH FIRST 16 ROWS ONLY The 1 and 2 refer to the value in that position of The 1 and 2 refer to the value in that position of
the result set (i.e.: the first and second the result set (i.e.: the first and second columns).columns).
We will save off the 16We will save off the 16thth row as the forward row as the forward paging key. If we get +100 before then we are paging key. If we get +100 before then we are at EOFat EOF
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
3939
Difficult CICS PagingDifficult CICS PagingThe WHERE clauseThe WHERE clause
WHERE CUSTOMER_ACCT = :WS-CUST-ACCTWHERE CUSTOMER_ACCT = :WS-CUST-ACCT AND CUSTOMER_LOC >= :WS-CUST-LOCAND CUSTOMER_LOC >= :WS-CUST-LOC AND CUSTOMER_LOC||AND CUSTOMER_LOC|| DIGITS(DAYS(‘9999-12-31’) – DIGITS(DAYS(‘9999-12-31’) –
DAYS(PAID_DATE))||DAYS(PAID_DATE))|| CHAR(DATE('0001-01-01') + CHAR(DATE('0001-01-01') + ((DAYS(ENTRY_DATE) - ((DAYS(ENTRY_DATE) - DAYS(DATE('0001-01-01'))) * DAYS(DATE('0001-01-01'))) * :WS-SCREEN-MODE-NUM) DAYS)||:WS-SCREEN-MODE-NUM) DAYS)|| INVOICE_NBR >= :WS-PAGING-KEYINVOICE_NBR >= :WS-PAGING-KEY AND (:WS-SCREEN-MODE = 'A' ORAND (:WS-SCREEN-MODE = 'A' OR DATE_PAID = '0001-01-01')DATE_PAID = '0001-01-01')
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4040
Difficult CICS PagingDifficult CICS PagingThe Where clause – The Where clause –
Explained!Explained!
First lets start with the table’s First lets start with the table’s index:index:– We do want this to run efficientlyWe do want this to run efficiently
The table has 750000 rowsThe table has 750000 rows There are have 5000 customers across There are have 5000 customers across
150 locations150 locations
Lets look at the index on the table Lets look at the index on the table that will make this SQL workthat will make this SQL work
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4141
Difficult CICS PagingDifficult CICS PagingThe WHERE clause - The WHERE clause -
Explained!Explained!ColumnColumn CardinalityCardinalityCUSTOMER_ACCTCUSTOMER_ACCT 50005000CUSTOMER_LOCCUSTOMER_LOC 150150INVOICE_NBRINVOICE_NBR 750000750000
• Invoice number would be a perfect key…Invoice number would be a perfect key…• But we don’t have it, we were given CUSTOMER_ACCTBut we don’t have it, we were given CUSTOMER_ACCT• It’s the third column in this index, indexes must be used It’s the third column in this index, indexes must be used
from the top down to work efficientlyfrom the top down to work efficiently• Remember that Cardinality assumes even distribution Remember that Cardinality assumes even distribution
(A perfect world)(A perfect world)• This is not a perfect world so it is only a good This is not a perfect world so it is only a good
approximation to gauge efficiencyapproximation to gauge efficiency• Cardinality becomes less significant further down an Cardinality becomes less significant further down an
index.index.
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4242
Difficult CICS PagingDifficult CICS PagingThe Where Clause – The Where Clause –
Explained!Explained! Lets break it down …Lets break it down …
CUSTOMER_ACCT = :WS-CUST-ACCTCUSTOMER_ACCT = :WS-CUST-ACCT
This is our big performance helper, This is our big performance helper, without it our SQL would be horrifyingwithout it our SQL would be horrifying
It cuts our 750000 row table into around It cuts our 750000 row table into around 5000 eligible rows5000 eligible rows
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4343
Difficult CICS PagingDifficult CICS PagingThe Where Clause – The Where Clause –
Explained!Explained! AND CUSTOMER_LOC >= :WS-CUST-LOCAND CUSTOMER_LOC >= :WS-CUST-LOC
This cuts the 5000 rows down to 33, well not This cuts the 5000 rows down to 33, well not really really – No one customer uses all 150 locations (they No one customer uses all 150 locations (they
probably use around 4 at most) probably use around 4 at most) – More realistically we are left with 125 or so rowsMore realistically we are left with 125 or so rows
If you remember back to the WHERE clause, If you remember back to the WHERE clause, this also appears in the big concatenationthis also appears in the big concatenation
This is not redundant, once you start using || This is not redundant, once you start using || and scalar functions, DB2 cannot use that and scalar functions, DB2 cannot use that criteria for indexingcriteria for indexing
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4444
Difficult CICS PagingDifficult CICS PagingThe Where Clause – The Where Clause –
Explained!Explained! AND CUSTOMER_LOC||AND CUSTOMER_LOC|| DIGITS(DAYS(‘9999-12-31’) – DAYS(PAID_DATE))||\DIGITS(DAYS(‘9999-12-31’) – DAYS(PAID_DATE))||\This puts together the customer_loc with the inverted paid This puts together the customer_loc with the inverted paid
datedate
CHAR(DATE('0001-01-01') + CHAR(DATE('0001-01-01') + ((DAYS(ENTRY_DATE) - ((DAYS(ENTRY_DATE) - DAYS(DATE('0001-01-01'))) * DAYS(DATE('0001-01-01'))) * :WS-SCREEN-MODE-NUM) DAYS)||:WS-SCREEN-MODE-NUM) DAYS)||
This adds in the Entry_date in ‘ALL’ Mode (‘0001-01-01’ in This adds in the Entry_date in ‘ALL’ Mode (‘0001-01-01’ in “U”)“U”)
INVOICE_NBR >= :WS-PAGING-KEYINVOICE_NBR >= :WS-PAGING-KEY and Finally tacks on the invoice numberand Finally tacks on the invoice number
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4545
Difficult CICS PagingDifficult CICS PagingThe Where Clause – The Where Clause –
Explained!Explained! The Working Storage KeyThe Working Storage Key
01 DATABASE-KEYS01 DATABASE-KEYS05 WS-PAGING-KEY 05 WS-PAGING-KEY PIC X(34)PIC X(34)05 FILLER REDEFINES WS-PAGING-KEY05 FILLER REDEFINES WS-PAGING-KEY 10 WS-KEY-LOC10 WS-KEY-LOC PIC X(04).PIC X(04). 10 WS-KEY-PDATE 10 WS-KEY-PDATE PIC X(10).PIC X(10). 10 WS-KEY-EDATE 10 WS-KEY-EDATE PIC X(10).PIC X(10). 10 WS-KEY-INVOICE10 WS-KEY-INVOICE PIC X(10).PIC X(10).
* “A”LL MODE OR “U”NPAID MODE* “A”LL MODE OR “U”NPAID MODE05 WS-SCREEN-MODE 05 WS-SCREEN-MODE PIC X(01).PIC X(01).
* 0 IF IN “U”PAID MODE, 1 IN “A”LL MODE* 0 IF IN “U”PAID MODE, 1 IN “A”LL MODE05 WS-SCREEN-MODE-NUM 05 WS-SCREEN-MODE-NUM `̀ PIC S9(04) COMP.PIC S9(04) COMP.
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4646
Difficult CICS PagingDifficult CICS PagingBacking upBacking up
The page up cursor is the same thing with The page up cursor is the same thing with 2 tweaks2 tweaks– Order by DESCENDINGOrder by DESCENDING– <= and < instead of >= and >=<= and < instead of >= and >=
When they page up we will use the reverse When they page up we will use the reverse cursor to find the starting point for the new cursor to find the starting point for the new page page – It will begin with the row prior to first row on It will begin with the row prior to first row on
the current page (the last row on the prior the current page (the last row on the prior page)page)
We will use this value as the key for the We will use this value as the key for the page down cursor to actually build the page down cursor to actually build the pagepage
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4747
Difficult CICS PagingDifficult CICS PagingThe WHERE clause - The WHERE clause -
UpUp
WHERE CUSTOMER_ACCT = :WS-CUST-ACCTWHERE CUSTOMER_ACCT = :WS-CUST-ACCT AND CUSTOMER_LOC <= :WS-CUST-LOCAND CUSTOMER_LOC <= :WS-CUST-LOC AND CUSTOMER_LOC||AND CUSTOMER_LOC|| DIGITS(DAYS(‘9999-12-31’) – DIGITS(DAYS(‘9999-12-31’) –
DAYS(PAID_DATE))||DAYS(PAID_DATE))|| CHAR(DATE('0001-01-01') + CHAR(DATE('0001-01-01') + ((DAYS(ENTRY_DATE) - ((DAYS(ENTRY_DATE) - DAYS(DATE('0001-01-01'))) * DAYS(DATE('0001-01-01'))) * :WS-SCREEN-MODE-NUM) DAYS)||:WS-SCREEN-MODE-NUM) DAYS)|| INVOICE_NBR < :WS-PAGING-KEYINVOICE_NBR < :WS-PAGING-KEY AND (:WS-SCREEN-MODE = 'A' ORAND (:WS-SCREEN-MODE = 'A' OR DATE_PAID = '0001-01-01')DATE_PAID = '0001-01-01')
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4848
Difficult CICS PagingDifficult CICS PagingBacking upBacking up
We are on page 3 We are on page 3 – We feed Page 3, line 1 values into page up cursor We feed Page 3, line 1 values into page up cursor
We saved it in Linkage when page 3 was built last We saved it in Linkage when page 3 was built last program cycle program cycle
The very first time in we used low-valuesThe very first time in we used low-values– The page up cursor finds us Page 1, line 16 valueThe page up cursor finds us Page 1, line 16 value
Remember there is not a Line 16 on the screen, this Remember there is not a Line 16 on the screen, this line is for the paging process and is saved in Linkageline is for the paging process and is saved in Linkage
– We feed that into page down cursor and build page We feed that into page down cursor and build page 22
This ensures that pages are always full and changes This ensures that pages are always full and changes to the database are reflected as they happento the database are reflected as they happen
Prevents pages with missing top linesPrevents pages with missing top lines Makes first/last pages reliableMakes first/last pages reliable
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
4949
Difficult CICS PagingDifficult CICS PagingIn ConclusionIn Conclusion
Remember performance, make sure the Remember performance, make sure the first variable item in the compound key is first variable item in the compound key is also stated as a >= (or <=) by itselfalso stated as a >= (or <=) by itself
Only put variable items in the compound Only put variable items in the compound key, if it is always the same value (ex: key, if it is always the same value (ex: Customer_Acct) put it in as an =Customer_Acct) put it in as an =
Do an EXPLAIN!, check your performanceDo an EXPLAIN!, check your performance Check your indexes, make sure there is Check your indexes, make sure there is
an index for at least one = and also the an index for at least one = and also the first variable itemfirst variable item
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5050
DB2 V7 and Beyond:DB2 V7 and Beyond:
Ideas to make use of Ideas to make use of UNIONUNION
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5151
Making Use of UNIONsMaking Use of UNIONs
A UNION can be used to replace A UNION can be used to replace multiple “OR” statementsmultiple “OR” statements– Remember that “OR”s are real index Remember that “OR”s are real index
killerskillers Avoiding them where possible is importantAvoiding them where possible is important
– We talked about RIDLISTs before but We talked about RIDLISTs before but the RIDLIST can’t help every SQLthe RIDLIST can’t help every SQL
UNIONS may be able to help some of theseUNIONS may be able to help some of these
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5252
Making Use of UNIONsMaking Use of UNIONs
Assume we have a large Customer Assume we have a large Customer TableTable– It has an index on CUST_NBRIt has an index on CUST_NBR– It is a large table 1.5 million rowsIt is a large table 1.5 million rows– We need to extract all customers with We need to extract all customers with
Current Bills and certain Past Due BillsCurrent Bills and certain Past Due Bills We only want to list a customer onceWe only want to list a customer once
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5353
Making Use of UNIONsMaking Use of UNIONs
SELECT * FROM TBL_CUSTOMERSELECT * FROM TBL_CUSTOMER WHERE CUST_NBR INWHERE CUST_NBR IN
( SELECT CUST_NBR ( SELECT CUST_NBR FROM TBL_CURR_BILLS) FROM TBL_CURR_BILLS) OR CUST_NBR IN OR CUST_NBR IN (SELECT CUST_NBR (SELECT CUST_NBR FROM TBL_PAST_DUE FROM TBL_PAST_DUE
WHERE PAST_DUE_DAYS < 30)WHERE PAST_DUE_DAYS < 30)
– The performance of this could be hideousThe performance of this could be hideous Even assuming the TBL_CURR_BILLS and TBL_PAST_DUE are Even assuming the TBL_CURR_BILLS and TBL_PAST_DUE are
smallsmall The presence of the OR really prevents any effective The presence of the OR really prevents any effective
indexingindexing
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5454
Making Use of UNIONsMaking Use of UNIONs
It can be rewritten as a Union:It can be rewritten as a Union: SELECT CUST_NBR FROM TBL_CUSTOMERSELECT CUST_NBR FROM TBL_CUSTOMER WHERE CUST_NBR INWHERE CUST_NBR IN
( SELECT CUST_NBR ( SELECT CUST_NBR FROM TBL_CURR_BILLS) FROM TBL_CURR_BILLS)
UNION UNION SELECT CUST_NBR FROM TBL_CUSTOMERSELECT CUST_NBR FROM TBL_CUSTOMER WHERE CUST_NBR IN WHERE CUST_NBR IN
(SELECT CUST_NBR (SELECT CUST_NBR FROM TBL_PAST_DUE FROM TBL_PAST_DUE
WHERE PAST_DUE_DAYS < 30)WHERE PAST_DUE_DAYS < 30)
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5555
Making Use of UNIONsMaking Use of UNIONs
The UNION will run each one as a The UNION will run each one as a separate SQL and can then index separate SQL and can then index CUST_NBRCUST_NBR
Then it will SORT/SUM them into Then it will SORT/SUM them into one resultone result– UNION ALL would eliminate the UNION ALL would eliminate the
SORT/SUM but would possibly return SORT/SUM but would possibly return duplicates if the customer had both duplicates if the customer had both a current and a <30 past due billa current and a <30 past due bill
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5656
Making Use of UNIONsMaking Use of UNIONs
Places to consider a UNIONPlaces to consider a UNION– SQL that you have to use a lot of “OR”sSQL that you have to use a lot of “OR”s– SQL where you are trying to get the same SQL where you are trying to get the same
result set from conflicting criteriaresult set from conflicting criteria– Places where RIDLIST processing is being Places where RIDLIST processing is being
invoked but is performing poorlyinvoked but is performing poorly– UNION doesn’t have to be used against UNION doesn’t have to be used against
different tables, both Selects can be the different tables, both Selects can be the same tablesame table
04/10/2304/10/23 DB2 V7 and Beyond: Rick Egleston © 200DB2 V7 and Beyond: Rick Egleston © 20066
5757
DB2 V7 and Beyond:DB2 V7 and Beyond:
Questions ?Questions ?