APAR NOTE - DB2 - bad access path when using 'FETCH FIRST N ROWS ONLY' (n - small value)
Sunday, January 10, 2010
APAR NOTE :
http://www-01.ibm.com/support/docview.wss?uid=swg1IZ49936
IZ49936: UNDER CERTAIN CONDITIONS, OPTIMIZER MAY PICK LESS THAN OPTIMAL ACCESS PLAN DUE TO OVER-ESTIMATED CARDINALITY
Our team ran into a problem of using the 'fetch first 1 row only' (functional requirement of just finding whether atleast one row matched a criteria), and the return time for the query was 100 times longer than the one when used without the row limiting clause.
On viewing the explain data, we found it was using a table scan, and when used 'without' the clause, it used an appropriate index scan.
So what was the reason?? Because of the row-limiting clause, DB2 'thinks' (sometimes it doesn't align with the world) that the cardinality in the table formed due to a subquery with this clause is very low and hence uses a tablescan.
This has been fixed now, and all is well, but before this was put in place, I was able to 'tell the optimizer' about the cardinality using the runstats with distribution on the predicates, yes, RUNSTATS is that powerful..
Live Workshop on 'Cloud Computing for Developers' hosted by IBM
Thursday, October 01, 2009
Databases and procedural programming - part 1
Tuesday, September 29, 2009
dba : the code is just an UDB translation of the 'whatever' script written in some 'whatever' interpreted language programmer : well, that was my requirement, was asked to convert this into an db2 SP, dba : whats the cardinality of this cursor ? p : 72 million d : (ok, today I did wake up in front of the mirror) and you think this is good? p : that was the work set in the file for that script d : do you know how that handled the file and memory? and do you know this is going to sort all 72 million rows? p : so what? DB2 has been touted as best thing next to bread, should be a breeze, now you help me speed this up, is this locked? d : (can't find a gun) hands out the 'thinking in sets' by joe celko can you please read this when free? (should contact Colbert, well there ain't colberts in the nerd domain ) p : ok, but promise you'll speed this procedure d worked a week and came up with a procedure that worked in sets and wanted to advise this to the procedural DB programmer (along with the link to the famous 'kiss my royal irish a**' scene from 25th hour) 1. Databases are logical mappings of data, not physical, I've even been asked to run an update over one page to the next in the table, and table being called a file 2. projections and other db concepts rose out of set theory, so please think in sets, 3. break your work into finer pieces, the database and tables are not at your disposal Once I was called to inspect a 'database slowness' for an SP. Below is a snippet. declare cur1 cursor for select create_dt, client_cd,order_line_num from tab1 order by client_cd, create_dt ; fetch cur1 into v_create_dt,v_client_cd,v_order_line_num; if (completed(v_order_line_num,v_client_cd) = 1 ) then do the processing for the client and for the particular line number; . . end if; set old_v_client_cd = v_client_cd; set old_v_order_line_num = v_order_line_num; while((fetch cur1 into v_client_cd,v_order_line_num) = (old_v_client_cd,old_v_order_line_num)) do end while; This sql was ordering 72 million rows and picking up the max date for a particular order line . Obviously the programmer wasn't updating his knowledge on the presence of the 'partition by' clause, so I re-wrote update target_table1 set full_amt = (select sum(amt) from table1 t1 where row-number() over(partition by client_cd, order_line_num order by create_dt desc) = 1) Simple and powerful single query to tackle a whole pseudocode. That is the power of set processing. Viola! the sp completed in 6 minutes compared to 4 hours and stopping the rest of the processes meanwhile. I could go on and on about the 'legacy' data programmers, and 'architects'. I am not gifted to working with people like james koopman or Cunningham to have a great insight or implement architectures for the programs. But when I face these kinds of crap from programmers and team leads of over 10 years experience, I question whether it is their complacency or lack of the 'push' for improving their knowledge in the domain they work. Regards to DB2, this has come a long way from a few blogs/a great info center to a thousand webpages, groups, conferences etc.
MDC - a ten thousand foot introduction
Monday, September 28, 2009

Client_cd = 300 Client_cd = 301 Client-cd – 302 Client-cd - 303
MAX of two values - scalar function
I’ve always wanted db2 to have wider array of scalar functions.
Some like first day of month, last day of month are missing, but the most glaring one that many programmers use is the
max(val1,val2) = (val1 > val2, val1, val2),
and that is missing in UDB version 9.5 as of now. Not very sure about the latest 9.7 that boasts to save the world and solve the hunger problem though.
So I created one myself, and am heavily using it in my code so does other developers.
create function DB2ADMIN.MAXTWO(x date, y date)
returns date
begin atomic
if y is null or x >= y then return x;
else return y;
end if;
end;
Overload this for handling other datatypes and use them with descretion.
Remove numbers from a character value - scalar functions
Thursday, August 13, 2009
One developer asked me to help out his project. He wanted to remove the numbers,any special chars in his field values,
eg., '99kirkh-ammet99' to 'kirkhammet' and ' db2' to 'db'
I tried using translate, but didn't know what to do with the space that came in due to the function. Got help from one friend for the same.
Here is the final one : easy for experts, useful for newbies.
VALUES REPLACE(TRANSLATE('999kirk-hammet9 8', '', TRANSLATE('999kirk-hammet9 8',
'#', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', '#')), ' ', '') ;
To separate the command into pieces to explain it,
1. the inner translate :
TRANSLATE('999kirk-hammet9 8','#','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', '#')
- converts any characters to #, and ref. the syntax of translate function (new), pads # if final string is smaller than initial. Please read the new syntax. Very useful function.
Result :
'####-######9 8'
2. Outer translate:
This converts all the values (in our example - #, -, 9, 8) to spaces in the value.
Result :
' kirk hammet '
3. Replace :
This replaces the spaces with empty places thus getting us - 'kirkhammet'
If anyone got useful functions or links for the same, please comment.
Yet another scripting article - LINK
Monday, November 03, 2008
Old article, but worth the read, gives a brief intro to using local os scripts from db2 udfs.
http://www.ibm.com/developerworks/db2/library/techarticle/0211yip/0211yip4.html
Wednesday, October 08, 2008
One of the junior DBAs asked me this question. I thought it was a good enough reason to blog.
I am not touching what primary key helps us achieve, but what's difference in executing just
create unique index x.y on table xx.yy allow reverse scans;
than
create unique index x.y on table xx.yy allow reverse scans;
alter table xx.yy add constraint -- and give the columns in the above defined unique index
unique index can have one row with null value in either of columns, while primary key disallows it
Question on syscat.keycoluse.colseq
Monday, June 30, 2008
Just to link with a usenet group's thread reg. the colseq column in keycoluse catalog view. I always thought this was supposed to list the foreign key columns and it's relation with the parent columns. But it seems db2 has a bug w.r.t this view.
Here is a list of statements I ran.
DROP TABLE ARUN.TEST2;
DROP TABLE ARUN.TEST1;
create table arun.test1 (a char(1) not null, b char(1) not null);
create unique index arun.test1_idx2 on arun.test1(b,a) CLUSTER;
create unique index arun.test1_idx1 on arun.test1(a,b) ;
alter table arun.test1 add constraint pk_test1 primary key(a,b);
create table arun.test2(a2 char(1),b2 char(1));
create unique index arun.test2_idx1 on arun.test2(a2,b2) cluster;
alter table arun.test2 ADD constraint fk_test2 foreign key(b2,a2) references arun.test1;
--The below statement gives the relation between foreign key columns and their corresponding parents
SELECT
SUBSTR(R.CONSTNAME, 1, 18) AS KEYNAME,
SUBSTR(KF.COLNAME, 1, 18) AS COLNAME,
SUBSTR(KP.COLNAME, 1, 18) AS REFCOLNAME
FROM
SYSCAT.REFERENCES R
INNER JOIN SYSCAT.KEYCOLUSE KF
ON R.TABSCHEMA = KF.TABSCHEMA
AND R.TABNAME = KF.TABNAME
AND R.CONSTNAME = KF.CONSTNAME
INNER JOIN SYSCAT.KEYCOLUSE KP
ON R.REFTABSCHEMA = KP.TABSCHEMA
AND R.REFTABNAME = KP.TABNAME
AND R.REFKEYNAME = KP.CONSTNAME
WHERE
R.TABSCHEMA = 'ARUN' AND
R.TABNAME = 'TEST2'
AND KF.COLSEQ = KP.COLSEQ
ORDER BY
R.TABSCHEMA,
R.TABNAME,
R.CONSTNAME,
KF.COLSEQ
WITH UR;
I hoped for this output, which is what I wanted..
Keyname Colname Refcolname
'FK_TEST2 ' 'A2 ' 'A '
'FK_TEST2 ' 'B2 ' 'B '
Instead I was blessed with
Keyname Colname Refcolname
'FK_TEST2 ' 'B2 ' 'A '
'FK_TEST2 ' 'A2 ' 'B '
Link to the usenet group's thread..
Deleting limited number of rows and still using Joins (mimicing, actually)
Wednesday, June 04, 2008
Everybody loves the new flavor DB2 introduced to the delete command ,
delete from (select * from table [where
because they can limit the number of rows to be deleted in one shot. It has been of immense help since I frequently delete millions of rows and it alleviates the problem of lock memory and log file usage. I just put this statement in a loop and run that for a specific number of times (or till it gets 0 rows returned, with a little complex code). Now the only setback we have is, we cannot use a select statement that joins tables, and would be staring at SQL0150N error. Now I just set out to solve this and using the mighty 'exists' clause, which has saved me during more than one bad situation, was actually able to mimic join and still limit delete to a set of rows.
The original query was
select t1.* from table1 t1 inner join table2 t2 on
T1.COL1 = T2.COL1 AND T1.COL2 = T2.COL2 AND T1.COL3 = T2.COL3;
The following will not work because joins are not allowed in the 'delete from (' clause
delete from (select t1.* from table1 t1 inner join table2 t2 on
T1.COL1 = T2.COL1 AND T1.COL2 = T2.COL2 AND T1.COL3 = T2.COL3 fetch first n rows only)
This would throw SQL0150N error.
So I changed the above to
delete from
(
SELECT * FROM table1 T1 where exists
(select 1 from TABLE2 T2 where T1.COL1 = T2.COL1 AND T1.COL2 = T2.COL2 AND T1.COL3 = T2.COL3)
);
Works wonderfully.
DB2_EXTENDED_OPTIMIZATION
Tuesday, June 03, 2008
I loved this new option 'ENHANCED_MULTIPLE_DISTINCT' that they gave for the registry variable in ver 9 fp 2. I normally face with sqls having multiple distinct clauses, select count(distinct(x)) , sum (distinct(x)) from table1, and what happens here is that the optimizer tries to do the groupby twice, once for each aggregation function and then unions them at the end.
Because of the new option we can prevent the above so that both functions are executed against the data whilst loading it only once.
This has good improvement potential in single processor systems and will not be useful all the time.
Labels: DB2 registry variables, DB2_EXTENDED_OPTIMIZATION, SQL tuning
IBM can do magic!!
Monday, February 25, 2008
Have you ever come across situations wherein you need to drop a table that has been defined with 'restrict on drop' clause and you can't access the table at all, possibly because you inserted rows with 'not logged initially' state and it crashed???
Do the following..
For each node, run the following accordingly.
1) Take db offline. Make sure db is offline by checking with "db2 list
active databases"
2) db2dart <dbname> /mt /serv 1 /oi <table id> /tsi <tablespaceid> /PW
IEOAHERU
-----Alas - IBM services are the only guys who can give the password in the PW argument!!!!
3) Connect to the db, run the following statement
db2 ALTER TABLE <tablename> DROP RESTRICT ON DROP
4) Then drop the table immediately.
Interesting table
Monday, January 07, 2008
create table test (a integer not null generated always as identity (start with 1 increment by 1))
I cannot insert data since a is defined with "generated always", and there aint no other columns. This is a hole, just found this when I was taking prescription for everyday boredom.
APPGROUP_share_heap error in db2
Thursday, August 30, 2007
SQL0973N Not enough storage is available in the
"APPGROUP_SHARE_HEAP" heap to process the statement. SQLSTATE=57011 ???
For "application group shared heap size" , you need to look at three
parameters....
APPGROUP_MEM_SZ, GROUPHEAP_RATIO, and APP_CTL_HEAP_SZ.
The number of applications in one application group is calculated by:
APPGROUP_MEM_SZ / APP_CTL_HEAP_SZ.
The application group sharedheap size is calculated by: APPGROUP_MEM_SZ
* GROUPHEAP_RATIO /100.
Great article about DB2 locking
Wednesday, August 08, 2007
How Can Statistics Be Updatee Using SQL
Monday, August 06, 2007
DB2 Viper 2 compatibility features
Wednesday, August 01, 2007
Make your applications port easier.
Below is a post by Serge Releiu talking about DB2's sql avatar, and how we can
use them with caution to tackle porting worries..
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0707rielau/
Cursor in UDFs ??
Wednesday, July 25, 2007
SQL PL can be categorized into two technologies.
One is "inline" SQL PL, the other, what I like to call "packaged" or
"compiled" SQL PL.
Procedures are compiled once into static SQL when they are created.
SQL Functions, Methods and Triggers as well as a standalone BEGIN ATOMIC
.... END statement (a dynamic compound) are not compiled into separate
objects. A trigger or SQL function get macro expanded into the
surrounding statement and compield within it's context.
This is very powerful technology, but also very tricky.
Consequently inline SQL PL has only a subset of the statements at its
disposal.
These are:
FOR loop (which is very close to a CURSOR)
WHILE
SET
ITERATE
CONTINUE
SIGNAL
GET DIAGNOSTICs
DECLARE variable
DECLARE condition
IF THEN ELSE
I know of only two things that inline SQL PL can do today that packaged
SQL PL cannot:
Multi column set (SET (a, b, c) = (....))
and SELECT and VALUES without INTO clauses
The former is on the todo list, the later is a historical feature.
Thanks to Serge Rielau, IBM Toronto labs..
Leverage data partitioning for scalability and high performance on Linux
Friday, June 29, 2007
This gives the step by step howto for implementing DPF in a SUSE enterprise v9
A colorful intro to db2 DPF
Secrets surrounding db2 locking behaviour
Thursday, May 31, 2007
http://www.ibm.com/developerworks/db2/library/techarticle/dm-0501melnyk/
