This page describes some suggested improvements to code and processes that could make your IBM Toolbox for Java application perform faster, better, and safer. These are just suggestions and may not work in every possible scenario. No guarantee is stated or implied.
- JarMaker. The Toolbox ships with a utility called JarMaker which allows a user to essentially carve up the jt400.jar file into a smaller file containing only the components that are needed by their application. Having a smaller JAR file then allows it to be downloaded more quickly if running in an applet.
- Native optimizations. Run natively on IBM i, using jt400Native.jar instead of jt400.jar. The Toolbox contains native optimizations for a few of its classes, including the AS400File classes. Your record-level access application will perform better if it is run on an IBM i system than if it is run from a remote client, since it will use native API calls to access the database instead of going through TCP/IP sockets to contact the database server.
- Read/write access. To effectively utilize the Toolbox's caching mechanism, avoid opening your AS400File object for READ_WRITE access. Instead, open it for READ_ONLY or WRITE_ONLY. If you have to do both, try using two AS400File objects, one for each. The reason for this is that when you open a file for READ_WRITE access, the blocking factor is ignored for data integrity reasons, so little or no caching is done of the records in the file.
- Blocking factor. Use a good blocking factor. Experiment a little. If you specify 0 for the blocking factor the Toolbox will calculate an appropriate one for you, based on the file size, number of bytes in a record, etc. Usually this number is optimal, but depending on how you access your file, you may find that another number does better. Remember, the blocking factor is how many records are cached at a time. Too large of a number could result in OutOfMemoryExceptions and too small of a number won't help performance. Bear in mind that a bad blocking factor can actually decrease the file access time in a few cases.
- Keyed access. Do not use a KeyedFile when you can get away with using a SequentialFile. Opening a physical file for keyed access is slower since the database will order the file by key at the time of the open. If you don't need any of the key functionality, just use a SequentialFile object.
- Threads. Remember, it's OK to have more than one Toolbox object representing the same physical file on the system. In fact, in a multi-threaded environment such as Java, this can increase the throughput so that more physical files are accessed simultaneously. When written carefully, a multi-threaded Java program is worth its memory footprint in gold.
- Retrieving record formats. Try not to retrieve the record format for a file repeatedly. If you can, the best way to do it is to hardcode and build the RecordFormat right in your Java program. But sometimes the format of the physical file isn't known, in which case you might try using the createRecordFormatSource() method of the AS400FileRecordDescription class -- this will output the Java source to build the RecordFormat. It can then be compiled and included at build time. Finally, if you must retrieve the record format at runtime, you shouldn't need to do it every time you access the file. Do it once at the beginning of your application and save it off. Communication I/O is the major bottleneck here.
- Text conversion. Specify a CCSID of 13488 for any of your text fields in your physical file. CCSID 13488 is Unicode, so when data is read and written between Java and IBM i, little if any text conversion needs to be done. Most text fields in a physical file (for an English system) default to 37 - the English EBCDIC CCSID. Data translation occurs between this CCSID and Unicode since all Java characters and Strings are in Unicode. Character conversion can become a serious bottleneck for applications that handle large amounts of string data.
- Stay current. A lot of work is done each release to improve the performance of the Toolbox JDBC driver. It is a good idea to use the latest release of the driver. Remember, that this does not mean you necessarily need to upgrade your IBM i. In most cases, you can upgrade your level of the IBM Toolbox for Java product and still communicate with an older release of IBM i.
- Reuse connections. Refrain from opening and closing Connections where possible. These operations are relatively expensive. If possible, keep Connections open and reuse them. A connection pool can help considerably. If your program must perform independent operations (for example, in separate threads or services), use separate Statement objects from the same Connection.
- Fine tuned SQL. If you only need to access a small number of columns or rows, then limit your query as much as possible. For example, suppose your Java program executes "SELECT * FROM TABLE" on a table with 100 columns and 200 rows, but it only needs to access 5 of the columns and only rows that meet a specific criteria. You can greatly improve overall performance by letting SQL do the work rather than your Java program. Do this by fine tuning your SQL query, e.g. "SELECT COL1, COL4, COL89, COL90, COL91 FROM TABLE WHERE COL2 > 55555". Now, the processing happens on the IBM i and much less data is sent to the client program.
- PreparedStatements. If an SQL statement is to be run more than one time, use a PreparedStatement object to execute the statement. A PreparedStatement compiles the SQL only once, so that subsequent executions run quickly. If a plain Statement object is used, the SQL must be compiled and run every time it is executed.
- Column indices versus column names. The get and update methods on ResultSet allow you to refer to columns using either column indices (1,2,3,etc.) or column names ("NAME", "ADDRESS", etc.). Using column indices is faster, since the Toolbox JDBC driver needs to do a sequential table lookup to map column names to their indices.
- Avoid getObject and setObject for built-in data types. ResultSet, PreparedStatement, and CallableStatement provide generic get and set methods in the form of the getObject() and setObject() methods. If you are dealing with built-in data types (boolean, byte, short, int, long, double, float), these methods create a superfluous object. If possible, it is better to use the get and set methods that directly manipulate these types, like getInt(), setShort(), etc.
- Unicode data. Java uses Unicode for all String data. Traditionally, most IBM i databases stored character data as EBCDIC. While the Toolbox JDBC driver does the translation between EBCDIC and Unicode automatically, the translation can be slow. You can reduce translation time by storing character data in the database as Unicode (CCSID 13488), which reduces the amount of translation that is necessary. This strategy works best if the data is commonly accessed by Java programs.
- Extended dynamic support. Use extended dynamic support. This caches the access paths (the compiled SQL) in SQL packages on the IBM i system. This support will improve performance when the same SQL statements are prepared repeatedly across multiple runs of the program. Package caching support pushes this even further by caching the packaging on the client. Enable extended dynamic and package caching support using the "extended dynamic", "package", "package library", and "package cache" properties.
- Stored procedures. Consider using stored procedures. Stored procedures can perform a portion of your program's logic on the IBM i, and can help reduce communication I/O and therefore potentially improve overall response time.
- Disconnect AS400 services.
If you are using instances of class AS400 , don't just let them sit around. Disconnect the services if you are not using the object, by calling either AS400.disconnectService() or AS400.disconnectAllServices() . One of our developers noticed that his servlet had a bunch of threads (AS400 Read Daemons) laying around waiting for input because he never disconnected the AS400 object he was using.