Showing posts with label DB2 v10. Show all posts
Showing posts with label DB2 v10. Show all posts

Saturday, November 8, 2014

2nd csDUG Conference: A great success!




50 attendees from Czech Republic, Slovakia, and some other European countries attended the 2nd csDUG Conference earlier this week, in Prague. This one-day conference was held in the IBM lab in Prague, and sponsored by CA Technologies. Various famous international speakers made the trip to share their DB2 expertise and give presentations about DB2 for z/OS.






We also had the pleasure to see some representatives of other European DB2 User Groups (PDUG, SpDUG, BeLux, …)

Steen Rasmussen giving a presentation at csDUG

A big thank you to the presenters, who provided great DB2 technical content:


Steve Thomas giving a presentation at csDUG


The agenda of the conference is available [here].

A Mainframe ?

Thursday, November 6, 2014

How to find Java application that is using my DB2

The amount of DB2 workload that is coming from Java applications is growing. Java applications can run on z/OS but more often they run outside of z/OS. In this post we will cover how you can investigate DB2 threads that are processing SQL statements issued by a Java application.

We will cover what is possible to do with standard DB2 commands and we will cover best practices for using JDBC that will make easier for database administrators to quickly identify the application that is responsible for the request. In future posts we will cover techniques for doing it without need to change the application code and how to get full information that can help developer to debug the code that is issuing SQL statements with poor performance. It can be a difficult task for complex applications and applications that are developed by different company.

Let's have a simple Java application that connects to DB2. This application just issues a simple query that can take long time. You can increase the sleep value to make it run longer. It issues the query and it reads its result set slowly. If you want to try it, you have to replace userid, password and URL with values that are good for your system. Then you just need to compile it and run with the DB2 JDBC driver on your Java class path.

package com.ca.blog.sampledbapp;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class SimpleDbApp {
private final String USERID = "qadba01";
private final String PASSWORD = "password";
private final String URL = "jdbc:db2://system:port/LOCATION";
private final String QUERY = "SELECT * FROM SYSIBM.SYSTABLES";

public static void main(String[] args) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, SQLException,
                        InterruptedException {
SimpleDbApp app = new SimpleDbApp();
app.run();
}

private void run() throws InstantiationException, IllegalAccessException,
ClassNotFoundException, SQLException, InterruptedException {
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
Properties properties = new Properties();
properties.put("user", USERID);
properties.put("password", PASSWORD);
Connection connection = DriverManager.getConnection(URL, properties);
CallableStatement statement = connection.prepareCall(QUERY);
final boolean rowsReturned = statement.execute();
if (rowsReturned) {
int count = 0;
while (statement.getResultSet().next()) {
count++;
Thread.sleep(100);
}
System.out.printf("Count: %d", count);
}
statement.close();
}
}

This application can run for a while. Let's see what we can see in DB2 about it.

We can issue -DISPLAY THREAD (*) DETAIL command to see if the thread for this statement is active:
DSNV401I  !D10A DISPLAY THREAD REPORT FOLLOWS -                   
DSNV402I  !D10A ACTIVE THREADS -                                  
NAME     ST A   REQ ID           AUTHID   PLAN     ASID TOKEN     
SERVER   RA *  2032 db2jcc_appli QADBA01  DISTSERV 02F2 98403     
 V437-WORKSTATION=130.200.80.104, USERID=qadba01,                 
      APPLICATION NAME=db2jcc_application                         
 V441-ACCOUNTING=JCC04150130.200.80.104                           
       '                                                          
 V445-O2C85068.DE86.CE04632EDB52=98403 ACCESSING DATA FOR         
  (  1)::FFFF:130.200.80.104                                      
 V447--INDEX SESSID           A ST TIME                           
 V448--(  1) 5166:56966       W R2 1431014492448                  

I was able to find it because it was the only thread for userid QADBA01. In case when there are hundreds of threads it can be difficult to find it. Default application name for all Java applications is db2jcc_application and if the application does not set you will not get anything better. There are some information that can help you:
  • Authid - if your application is using single userid to access DB2 and no other applications are using it, you can find out what application it is if you keep track of it. In case when every user of the application is also connecting to DB2 under its userid, you cannot use it to identify the application.
  • Workstation - there is an IP address of the application server. This can be used to find the application but it is not easy for database administrator to find out what application is running on that server and there can be multiple applications on one server.
  • SQL text - you can figure out the application from the tables that are used. That usually works for one statement but you cannot effectively aggregate performance metrics based on SQL text.
This is not issue of -DISPLAY THREAD command. Even advanced performance monitoring tools like CA SYSVIEW for DB2 or CA Chorus for DB2 Database Management does not display more than just better formatted identification section:

Identification                              
  End User User ID    : qadba01             
  End User Workstation: 130.200.80.104      
  End User Transaction: db2jcc_application  

Active Threads in the Investigator of CA Chorus
So let's see what can be done by the Java application to identify itself better to DB2.

We will start with standard JDBC properties and then we will cover DB2 specific properties. These properties can be set by Connection.setClientInfo(name, value) method.

These three properties are recommended to be used by every Java application that is connecting to a database:
  • ApplicationName - The name of the application that is connected. DB2 will user first 32 characters.
  • ClientUser - The name of the user that the application is performing work for. This should be the real end user ID and not the user ID that was used to establish the connection.
  • ClientHostname - The hostname of the computer the application using the connection is running on. Hostname is better than just IP address. When the application is running on multiple servers it is good to provide different hostnames for each server so it is possible to identify the real server.
Let's see how we can set it in our sample program:
    connection.setClientInfo("ApplicationName", System.getProperty("sun.java.command"));
    connection.setClientInfo("ClientUser",      System.getProperty("user.name"));
    connection.setClientInfo("ClientHostname",  InetAddress.getLocalHost().getHostName());

Note: This is simple example that does not handle exceptions how it should.

The output for -DISPLAY THREAD has improved:

SERVER   RA *  2077 db2jcc_appli QADBA01  DISTSERV 02F2 99078
 V437-WORKSTATION=plape03mac739, USERID=plape03,             
      APPLICATION NAME=com.ca.blog.sampledbapp.SimpleDb      
 V441-ACCOUNTING=JCC04150130.200.80.104                      
       '                                                     
 V445-O2C85068.E276.CE04710F0A04=99078 ACCESSING DATA FOR    
  (  1)::FFFF:130.200.80.104                                 
 V447--INDEX SESSID           A ST TIME                      
 V448--(  1) 5166:57974       W R2 1431015452732             

You can see the computer host name (in this case my laptop), my real userid and the main class of the application. The same is true for other tools:
Identification                                                  
  End User User ID    : plape03                                 
  End User Workstation: plape03mac739                           
  End User Transaction: com.ca.blog.sampledbapp.SimpleDb        

DB2 has two more properties in the client info that can be used. See Client info properties support by the IBM Data Server Driver for JDBC and SQLJ for full documentation.
  • ClientAccountingInformation - This can be up to 200 characters long string with accounting information. The default is JCCversionclient-ip. You can see it in the output of -DISPLAY THREAD on line that starts with V441-ACCOUNTING=.
  • ClientCorrelationToken - Unique value that allows you to correlate the logical unit of work in DB2 to your application. It was added in DB2 and it seems to be read-only.
That is nice but as DB2 database administrator you cannot change the Java application code. In future post we will cover how to inject this information into any application without need to change the code and rebuild and redeploy the application. The identification of the application is a good first step but in reality you need more information about what part of the application was issuing the statement, for example full stack trace would be helpful. We will cover techniques for it as well in future.

If you are a developer you should be using mentioned client info properties to make your application more friendly to database administrators. 

Monday, June 16, 2014

November 6, 2014 – csDUG Conference

The Czech Republic and Slovakia DB2 Users Group (csDUG) is a new Regional User Group (RUG) that was created a year ago.
On November 6th 2014, we will be hosting our SECOND csDUG EVENT, sponsored by IBM and CA Technologies !

This is a full day FREE conference with top industry speakers - an great opportunity DB2 users to meet industry experts !

Agenda of the conference



Location

IBM lab, building 4
V Parku 4, 148 00 Prague 4, Chodov
Czech Republic

Are you a qualified DB2 specialist? Do you want to discover what DB2 is or what it can do for you? Are you an experienced DBA in environments other databases and need support in DB2 for a new project? Are you interested in what role it can play a DB2 architecture of your business?
     --> Join the November 6 csDUG conference to listen to industry experts and network with other people interested in DB2!


Register to this FREE conference by sending an email to Register.csDUG.6.NOV@gmail.com
Please specify your name, country/language(s), job title, and company.

Thursday, October 17, 2013

csDUG Conference 2013 in Prague


35 attendees from the Czech and Slovak Republics met at the CA Technologies office in Prague on the 8th of October 2013 for a one-day conference. It was the first DB2 user conference in the Czech and Slovak region.



The attendees were a mix of database administrators, systems programmers, application developers and other specialists in the DB2 for z/OS and mainframe area. 

Steen Rasmussen (CA) talking about changes in DB2 10 catalog
The conference focused on the new features in DB2 10 and 11 and IBM DB2 Accelerator. The speakers were experienced DB2 specialists and architects from IBM and CA Technologies. The attendees appreciated the value of the sessions because they received a lot of new information that is related to their job.


MichaÅ‚ Bialecki (IBM), Philippe Dubost (CA), Peter Priehoda (IBM) and Robin Hopper (CA)  
The event was free and sponsored by CA and IBM. There were 5 sessions plus an open and closing session. You can see full agenda at October 8, 2013 – csDUG Conference.

One of the attendees won a free pass for the next IDUG conference in Phoenix, Arizona (USA).

Winner of the free pass for the next IDUG
If you missed the conference this year you will have opportunity to attend next year. As we shape the next event, we would like to hear from you with your preferred city (Prague, Brno, Ostrava or Bratislava), the most convenient time of year for you, and what topics are you interested in. Please post a comment to the blog article. Thank you.








Thursday, August 8, 2013

Save cpu by including extra columns to an unique index

Indexes are mainly used to improve the performance of SELECT statements. They however need to be used with caution, because indexes consume a lot of disk space. One could argue that nowadays DASD is relatively cheap, so that’s not a big deal. In fact, there is another big reason why one should be cautious about adding indexes: an index adds 30% of CPU on INSERTs.

IBM DB2 v10 introduces a new feature, the ability to include non-key columns to an unique index [more info on IBM site].

What is it good for ?


The new INCLUDE feature in DB2 v10 allows you to reduce the number of indexes, which results in cost savings in DASD and in CPU.

Let’s see how, through a very simple scenario: a table composed of 2 columns, COL1 is a unique ID, and COL2 is a non-unique column. You obviously need to define an unique index IX1 on COL1 to insure the uniqueness of the rows in COL1. But because a lot of queries gather data from COL1 and COL2 with ORDER BY, you decided (prior DB2 v10), to create another index IX2 on COL1 and COL2, to improve performance of the applications (SORT avoidance).
Now, in DB2 v10, you can simply INCLUDE COL2 as part as IX1 as a non-key column, meaning that X1 can both assure the uniqueness requirement in COL1, and keys for COL2. As a result, X2 became obsolete and can be deleted (saving DASD space and improving INSERTs performance).



Obviously, the unique key of an index can be composed of several columns, but the idea is the same.



In the scenario above, you will want to include COL3, COL4, and COL5 into the unique index IX1, and get rid of IX2.



Note that you can INCLUDE several non-key columns to an unique index, but you can only INCLUDE them one at a time … Meaning that in the above scenario, you will need to execute 3 SQL statements to INCLUDE to 3 non-key columns :
ALTER INDEX IX1 ADD INCLUDE (COL3);
ALTER INDEX IX1 ADD INCLUDE (COL4);
ALTER INDEX IX1 ADD INCLUDE (COL5);

From Theory to Practice …


The above theory is nice, but this scenario might be very difficult to locate manually, in a production DB2 environment composed of thousands of tables and indexes.

The following SQL statement will scan the DB2 catalog to locate some of these cases, namely locating non-unique indexes which contain columns that include the key of an unique index (when the unique index is composed of only 1 column).

SELECT IX.CREATOR,IX.NAME,         
       IX.TBCREATOR,IX.TBNAME,     
       IX.UNIQUERULE,IX.COLCOUNT,  
       KEYS.IXCREATOR,KEYS.IXNAME, 
       KEYS.COLNAME,KEYS.COLNO,    
       IX2.CREATOR,IX2.NAME,       
       IX2.TBCREATOR,IX2.TBNAME,   
       IX2.UNIQUERULE,IX2.COLCOUNT,
       KEYS2.IXCREATOR,KEYS2.IXNAME,
       KEYS2.COLNAME,KEYS2.COLNO   
  FROM SYSIBM.SYSINDEXES IX,       
       SYSIBM.SYSKEYS    KEYS,     
       SYSIBM.SYSINDEXES IX2,      
       SYSIBM.SYSKEYS    KEYS2     
 WHERE IX.UNIQUERULE = 'U'        
   AND IX.CREATOR = KEYS.IXCREATOR
   AND IX.NAME = KEYS.IXNAME      
   AND IX.COLCOUNT = 1            
   AND IX.TBCREATOR = IX2.TBCREATOR
   AND IX.TBNAME = IX2.TBNAME       
   AND IX2.CREATOR = KEYS2.IXCREATOR
   AND IX2.NAME = KEYS2.IXNAME      
   AND IX2.UNIQUERULE = 'D'         
   AND IX.TBCREATOR = IX2.TBCREATOR 
   AND IX.TBNAME = IX2.TBNAME        
   AND KEYS.COLNAME = KEYS2.COLNAME ;

With the result of this SQL statement, you can prepare your ALTER INDEX to INCLUDE non-key columns to the unique indexes listed, and get rid of the corresponding now-superfluous indexes.


If the unique index is composed of several columns, getting such simple output will be much more complex in pure SQL, because of the necessity of some kind of "table transpose" involving 2 UNIONs, and several INNER JOINs - due to the structure of the catalog. That said, if one gets rid (or changes the value) of the AND IX.COLCOUNT = 1 WHERE clause in the above statement, and looks carefully at the output (IX.COLCOUNT and number of IX2 rows matching), locating the other cases should be pretty straight forward.

Monday, July 22, 2013

Is the length of your inline LOBs optimal ?

From DB2 v10, you can specify that a portion of a LOB column will be stored in the base TableSpace. This improves the performance of applications that access LOB data, because it reduces the need to access the auxiliary LOB TableSpace. That also enables the creation of expression-based indexes on the inline portion of a LOB column, which can help improving the performance of searches through a LOB column [more info on IBM website].

Inline LOBs means that, for LOBs that are less than or equal to the size of the specified inline length, DB2 will store the entire LOB data in the base TableSpace, so more or less as if it would be a VARCHAR. However, for LOBs that are bigger than the inline length, the inline portion of the LOB resides in the base TableSpace, and the remainder of the LOB in the LOB auxiliary TableSpace. In order to use this feature, assuming you are currently using standard LOBs columns, you can alter existing LOB columns to become inline (using an ALTER TABLE statement).

But, what is the optimal INLINE LENGTH that you should specify ? The question is almost philosophical, since the answer greatly depends on the LOB Lengths Distribution in the column, in other words, it depends on the type of data that are stored in the LOB. And the DBA creating the table does not necessarily know what it contains, nor what it will contain…

Let’s examine 5 types of LOB length distributions that could exist in a LOB column.

1st case : almost all LOBs data are small, limited in size, with a few exceptions.



This case is almost too good to be true, because the answer of the optimal INLINE LENGTH is obvious. You should setup the INLINE LENGTH “threshold” so that it fits the “almost all small data” :


2nd case : the LOBs lengths are equally distributed, from the minimum length to the maximum length




This case is also a no brainer, and you will want to setup a threshold based on the percentage of LOBs row that should be self-contained in the inline LOB. For example, a 80 / 20 distribution as illustrated in the graph below:



3rd case : the LOBS lengths is are linearly distributed (ascending or descending)


Similarly to the 2nd case, you will want to setup a threshold based on the percentage of LOBs row that should be self-contained in the inline LOB. For example, a 80 / 20 distribution as illustrated in the graph below:


4th case : the LOBs length follow a normal distribution (Gauss).



This case might be more common, but essentially (if you forget about the small amount of low length LOBs on the left of the graph), you end up with a situation very similar as the 1st Case, where you will want to set the Inline LOB Length very close to the end of the Gauss curve. You might also use a 80 / 20 percent approach. 


5th case : the LOBs length distribution is sinusoidal


For this case, it is fairly complicated to provide an educated suggestion as to where to set the Inline LOB length “threshold”. In fact this looks like a succession of Gauss curves (4th case), so you could setup the threshold after any of these curves as illustrated below. Furthermore, you might want to analyze which data get accessed more frequently, an thus determine after which curve to place the threshold. Hopefully, this case will not be that common in real environements.
  


 From Theory to Practice …

The above describes distribution models, which is nice in theory… Well, in practice, you will want some sort of tool, to analyze existing length of LOB data, to understand in which case your LOBs are, and adapt the INLINE length accordingly (or confirm the setup is good the way it is). Read below …

The following SQL statement will list the columns in tables which are using INLINE LOB technique in your subsystem:

SELECT TBCREATOR,TBNAME,"NAME",LENGTH,LENGTH2,COLTYPE
  FROM "SYSIBM".SYSCOLUMNS                          
 WHERE ( COLTYPE = 'CLOB'                           
      OR COLTYPE = 'BLOB'                           
      OR COLTYPE = 'DBCLOB' )                       
    AND  LENGTH  > 4 ;                               

“LENGTH” > 4 indicates that the LOB column uses the INLINE LOB technique, the actual Inline LOB Length is LENGTH-4
“LENGTH2” reflects the maximum length of the LOB column (inline + stored in Auxiliary)

As an example, the below test was made on a SYSIBM catalog table SYSIBM.SYSVIEWS that contains a LOB column PARSETREE, a 1GB BLOB (1073741824) with Inline LENGTH 27674-4 = 27670  

Here the sample SQL statement that I used to visualize the length distribution of a LOB column. It simply categorizes the various lengths of the LOBs into LOB length ranges.

SELECT RANGE, COUNT(LENGTH) AS ROW_COUNT FROM (                      
SELECT LENGTH(PARSETREE) AS LENGTH,                                  
 (CEIL(27670/100)*(1+CEIL( 100 * LENGTH(PARSETREE) / 27670))) AS RANGE
FROM SYSIBM.SYSVIEWS) AS TABLE_WITH_RANGE                          
GROUP BY RANGE                                                       
ORDER BY RANGE ;                                                     

When exporting the output of the query into Excel, one can make a simple graph representation of the LOB length distribution and visualize if the INLINE LENGTH value is properly set. The analyzes shows that we are pretty much in the scenario of 1st Case, which I would assume to be the most common one anyway. The Inline LOB Length “threshold” seems adequately placed, for this LOB column.


The nice thing about this technique is that it is re-usable, and that the same query can be ran over time, when the LOB data values evolve, monitoring the LOB length distribution, to make sure the INLINE LENGTH value is still optimal.

Monday, July 15, 2013

Impact of SELECT * versus SELECTing specific columns

A couple of weeks ago, I attended a DB2 for z/OS technical conference and one of the sessions focused on tuning SQL statements and other topics related to DB2 performance. For the records the presentation name was “DB2 10 for z/OS: selected performance topics” and the presenter was Cristian Molaro (Independent DB2 Consultant, IBM Gold Consultant & IBM Champion).

Anyway, I learned that there is a notable performance impact when doing a simple and dirty SELECT * compared to selecting only the specific columns you need. There was no benchmarks however, so I thought it would be a good test to perform, create some simple tests with various tables and measure the impact of this SELECT * bad coding practice. First thing to mention, the performance degradation is not visible if we are dealing with small tables (small number of rows). My tests with a 1000 rows table did not show any difference. But when I performed tests on a more realist size of table (1,000,000 rows), I did notice meaningful differences.

The below graphs represents the results of a performance test (CPU time, and Elapsed time) for a 1,000,000 rows table, residing in a DB2 v10 New Function Mode (NFM) subsystem. This represents a fairly simple table, with 7 columns only (integer, dates, and timestamps), and compared a SELECT * with SELECT COL1, COL2.


The results of this test speak for themselves, there is a 70% overhead of CPU time consumed, and a 17% overhead of Elapsed time spent when using the SELECT * statement, i.e. when retrieving all columns, some of which are probably not needed by “the application”. Other tests performed show similar results, granting that obviously the overhead of SELECT * varies depending on the number of columns specified in the SELECT COL1, COL2, … and the size of the table (number of rows).

Digging deeper, I used a product a few years ago that examines embedded SQL statement in Cobol programs: CA Plan Analyzer (it also works for other programming languages). While writing this blog article, I went back to this tool, to see if it would detect a SELECT * statement. It did. Not to enter into too much details about this tool, there is a rule (sort of trigger) called Expert Rule 0064 that will be triggered if an embedded SELECT * SQL statement is discovered in the application / plan / package analyzed. In addition to the performance impact mentioned detailed above, CA Plan Analyzer also notifies the user with the following recommendation (which makes a lot of sense, and IMHO another good reason why application developers should not use SELECT * type of SQL statements in their application) :
                                                                             
         This should be avoided because of problems that can be encountered 
         when adding and removing columns from the underlying table(s). Your
         application program host variables will not correspond to the      
         added/removed columns.                                             

In a nutshell, if you are a DB2 application developer and you care about your applications performance : do not use SELECT * statements !
If you are a DB2 administrator, you may want to share this post with your application developers, and / or look for products that can detect the use of embedded SELECT * statements running in your DB2 environment.

Monday, July 8, 2013

Improving the response time of Native SQL procedures in DB2 v10

IBM claims better performance “out of the box” when upgrading to DB2 version 10. Some additional manual steps are however recommended to gain additional performance of your DB2 application and/or environment. One of which is about Native SQL Procedures.

DB2 version 9 introduced a new type of stored procedures called Native SQL Procedures. These procedures execute in DBM1 address space, and provide SQL performance improvements due to less cross-memory calls compared to external stored procedures.
Several improvements were done in this area in DB2 version 10. IBM however mentions that the response time improvement (up to 20% improvement) can be achieved only if the existing Native SQL Procedures are dropped and re-created. That is, if you had created Native SQL Procedures under DB2 version 9 and upgraded to DB2 version 10, you might want to DROP/CREATE those.

I created a SQL statement to locate Native SQL Procedures that were created prior the migration to DB2 version NFM. Since I did not know the exact date when the subsystems were upgraded, I figure out that I could use a trick to get this information. As in every new DB2 version, the DB2 catalog contains additional tables that are created during the migration process. I took one of them, SYSIBM.SYSAUTOALERTS, and queried SYSIBM.SYSTABLES to get the CREATEDTS value. That is a timestamp that indicated when a table was created. So the following SQL statement indicates when DB2 was either installed at the version 10 level, or upgraded to version 10 NFM:

-- When was DB2 upgraded to v10 NFM ?
SELECT CREATEDTS               
  FROM SYSIBM.SYSTABLES        
 WHERE NAME    = 'SYSAUTOALERTS'
        AND CREATOR = 'SYSIBM' ;

The game is then to locate Native SQL Procedures created prior that date. Stored procedures are listed in SYSIBM.SYSROUTINES, and the column ORIGIN = 'N' indicates that we deals with a Native SQL Procedure. The following statement will thus provide a list of the Native SQL Procedures created prior DB2 was upgraded to version 10 NFM :

-- List of Native SQL Procedures to re-create
SELECT CREATEDBY,OWNER,NAME,ORIGIN,CREATEDTS        
  FROM SYSIBM.SYSROUTINES                           
 WHERE ORIGIN = 'N'                                 
   AND CREATEDTS < ( SELECT CREATEDTS               
                       FROM SYSIBM.SYSTABLES        
                      WHERE NAME    = 'SYSAUTOALERTS'
                        AND CREATOR = 'SYSIBM' );    

With that, I got the list of Native SQL Procedures that I want to DROP / RECREATE. Hopefully, you have the DDL for these objects stored in dataset, but nothing is less obvious. If not, you can use tools to generate the DDL statements from the information in the catalog, in this example I used CA RC/Query for DB2 for z/OS to locate a particular Native SQL Procedure and generate its DDL:


This command produces the following output :


All what’s needed is to update the SQL, add the DROP syntax and a couple of COMMITs, and the job is done!

I hope that this post is useful to you. If you used the technique described above, I will be glad to read your comments, especially if you noticed and quantified performance improvements when dropping and re-creating your Native SQL Procedures!