Performance Tuning Guide: DB2 UDB V7.1
Performance Tuning Guide: DB2 UDB V7.1
Performance Tuning Guide: DB2 UDB V7.1
1
Performance Tuning
Guide
A comprehensive guide to improving
DB2 UDB database performance
Tetsuya Shirai
Lee Dilworth
Raanon Reutlinger
Sadish Kumar
David Bernabe
Bill Wilkins
Brad Cassells
ibm.com/redbooks
SG24-6012-00
December 2000
Take Note!
Before using this information and the product it supports, be sure to read the general information in
Appendix C, “Special notices” on page 381.
This edition applies to Version 7, Release 1 of IBM DB2 Universal Database, Program Number
5648-D48 for use with the AIX V4.3.3 operating system.
When you send information to IBM, you grant IBM a non-exclusive right to use or distribute the
information in any way it believes appropriate without incurring any obligation to you.
Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .ix
Tables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xi
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
The team that wrote this redbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv
Comments welcome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvi
Chapter 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .1
1.1 Measuring system performance . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .1
1.2 Determining when system tuning will be cost-effective . . . . . . .. . . . . .2
1.3 Causes of performance problems . . . . . . . . . . . . . . . . . . . . . . .. . . . . .2
1.4 Deciding when to tune the system . . . . . . . . . . . . . . . . . . . . . .. . . . . .3
1.5 Planning performance tuning . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .4
1.5.1 Locate problems and establish goals . . . . . . . . . . . . . . . .. . . . . .5
1.5.2 Identify the cause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .5
1.5.3 Change one performance parameter at a time . . . . . . . . .. . . . . .6
1.6 Architecture and process overview . . . . . . . . . . . . . . . . . . . . . .. . . . . .8
1.6.1 DB2 agents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .9
1.6.2 Buffer pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 10
1.6.3 Prefetchers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 10
1.6.4 Page cleaners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 10
1.6.5 Logs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 11
1.6.6 Deadlock detector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 13
v
6.2.1 Types of memory used by DB2 UDB. . . . . . . . . . .. . . . . .. . . . 195
6.2.2 How memory is used . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 196
6.3 CPU related parameters . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 199
6.3.1 Intra-partition parallelism . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 199
6.3.2 Controlling the number of DB2 agent processes . .. . . . . .. . . . 200
6.4 Memory related parameters . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 201
6.4.1 Sorting methods . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 201
6.4.2 Agent pool size . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 204
6.4.3 Disclaim memory areas for DB2 agents . . . . . . . .. . . . . .. . . . 205
6.4.4 FCM related parameters . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 206
6.4.5 Package cache size . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 206
6.4.6 Utility heap size . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 208
6.5 Disk I/O related parameters . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 208
6.5.1 Buffer pool size (buffpage) . . . . . . . . . . . . . . . . . .. . . . . .. . . . 209
6.5.2 Extended STORagE (ESTORE) . . . . . . . . . . . . . .. . . . . .. . . . 218
6.5.3 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 219
6.6 Network related parameters . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 222
6.6.1 Number of TCP/IP connection managers . . . . . . .. . . . . .. . . . 222
6.6.2 Blocking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .. . . . 223
vii
Appendix A. Sample scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
A.1 Executing db2look. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
A.2 Executing GET DBM CFG / GET DB CFG . . . . . . . . . . . . . . . . . . . . . . . 338
A.3 Display statements in the dynamic SQL cache. . . . . . . . . . . . . . . . . . . . 342
A.4 Disk I/O activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
A.5 Lock information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
A.6 Statement Event Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
A.7 Benchmark tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
This IBM Redbook will provide you with guidelines for system design,
database design, and application design with DB2 UDB for AIX Version 7.1.
We will also discuss the methods that are available for performance analysis
and tuning.
Prior to reading this book, you need to have some knowledge of database
environments, as well as a basic understanding of activities that are typically
performed in a database environment.
This book was written from the AIX operating system perspective, and some
tools and commands discussed in this book may not be available on other
operating systems. However, the hints and methodologies described in this
book can be applicable for database systems which use DB2 UDB on other
operating systems.
This publication does not cover partitioned databases, which you can create
using DB2 UDB Enterprise-Extended Edition (EEE). Please see the DB2 UDB
Administration Guide - Planning, SC09-2946, the DB2 UDB Administration
Guide - Implementation, SC09-2944, and the DB2 UDB Administration Guide
- Performance, SC09-2945 for hints and tips for partitioned databases using
DB2 UDB EEE.
Brad Cassells is the Lead Writer on the DB2 UDB Administration Guide in
the Information Development group of the IBM Toronto Software
Development Laboratory. For the last 8 years he has worked on DB2 UDB
information as team leader, planner, and writer. He is an IBM Certified
Solutions Expert on DB2 UDB Database Administration. In addition, he has 5
years of DB2 for VM and VSE experience, and has worked at IBM for 17
years.
Berni Schiefer
Matthew Huras
Roger Zheng
Haider Rizvi
Cadambi Sriram
Hebert Pereyra
Kaarel Truuvert
Dale McInnis
Adriana Zubiri
Lily Lugomirski
Dwaine Snow
Sean McKeough
Mike Winer
Susan Visser
IBM Toronto Lab
Mikiko Satoh
IBM Yamato Lab
Nhut Bui
IBM Silicon Valley Lab
John Aschoff
IBM Storage Systems Division
xv
Mary Comianos
Emma Jacobs
Yvonne Lyon
Deanna Polm
International Technical Support Organization, San Jose Center
Comments welcome
Your comments are important to us!
When you plan, design, and build your database system, you need to
understand several considerations about logical and physical database
design, application design, and configuration parameters of DB2 so that your
database system can meet the performance requirements of your application.
While its performance may initially be good, as time goes on, your system
may need to serve more users, store more data, and process more complex
queries. Consequently, the increased load level of your database server will
affect its performance. This could be the time to upgrade to more powerful
equipment. However, before investing in equipment, you may be able to
improve performance by simply tuning the database system.
Avoid setting limited performance goals such as “The response time of all
transactions must be less than 3 seconds”. This is not a practical goal,
Other benefits are intangible; for example, greater user satisfaction and
productivity resulting from faster response times. If you manage an Internet
business, higher performance — including quick response time and high
availability — may prevent lost business opportunities. When weighing the
cost of performance tuning against its possible benefits, all of these benefits
need to be considered.
Chapter 1. Overview 3
database manager. Therefore, you should be aware that performance tuning
is not an add-on activity to be done in the production system when there is a
problem. Performance needs to be a design goal. It must be taken into
consideration in each step of the project life cycle:
• Planning
Choose the right hardware, software, and network for your system. Take
care of future growth.
• Design
Choose an appropriate data model and programming interfaces.
• Development
Take performance into consideration when developing application
programs. Choose the right locking strategy.
• Testing/acceptance
Use the same volume of data and configuration as the production system.
• Production
Perform proactive performance tuning.
In this book, we discuss not only tuning the operating system and the
database manager/database configuration parameters, but also various
considerations associated with disk storage layout, database design, and
application design.
If possible, you should execute the queries in the system where the problem
has been observed. If you have to execute them in another environment, it is
important to replicate the original environment as carefully as possible. For
example, if the user is running in client-server mode, then you should set up a
client-server environment to test the queries.
Chapter 1. Overview 5
This step is important, because if you tune resources that are not the primary
cause of performance problems, your efforts will have little or no effect on
response time until you have relieved the major constraints. Also, the
changes you introduce can make subsequent tuning work more difficult.
To update the database manager configuration parameters, you can use the
Control Center GUI tools (as discussed in Chapter 2, “Setting up the Control
Center” on page 15). Or, you can use the following command:
UPDATE DBM CFG USING parameter_name value
To update the database configuration parameters, you can use the Control
Center GUI tools, or use the following command:
UPDATE DB CFG FOR dbname USING parameter_name value
DB2 also provides the registry variables which control the behavior of the
database manager. The registry variables can affect both instance level and
machine level. We introduce some of the available registry variables which
affect the system performance in this book.
To update the registry variables, you can use the following command:
db2set variable=value
You need to restart the database manager when you change the registry
variables.
Before making any changes to performance parameters, be prepared to back
out those changes if they do not have the desired effect or have a negative
effect on the system. For example, the db2look utility with -f option extracts
the current values of the configuration parameters and the DB2 registry
variables. The output of the utility is a script file which you can execute to go
back to the setting at the time when the utility was executed. The db2look
utility also extracts the required DDL statements to reproduce the database
objects of a production database on a test database. This utility is very useful
when testing against a production database is not possible. See the DB2
UDB Command Reference, SC09-2951 for more information.
Note
The db2look utility with -f option only extracts configuration parameters and
registry variables that affect the DB2 query optimizer. Not all registry
variables might be extracted.
Chapter 1. Overview 7
As we have stated, the major causes of performance problems are actually
poor application design or poor database design, rather than the database
configuration itself. Before tuning performance parameters, check to make
sure that your application or database design is not a cause. Chapter 3, “Data
storage management for performance” on page 31 and Chapter 7, “Tuning
application performance” on page 229 describe the points you should
consider when designing databases and developing applications.
Note
DB2 Clients cannot use Named Pipe or NetBIOS to communicate with DB2
on UNIX operating systems, including AIX.
Note
EDUs are implemented as threads within a single process on Windows
32-bit operating systems and OS/2.
Scatter/Gather
I/Os
Log Page
Disks Parallel, Page
write requests
Cleaners
Chapter 1. Overview 9
1.6.2 Buffer pools
A buffer pool is an area of storage memory where database pages of user
table data, index data, and catalog data are temporarily moved from disk
storage. DB2 agents read and modify data pages in the buffer pool. The
buffer pool is a key influencer of overall database performance because data
can be accessed much faster from memory than from a disk. If more of the
data needed by applications were present in the buffer pool, then less time
would be needed to access this data, compared to the time taken to find the
data on disk storage.
1.6.3 Prefetchers
Prefetchers are present to retrieve data from disk and move it into the buffer
pool before applications need the data. For example, applications needing to
scan through large volumes of data would have to wait for data to be moved
from disk into the buffer pool if there were no data prefetchers.
Having multiple disks for storage of the database data means that the data
can be striped across the disks. This striping of data enables the prefetchers
to use multiple disks at the same time to retrieve data. We discuss disk layout
considerations in Chapter 3, “Data storage management for performance” on
page 31.
Page cleaners are independent of the application agents, that look for, and
write out, pages from the buffer pool to ensure that there is room in the buffer
pool. On UNIX, you can see page cleaner processes ( db2pclnr) using the ps
command.
Note
When a page cleaner flushes a dirty page to disk storage, the page cleaner
removes the dirty flag but leaves the page in the buffer pool. This page will
remain in the buffer pool until a prefetcher or a DB2 agent overrides it.
1.6.5 Logs
Changes to data pages in the buffer pool are logged. Agent processes
updating a data record in the database update the associated page in the
buffer pool and write a log record into a log buffer. The written log records in
the log buffer will be flushed into the log files asynchronously by the logger.
On UNIX, you can see a logger process ( db2loggr) for each active database
using the ps command.
Neither the updated data pages in the buffer pool nor the log records in the
log buffer are written to disk immediately to optimize performance. They are
written to disk by page cleaners and the logger respectively.
The logger and the buffer pool manager cooperate and ensure that the
updated data page is not written to disk storage before its associated log
record is written to the log. This behavior ensures that the database manager
can obtain enough information from the log to recover and protect a database
from being left in an inconsistent state when the database is crashed
resulting from an event such as a power failure.
Chapter 1. Overview 11
The data in the log buffer is only forced to disk:
• Before the corresponding data pages are being forced to disk. This is
called write-ahead logging.
• On a COMMIT; or after the value of the number of COMMITS to group
( mincommit) database configuration parameter is reached.
• When the log buffer is full. Double buffering is used to prevent I/O waits.
First, the page to be updated is pinned and latched with an exclusive lock. A
log record is written to the log buffer describing how to redo and undo the
change. As part of this action, a log sequence number (LSN) is obtained and
is stored in the page header of the page being updated. The change is then
made to the page. Finally, the page is unlatched and unfixed. The page is
considered to be dirty because there are changes to the page that have not
been written out to disk. The log buffer has also been updated.
Both the data in the log buffer and the dirty data page will need to be forced to
disk. For the sake of performance, these I/Os are delayed until a convenient
point (for example, during a lull in the system load), or until necessary to
ensure recoverability, or to bound recovery time. More specifically, a dirty
page is forced to disk when a page cleaner acts on the page as the result of
these situations:
• Another agent chooses it as a victim.
• The CHNGPGS_THRESH database configuration parameter percentage value is
exceeded. Once exceeded, asynchronous page cleaners wake up and
write changed pages to disk.
• The SOFTMAX database configuration parameter percentage value is
exceeded. Once exceeded, asynchronous page cleaners wake up and
write changed pages to disk.
If you set the number of page cleaners to zero and no page cleaner is started,
a dirty page is forced to the disk storage by another DB2 agent which
chooses it as a victim.
DB2 uses a background process, called the deadlock detector, to check for
deadlocks. When the deadlock detector finds a deadlock situation, one of the
deadlocked applications will receive an error code and the current unit of
work for that application will be rolled back automatically by DB2. When the
rollback is complete, the locks held by this chosen application are released,
thereby allowing other applications to continue.
Chapter 1. Overview 13
14 DB2 UDB V7.1 Performance Tuning Guide
Chapter 2. Setting up the Control Center
DB2 provides the install script (db2setup), but the Control Center is not
installed by default on UNIX platforms. In this chapter we introduce the
Control Center and describe how to set up the Control Center.
Tool Bar
The Systems object represents the one local and two remote machines. To
display all the DB2 systems that your system has cataloged, expand the
object tree by clicking on the plus sign (+) next to Systems. The left portion of
the screen lists available DB2 systems. We can see from Figure 2 that the
system ununbium contains an instance, db2inst1. The instance db2inst1 has
four databases.
When Systems is highlighted, details about each system are shown in the
Contents Pane. We can see that they are AIX systems.
If you want to see each database object in detail, you can expand a database
icon and list each database object by clicking on the plus sign (+) next to a
database icon. Figure 3 shows the table lists that are defined in the SAMPLE
database of the db2inst1 instance.
If you do not use the db2setup utility and use the AIX installp command or
SMIT to install the DB2 products, select the file set db2_07_01.wcc to be
installed.
The Control Center is written in Java and can be run as a Java application or
as a Java applet through a Web server. In both cases, you need a supported
Java Virtual Machine (JVM) installed on your machine to run the Control
Center. A JVM can be a Java Runtime Environment (JRE) for the Control
Center applications, or a Java-enabled browser for the Control Center
applets.
For more information about installing the products, please see the manual
DB2 for UNIX Quick Beginnings,GC09-2970.
The DAS instance is started automatically. You can start and stop it using the
db2admin start and db2admin stop command.
If you want to use the Control Center on the client machines, be aware that
the DB2 Run-Time Client does not provide the GUI tools. You should install
the DB2 Administration Client or DB2 Software Developer’s kit. In this case,
the process of the Control Center is running on the client machine, and the
instances and databases on the server machine are managed remotely.
If you intend to use the Control Center on other operating systems than
Windows and AIX, you must install the correct JRE level before running the
Control Center. See the manual Installation and Configuration Supplement,
GC09-2957 for information about the correct JRE level you need to install.
Also, check the latest service information on the Control Center at the
following URL:
http://www.ibm.com/software/data/db2/udb/db2cc/
Java applets are programs that run within Java-enabled browsers. The
Control Center applet code can reside on a remote machine and is served to
the client's browser through a Web server. Since there are no supported
browsers for AIX and other UNIX operating systems, this is not an option you
can choose if you want to use the Control Center from UNIX machines.
However, on Windows 32-bit or OS/2 operating systems, you can use the
Control Center as a Java applet using a supported Java-enabled browser.
See the manual Installation and Configuration Supplement, GC09-2957 for
information about the supported browser.
Scenario 1 and Scenario 2 are cases that the Control Center runs as a Java
application. In Scenario 1, the Control Center runs on the same machine as
the DB2 server runs. In Scenario 2, the Control Center runs on a different
machine as the DB2 server runs and accesses it through the DB2
Administration Client. Machine A can be any supported platform for the DB2
Administration Client.
Scenario 3 and Scenario 4 are cases that the Control Center runs as a Java
applet. In Scenario 3, the Control Center applet code resides on the same
machine as the DB2 server runs, and it is served to the client's browser
through a Web server. In Scenario 4, the Control Center applet code is
served to the client's browser through a Web server as well; however, it
resides on a different machine in which the DB2 server runs and access it
through the DB2 Administration Client. In Scenarios 3 and 4, only a Windows
or OS/2 machine can be Machine A.
On AIX or other UNIX operating systems containing the DB2 JDBC Applet
Server, enter the db2jstrt 6790 command.
On the Windows 32-bit or OS/2 operating system containing the DB2 JDBC
Applet Server, enter the db2jstrt 6790 command to start the DB2 JDBC
Applet Server. On Windows NT, you can also start the DB2 JDBC Applet
Server by clicking on Start->Control Panel->Services. Select the DB2
JDBC Applet Server - Control Center service and click on the Start button.
If you choose to use a virtual directory, substitute this directory for the home
directory. For example, if you map sqllib to a virtual directory called temp on
a server named yourserver, then a client would use the URL:
http://yourserver/temp
We will not explain basic concepts and tasks, such as creating a database, a
table space, or a buffer pool. Rather, we will provide information that can be
used to help understand how creating these components in certain ways can
affect performance.
For information on the commands to perform these tasks, please refer to the
DB2 UDB Administration Guide: Implementation, SC09-2944 or the DB2 UDB
SQL Reference, SC09-2974.
How the data is physically laid out across the disks affects performance, as
we explain in the following sections.
Workload considerations
The type of workload your database is tasked to perform needs to be taken
into account when considering how the physical database layout may affect
the performance of the database. The primary function of each workload type
should give you some indiction of how to lay out the database.
For example, if the database is part of a Web application, then typically its
behavior will be On-line Transaction Processing (OLTP). There will be a great
deal of concurrent activity, such as large numbers of sessions active, simple
SQL statements to process, and single row updates. Also, there will be a
requirement to perform these tasks in seconds.
This information gives the database administrator some ideas which can be
used to aid in the physical design of a database which will be well-suited to
that type of workload.
Another important factor is the location of the logical volume on the disk itself.
In most cases, the general advice would be to place the logical volume as
close to the center of the disk as possible. However, with the log filesystem or
raw logical volumes, this is NOT the case. The typical activity of the DB2
logger process, which writes to the log files, will be a large number of
sequential reads and writes. For this reason, when creating the logical
volume, ideal placement is on the outer edge of the disk where there are
more data blocks per track.
Availability
Irrespective of the type of logging you choose, whether it be Circular Logging
or Archival Logging, the availability of the physical disks is crucial to the
database. For this reason, it is strongly recommended that you protect the log
against single disk failures by using RAID 1 (mirroring the log devices), or by
storing log files on a RAID 5 array.
You might wonder why a RAID 5 array, which incurs the write penalty, is
suitable for log files. We will discuss RAID disks and write penalty in 3.2,
“Mirroring, striping, and using RAID devices” on page 35.
Note
Some further considerations for mirroring and striping are also discussed in
3.3, “Table spaces: performance considerations” on page 52
3.2.1.1 RAID 0
Also known as striping, RAID 0 does not bring any additional data
redundancy to a disk subsystem. Primary goal of RAID 0 is to improve I/O
performance. When data is written, using a striped logical volume, the data is
divided into small pieces known as chunks or stripe units. These units are
then written to the disks in parallel, in a round-robin fashion. During a read
operation the same units are read back in parallel then written directly to the
caller’s memory area where they are re-assembled into the original data.
Main problem with RAID 0 is obviously that any disk failure in the array will
render the data on the remaining disks unusable. For that reason only
consider RAID 0 is you require good performance but are not concerned
about availability.
3.2.1.2 RAID 1
Also known as mirroring, RAID 1 is simply keeping a copy of the data in a
different location to protect against data loss in the event of a disk failure. So
from the availability perspective, the copies should be kept on a separate
physical volume which ideally should be attached to a separate I/O adapter.
To take this one stage further, another possibility would be to have the
second disk in a separate disk cabinet to protect against events such as a
power loss to one of the disk cabinets.
In the event of a disk failure, read and write operations will be directed to the
mirrored copy of the data. In performance terms, mirroring has some
advantages over striping. If a read request is received and the primary data
copy is busy, then the AIX LVM (Logical Volume Manager) will read the data
from the mirrored copy. Write performance is affected by the write scheduling
Although mirroring can improve the read performance, the penalty is write
performance. For optimal performance, we recommend the use of the Parallel
scheduling policy. See 3.2.3, “AIX logical volume parameters” on page 40 for
more details on scheduling policy.
• For more detailed information on the AIX Logical Volume Manager, refer to
your AIX documentation.
Note
In AIX, when mirroring data, ONLY the logical volumes are mirrored, not
the physical disk. Mirroring is not a tool to provide a disk copy
3.2.1.3 RAID 5
In a RAID 5 array, data and parity are spread across all disks. For example, in
a 5+P RAID 5 array, six disks are used for both parity and data. In this
example, five-sixths of the available space is used for data and one-sixth is
used for parity.
Because of the parity data used by RAID 5, each write to the array will result
in four I/O operations; this is known as the RAID 5 write penalty:
1. Read old data
2. Read old parity
3. Write new data
4. Write new parity
Fast Write Cache (FWC), which exists on some RAID adapters, can reduce
the effects of this write penalty. RAID 5 is commonly chosen because it
provides an extremely good price/performance ratio combined with good
availability. By default, FWC will be OFF; see 3.2.4, “SSA RAID array
parameters” on page 42 for more information on checking and setting FWC.
Using the Enterprise Storage Server (ESS), which has a large cache, can
significantly decrease the effects of the write penalty. See 3.2.9, “Using
Enterprise Storage Server” on page 50 for more information on ESS.
3.2.1.4 RAID 10
• Sometimes called RAID 0+1, this RAID level provides better data
availability at the cost of extra disks. Consider a striped logical volume,
where failure of one disk renders the entire logical volume unusable. RAID
Note
AIX 4.3.3 introduces the ability to create logical volumes outside of RAID
which are mirrored and striped, known as RAID 0+1 or RAID 10.
3.2.2.1 Striping
If you are using striping, the following are some general performance
considerations:
• Set max_coalesce equal to or a multiple of the stripe unit size, but not
smaller. See 3.2.4, “SSA RAID array parameters” on page 42.
• Set minpgahead to 2 and maxpgahead to 16 * number of disk drives, using the
AIX vmtune command. Refer to the AIX documentation for more details on
these parameters.
• Modify maxfree to accommodate the change in maxpgahead so that the
difference between minfree and maxfree is maxpgahead.
• If the striped logical volumes are raw logical volumes, consider increasing
the lvm_bufcnt parameter of the AIX vmtune command; see 3.2.3, “AIX
logical volume parameters” on page 40 for more details on this.
• If you create a logical volume for a DB2 container which will be intensively
used and updated, try NOT to put it on a disk with your striped logical
volumes.
To use vmtune, install the AIX fileset bos.adt.samples, and the executable
will be placed in the /usr/samples/kernel/ directory
3.2.2.2 Mirroring
The following are performance considerations for mirroring:
• Be aware that when you use mirroring, every write performs multiple
writes, this will affect performance. When mirroring, set the scheduling
policy to parallel and allocation policy to strict, as discussed in 3.2.3,
“AIX logical volume parameters” on page 40.
• Mirrored logical volumes which are frequently accessed should be placed
on the outer edge of the physical volume, because the mirror write
consistency cache resides there and this is updated frequently. Please
refer to the 3.2.3.3, “Mirror write consistency” on page 41 for more details.
RAID 5:
Read performance is affected by number of disks within the array. With a
greater number of disks, the I/O throughput increases, because more
requests can be processed in parallel (up to the RAID adapter limit).
If you do not have FWC, mirrored disks would be a better choice for log files
than a RAID 5 array.
To check the scheduling policy, you can use SMIT or the lslv command. The
attribute to look for is SCHED POLICY, as shown in Figure 10.
When creating a mirrored logical volume using the mklv command, the -d p
flag and attribute will influence the scheduling policy.
From DB2’s point of view, having MWC on for the log disks, for example,
would prove very costly, as every write would consist of two operations, one
to write the data and one to update the MWC cache record. Using hardware
write cache such as that contained on certain SSA adapters can minimize this
impact. If you do decide to disable MWC, then it will be necessary to put in
place a procedure to re-synchronize the mirror copies in the event of a
system crash. The volume groups containing such logical volumes would
need to have their autovaryon capability disabled, and then after the system
comes back up, each mirrored logical volume would need to be
re-synchronized by running the following command:
syncvg -f -l <logical volume name>
If you are going to create such logical volumes and leave MWC set to ON, then
write performance will be affected, so try to locate these logical volumes on
the outer edges of the disks, as this is where the MWC cache is located. This
will help minimize disk head movements when performing writes.
For more information on volume group attributes and selecting where on the
disks to create logical volumes, refer to the AIX Commands Reference ,
SBOF-1851-00. Commands to look at are mkvg and chvg (for existing volume
groups); mklv and chlv (for existing logical volumes).
We will now use an example to demonstrate how to check these values and
make recommendations on how SSA RAID array parameters can effect table
space configuration decisions.
First we need to know what the RAID logical disks are on our system. To do
this, we can run the following command — we can see here that on this
system we only have one logical SSA RAID disk, hdisk4 (the logical disk will
be made up of multiple physical disks).
To set this value, use the following command for the logical SSA disk you
want to change. The chdev command can also be used to alter queue_depth.
chdev -l hdisk# -a max_coalesce=(0x10000 * N)
Note
Make sure any volume groups defined on the array are varied off before
making changes to the above parameters.
You will now be presented with a screen similar to Figure 12, from which you
can select the SSA Logical Disk name:
We now see a screen as in Figure 13 below. Here you can see the
max_coalesce and queue_depth settings:
For a 9+P array of 10 disks, set the value to 0x90000 which is 9x64KB.
With SSA, the fast write cache can be used if you have a RAID array
configured, or even if you are just using it as JBOD (just a bunch of disks).
To check if you have fast write cache modules installed, you will need to look
at the vital product data (VPD) for your adapters. This can be checked using
the SMIT ssafastw fast path, or from the command line as shown in Figure 14:
Using the AIX command, lscfg -vl <adapter_name>, we can view the adapter
information as shown above. From this we can see that the attribute Device
Specific (Z1) tells us if the adapter contains a plugable fast write cache
You can also see, in Fig. 15 on page 47, how the ssaraid command can be
used to show the status of the fast write cache attribute.
Note
The entry, Device Specific (Z0) represents the size, in megabytes, of the
installed synchronous dynamic random access memory (SDRAM)
modules. This is NOT fast write cache.
When enabling the fast write cache for a device, in order for the change to
take effect, you must ensure that:
• All filesystems associated with the volume group the disk belongs to must
be unmounted.
• Once filesystems are unmounted, the volume group must be varied off.
If you do have a fast write cache module installed, then to turn fast write
cache on, you can use SMIT. The fast path command would be:
smitty ssafastw
From the command line, this can be done by running the following command:
ssaraid -H -l ssa0 -n hdisk4 -a fastwrite=yes
In this example, we are enabling the fast write cache for the SSA logical disk,
hdisk4, which is attached to the ssa0 adapter. Once the change has been
made, the volume group can be varied back on again, and the filesystems
can be mounted.
We would recommend that for any table space using a RAID device, you
should define only one container. The reason is that, if you define multiple
containers, then the data will be striped, not only across the DB2 containers,
The SSA RAID logical disk attribute strip_size is the parameter that you
need to look at. The strip_size parameter is set when the array is created.
Once the array is created, you can query the value used for strip_size as
shown in Figure 15; the value used for this parameter is in 512 byte blocks,
not KB:
In Figure 15, you can see that strip_size is set to 128 for this particular SSA
RAID logical disk. This value represents 64 KB (128 * 512 byte blocks).
Because the SSA RAID array is striped in this way, it is recommended that
you set the following DB2 registry variable BEFORE creating any table space
containers on the array.
The reason this variable does not affect DMS file containers is that the pages
allocated for the DMS file container are still allocated by the filesystem, so we
cannot guarantee that the pages in the container will be contiguous across
the disk(s). With raw devices, DB2 controls this and allocates the pages
contiguously.
The next stage is to create the raw logical volume on the RAID array. Let us
assume the logical volume is called tbslv. We now connect to the database
and create the table space using a command like that shown below.
CREATE TABLESPACE TBS1
MANAGED BY DATABASE USING
(DEVICE '/dev/rtbs1lv' 2000) PAGESIZE 8K
EXTENTSIZE 8
PREFETCHSIZE 24
Using an array = 3 + P (3 parallel plus one parity) and a strip size = 64k, we
can say that the above CREATE TABLESPACE command will give us the following
results:
In our example, we have been using DMS raw containers. When this type of
container is used, the operating system does not do ANY prefetching or
caching, so ensure that you use an adequate PREFECTHSIZE and enable the
table space for parallel I/O.
You can enable parallel I/O for every table spaces using the DB2_PARALLEL_IO
variable, as shown in the following example:
db2set DB2_PARALLEL_IO=*
You can also enable parallel I/O for a list of table spaces IDs
(comma-separated) as in the following example:
A list of table space IDs can be obtained by running the LIST TABLESPACES
command when connected to your database, or you could run this command:
SELECT TBSPACE,TBSPACEID FROM SYSCAT.TABLESPACES
After setting the DB2_PARALLEL_IO registry variable, you must run db2stop and
then db2start for the change to take effect.
Note
Also refer to the table space parameters OVERHEAD and TRANSFERRATE
discussed in 3.3, “Table spaces: performance considerations” on page 52.
Note
Once this parameter has been set to YES for a particular database, it
cannot be set back to NO.
One recommendation would be to look at the value being used for the
NUM_IOSERVERS parameter. We would recommend that a good starting value
would be to set the NUM_IOSERVERS equal to the number of the ESS's ranks.
Note
One ESS rank is a set of 7 Raid-5 disks (a 6+P array). Normally you will
have two spare disks per SSA loop, so the array may be known as a
6+P+S. In ESS the spare disk is able to "float" between different arrays.
Using that as a starting point, NUM_IOSERVERS can then be increased, but some
tests have shown that, in some cases, this does not provide any performance
improvements; in fact, there may be some small overhead in going for a
larger value. This will ultimately be up to the database administrator to test,
as all environments are different, and the value used will depend on factors
such as workload type, for example, DSS or OLTP.
If you use your ESS unit, which has a large cache, with a system which also
has a large amount of physical memory dedicated to DB2 (such as large
buffer pools) then the NUM_IOCLEANERS value need not be very large. Using the
number of CPUs in the system would be a good starting point.
It is also recommended that if your database uses mainly SMS table spaces,
then having more containers per ranks of ESS gives better performance.
For example, suppose you create a filesystem on one ESS rank, then define
it as a container for one of your SMS table spaces. Doing this could cause a
performance degradation due to i-node lock contention in the operating
system. By defining multiple containers for the SMS table space, you would
reduce the i-node lock contention. Some tests have shown that allocating four
containers per ESS RAID array achieves very good results.
With SMS table spaces, data objects (table data, indexes, LONG
VARCHARs, and LOBs) are located by operating system file name.
With DMS, you can increase table space capacity via ALTER TABLESPACE ADD
CONTAINER, or use a new feature in DB2 v7.1 — the addition of two new
clauses for the ALTER TABLESPACE statement. These are RESIZE and EXTEND.
These options will be discussed in 3.3.9.2, “Container sizes” on page 68.
When using DMS device containers in a table space, you need to understand
the following performance considerations:
• File system caching for DMS file containers is performed by the operating
system in the filesystem cache; on AIX this is the JFS cache.
• File system caching for DMS device containers (raw logical volumes for
example) is NOT done by the operating system.
0 1
2 3 Table1
4 5
6 7 Table2
11
Extents Striped
across containers
8
When using DMS raw devices, DB2 will ensure that pages are placed
contiguously on the disk drives; with SMS containers, this is not the case, as
the filesystem decides where to locate the pages (this can also apply to DMS
file containers). Contiguous placement of pages is important, as pages make
up DB2 extents. Contiguous pages will speed up operations like table scans.
You can, of course, drop USERSPACE1 if you wish, as its use for data is optional.
Mostly, you will create additional table spaces for your data. However, the
name SYSCATSPACE must be used for the table space which is holding the
system catalogs.
When any application has a need to access data from a long table space
(whether the data be LOBs, LONG VARCHAR, or LONG VARGRAPHIC), the database
manager cannot use the buffer pools to cache the data. Therefore, every time
a page is requested, the database manager must request it from disk (see
point in this section on DMS file containers to help with this).
Long table spaces must be DMS type table spaces. Use of long table spaces
is optional, as the data type can reside in regular table spaces.
From a performance point of view, as LONG data is NOT stored in the buffer
pools, then you can use DMS file containers instead of raw devices. The
reason for this is that by using the file containers, you will benefit from the
operating system’s filesystem cache.
All databases in DB2 must have at least one system temporary table space.
The default, called TEMPSPACE1, is created by default as an SMS table space.
As we have said already, raw containers will, in nearly all cases, outperform
file containers because the database manager can bypass the operating
system’s file system and also avoid unnecessary double buffering.
Again, LOB or LONG VARCHAR data benefits from the use SMS or DMS table
spaces with FILE containers, as they benefit from the operating system’s
filesystem cache. LOB and LONG VARCHAR are not buffered in DB2's buffer pools,
as they use direct I/O. Any memory allocated to long table spaces should be
kept to a minimum, or alternatively, just use the default buffer pool
IBMDEFAULTBP.
The main advantage of using SMS for temporary table spaces is that data
stored in temporary tables is mostly transient data (for example batch work).
By using SMS you will only allocate disk space as and when required, unlike
DMS, which will allocate all specified space when the table space is created.
If you have table spaces utilizing different page sizes, then our suggestion
would be to create one temporary table space with a page size equal to that
of the majority of your data tables (see note on reorg). When selecting
The reason we suggest only having one temporary table space for a given
page size is because when you have multiple temporary table spaces using
same page sizes, the DB2 optimizer will generally choose a temporary table
space size by selecting the temporary table space with the largest buffer
pool. Let us say you had two 16 KB temporary table spaces defined called
TEMP1 and TEMP2. Now assume TEMP1 has a large buffer pool and TEMP2 has only
a small buffer pool; UDB will select TEMP1 as it has largest buffer pool. Once
selection is made, UDB will then alternate between ALL temporary table
spaces which have the chosen page size (16 KB).
Note
If you reorganize table spaces in the temporary table space, then you will
need a temporary table space which has the same page size as the table
space being reorganized.
For the catalog table space, use SMS or DMS with FILE containers and a
small extent size (2 or 4 pages).
The reason for this is that the catalogs contain a lot of relatively small tables.
DMS requires 2 overhead extents per table (Extent Map Page + 1st data
extent). SMS requires only 1 page.
Here are some considerations for placing tables, which might help you decide
which tables should go:
• When recovering your table spaces, if you have a collection of tables
related by Referential Integrity (RI) constraints or summary tables, then if
you ever need to restore the tables, they should be rolled forward together
to a point in time. If this is not done, then one table, or more, will be placed
in a check pending state.
• If you are using DMS table spaces, you then have the option of creating
what are known as "spanned" tables. A spanned table has data pages in
more than one table space. The best example of this is a table which has
its data in one table space, indexes in another, and LOB data in another.
Only DMS supports this. An advantage of using spanned tables is that, by
separating data and indexes, you can place the indexes in a table space
with its own dedicated buffer pool, which can help ensure that index pages
are kept in memory.
• How much raw data is in the tables is also important. If you have a number
of small tables with a small amount of data which are not changed
frequently, then it is feasible to group these tables together in a single
table space. Larger base tables which are heavily accessed and
frequently updated can justify having their own DMS table space. From a
performance point of view, if a very large table has its own table space,
then you can also assign it a dedicated buffer pool (see 3.4.1.2, “Multiple
buffer pools” on page 72 for details on this subject). By grouping tables in
specific table spaces, you can perform flexible backup strategies as you
have more granularity.
• Keeping important tables in their own table space will simplify
administration of this table space and will speed recovery should the table
space need to be restored (because you will only have one table to
restore). When required, you can also create a dedicated buffer pool for
these tables.
• Group infrequently accessed data in table spaces which use containers on
slower devices.
• Minimize relationships (such as RI constraints) between table spaces; this
simplifies recovery.
Over the last few years, many people have performed benchmarks on device
containers (raw logical volumes) versus directory and file containers (JFS file
systems). In nearly all cases these benchmarks have shown an overall
improvement in disk I/O throughput of 10-35 percent when using device
containers, as compared to JFS file systems. However, the database
administrator needs to take into account that actual gains will vary, depending
on the I/O workload mix of the application, OLTP or DSS.
3.3.7.1 Directory
This is the only container type that can be used in SMS table spaces. When
creating SMS table spaces, make sure you specify at creation time all the
directories (containers) that you want to incorporate into the table space;
additional containers CANNOT be added once the table space exists.
3.3.7.2 File
File containers are used by DMS table spaces and are files of a pre-allocated
size. DMS treats file and device containers in the same way. When choosing
a size for the file, be aware that the space required, for the chosen size, is
pre-allocated. When the file is created, DB2 will allocate the entire container
(file) at table space creation time. Even though this allocation is done at
creation time, the operating system’s filesystem may still fragment the file, so
in some cases, the allocation of pages may not be contiguous.
If using DMS table spaces, then in most cases, file containers will give poorer
performance when compared to raw device containers. The reason for this is
that with file containers, the database manager has to interact with the
operating system’s filesystem layer, unlike raw device containers, which the
database manager manages directly. An exception to this rule would be a
DMS table space using file containers that was created to hold LOB data. In
this case, performance might be greater than that of device container, since
DB2 can take advantage of the filesystem cache. Remember that LOB data is
NOT buffered by DB2, so using device containers would result in direct disk
I/O operations when accessing LOB data.
3.3.7.3 Device
On AIX, device containers are commonly known as raw logical volumes. This
type of container can only be used by DMS table spaces. When using device
containers, the space, as with file containers, is also allocated at table space
creation time. However, in this case, DB2 interacts with the raw device
directly, which ensures that page allocation is contiguous.
The DMS and device container combination avoid the double buffering
scenario which can occur with DMS file containers or SMS directory
containers. This occurs when pages are cached by the operating system in its
filesystem cache and by DB2 in the buffer pools. This scenario is a waste of
resources.
For random access workloads (such as OLTP), you will need as many disks
in the table space as are necessary to support the required I/O. For this type
of workload, writes will be the main concern, as they are more expensive than
reads (RAID systems), therefore the read/write ratio of one physical write has
to be considered.
For sequential access workloads (such as DSS), some of the same points
apply; you will need sufficient disks to support the required I/O. However, in
most situations, DSS workloads will be more “disk-friendly”; this is because
they have larger I/O sizes, which are generally sequential. This, along with
other factors such as prefetching and disk caching, means that a DSS
workload may be able to work efficiently with fewer disks than an OLTP
system, with similar I/O requirements.
There are also two table space configuration parameters that can be set with
either the CREATE TABLESPACE or ALTER TABLESPACE statements, which will also
affect the performance of your table space containers. These are defined in
two columns contained in SYSCAT.TABLESPACES, and the values can be shown
by running the command:
SELECT TBSPACE,OVERHEAD,TRANSFERRATE FROM SYSCAT.TABLESPACES
The DB2 optimizer considers these two parameters when determining the I/O
cost of accessing data from a particular table space. The results the optimizer
obtains can affect a number of its decisions, for example, whether or not to
use a particular index contained in a certain table space container, or which
table to select for the inner and outer tables in a join statement.
Overhead
Overhead is an estimate (in milliseconds) of time required by the container
before data is read into memory. The following formula can be used to
estimate overhead cost (I/O controller, latency, seek time). A detailed
explanation of this formula can be obtained in the DB2 UDB Administration
Guide: Performance, SC09-2945.
OVERHEAD = average seek time in milliseconds + ( 0.5 * rotational latency )
In this formula, 0.5 represents an average overhead of one half rotation and
rotational latency (milliseconds / full rotation) is given as:
( 1 / RPM ) * 60 * 1000
So, assume an average seek time of 5.4 milliseconds for this disk type; this
gives the following estimated OVERHEAD:
5.4 + ( 0.5 * 6.0 ) = 8.4 milliseconds
Transfer rate
This is also an estimate given in milliseconds. TRANSFERRATE represents time
taken to read one data page into memory.
In this formula, spec_rate is disk specification for transfer rate (MB/sec) and
PAGESIZE represents the table space PAGESIZE value you have chosen for the
table space which owns this container.
DB2 uses default values of 24.1 milliseconds for OVERHEAD and 0.9
milliseconds for TRANSFERRATE.
When calculating the TRANSFERRATE you need to take into account the following
considerations if your table space containers are made up of more than one
single physical disk (for example, an array such as RAID):
• If the spec_rate value is small, then multiply by the number of physical
disks on which the container resides, assuming bottleneck at disk level.
• If the number of disks is large, then I/O bottleneck is not likely to be due to
disks, but more likely due to disk controller or I/O buses (system). If this is
the case, then you will need to test the actual I/O rate. Refer to the DB2
UDB Administration Guide: Performance, SC09-2945 for further
suggestions on how to do this. One suggestion would be to monitor the
sequential scan of a large table.
If they are not the same, or you do not have the hardware documents that
contain the information you require for the formulas given, then set the
OVERHEAD value to the average of all the disks in the table space. As for
TRANSFERRATE, if no figures are available, try to set this to the value for a single
physical disk for OLTP environments (or the value of the slowest disk). For a
DSS environment, set TRANSFERRATE to the sum of all the disks. If your
workload is a mixture, then use a figure in between the recommendations for
OLTP and DSS.
Note
Use large page sizes for temporary table spaces, as rows in tables that
reside in this type of table space will be accessed sequentially.
However, there is an exception to this rule. When row size is smaller than
page size/255, we will have wasted space on each page, as there is a
maximum of 255 rows per page. If this applies to your system, then using a
smaller page size may be more appropriate. Remember that the database
manager allocates 76 bytes in each page (regardless of size) for control
information. So using the default size of 4 KB as an example, this would leave
4020 bytes for data. Maximum row lengths and column limits for each page
size are shown in Table 2.
Larger page sizes may allow you to reduce the number of levels in the index,
since more index keys will fit on each index leaf page. However, remember
that each index page can have only 255 index entries. Therefore, if your
index key size is small, a good percentage of the page might be wasted with
a large page size.
This allocation policy will influence your table space performance. Let us
assume you have a number of small tables which you want to group together
in one table space. If you decide to use DMS, when a new table is created,
two extents are immediately required for the table object. If you have many
small tables in this table space, then the database manager would allocate a
lot of disk space to store a small amount of data.
You may notice when using DMS table spaces that a number of pages are
used up when you first create the table space and then create the first object
(table). Figure 17 shows how these pages are used up on the initial creation
of both the table space itself and the object. Note that each subsequent table
added to the same table space will incur a minimum overhead of two extents.
extent map
1 extent
Object creation
(such as a table) extent for data 1 extent
Figure 17. Minimum initial extent requirements for DMS table space
When the first storage object in table space is created, the following pages
will be required, as shown above (assuming EXTENTSIZE=32):
When using "striped" containers (like RAID), extent size should be set to a
multiple of the stripe size (such as RAID strip size), as we discussed in 3.2,
“Mirroring, striping, and using RAID devices” on page 35.
If you want to perform aggressive prefetching initially, try doubling the figure
obtained after using the formula ( EXTENTSIZE * number of containers).
Regardless of whether you want to increase or decrease prefetching, it is
best if the value used is still a multiple of EXTENTSIZE.
Note
To disable prefetching on a table space, set PREFETCHSIZE to 0 using the
ALTER TABLESPACE statement.
Normally you want to map each disk (or filesystem) to its own container for
the following reasons:
• Isolation from disk errors
• Ability to better isolate parts of a workload (or database) from one another:
For example, separating tables scanned simultaneously into separate
table spaces with separate disks can reduce disk head movement (thus
seek time) when doing sequential scans.
As another example, you may want to protect time-critical data from
random/adhoc queries on other data (remember that there are usually still
shared CPUs and buses, so this is not always effective).
Note
Introduced with DB2 UDB v7.1 is the ability to increase the size of DMS
containers using the RESIZE or EXTEND clauses of the ALTER TABLESPACE
command. See the DB2 UDB SQL Reference, SC09-2974 for more
detailed information.
Availability
Other than parallel I/O performance, the main advantage of mapping one
container to each physical disk is availability. With this system setup, disk
errors will be isolated to only one container and therefore only one table
space.
Load
With disk drive capacity increasing all the time, it may not be cost effective for
you to have only one container per disk (especially as the disk could be
18 GB, 32 GB, or more). However, there is a scenario in which having more
than one container on a disk may not cause you any performance problems.
Imagine that you have two table space containers on an 18 GB drive
(9 GB/container), each belonging to two different table spaces. Normally this
setup would be sub-optimal, but if one of the table spaces is only accessed at
certain times (for example, month-end), and the other is accessed during
normal operation but not at month-end, then having containers share the
same physical disk would not be a problem.
Apart from the Availability and Load considerations discussed, you may need
multiple containers on older operating systems to get past a file size limit
(such as 2 GB)
You also may need multiple containers per filesystem to reduce inode
contention (AIX). One file for a heavy read/write table will result in inode
contention; 2 or more containers on the same filesystem can help reduce this
contention.
The table space is then recreated using the new name, and the objects within
the table space are then recreated. Obviously this is a big problem in terms of
availability if the table space is very large or contains many data objects.
The new command will allow a user to rename the table space with a single
SQL statement (for example, only updating catalog records and changing
table space control information). An example of this would be:
RENAME TABLESPACE USERSPACE1 TO NEWSPACE1
Please refer to the DB2 UDB SQL Reference, SC09-2974 for more details.
Note
If you rename a table space, then you need to restore the table space from
an old backup image taken before the rename command was run. The new
name must still be used to perform the restore.
The most common question asked is, "How much memory do I need to
allocate for buffer pools?" Although there is no definitive answer to this
question, the general rule of thumb would be to start with about 75% of your
system’s main memory devoted to buffer pool(s), but this rule has to be
considered VERY carefully before being followed. The biggest factor for
consideration is obviously the answer to the question, "Is this machine a
dedicated database server?"
If the answer is no, then allocating 75% of system memory to DB2’s buffer
pools is not going to be a good idea. It is the database administrator’s job to
determine how much memory there is available on the system for DB2’s use,
after allowances for the operating system and other applications have been
made.
Many people want to know why the default buffer pool (IBMDEFAULTBP) is
so small (1000 * 4 KB). The main reason is to allow you to connect to a
database in situations where you may have over-allocated memory
elsewhere. We do not recommend that you run a database using only the
default buffer pool, but once connected to your database, you can then add
additional buffer pools dedicated to specific table spaces.
When you add buffer pools to your database, the total memory required by all
buffer pools must be available to the database manager to allow the buffer
pools to be activated when the database is started. Should this memory not
be available, then only the default buffer pool ( IBMDEFAULTBP) is started along
with one buffer pool for each table space which uses a page size different
from the 4 KB default. This allows you to connect to your database. These
extra buffer pools will be restricted to 16 pages. If this behavior was not the
default, then you could potentially allocate too much memory to your buffer
pools; and when you attempted to activate or connect to the database, the
operation would fail.
Each buffer pool page allocated uses space in the memory allocated for the
database heap (DBHEAP), for internal control structures. Therefore, if you
increase your BUFFPAGE parameter and/or the total size of your buffer pools
then also ensure that you remember to increase DBHEAP.
If you decide to opt for table spaces using multiple page sizes, then you
should create only one buffer pool for each page size. If you want to create
table spaces using a page size other than the default 4 KB, then you will need
a buffer pool which uses the same page size.
Set the registry variables DB2_MMAP_READ and DB2_MMAP_WRITE to OFF on AIX with
SMS or DMS table space file containers. When you set these parameters off,
the database manager:
• Frees up extra 256 MB segments
• Enables the use of the AIX JFS file system cache
Set the registry variable DB2_FORCE_FCM_BP=NO, which is the default for this
variable. When it is set to YES, the Fast Communication Manager (FCM)
buffers are allocated from the same shared memory segment. This gives
optimal FCM performance when you use the Enterprise-Extended Edition of
DB2 UDB and have multiple database partitions on one physical node.
However, the Enterprise Edition of DB2 UDB will be working with only one
database partition. By setting the variable to NO, we free another shared
memory segment which can then be used for buffer pools.
For customers using AIX 4.3.2 and later, the above points may not be as
relevant. This is due to enhancements in shared memory segment size.
Using AIX at this level and above will allow shared memory segments up to
2 GB in size.
Note
To eliminate database initialization overhead, which could, for example, be
caused by activating large buffer pools, use the ACTIVATE DATABASE <dbname>
command. This works well in a dynamic environment (such as a Web
server) where all applications may frequently disconnect from the
database.
system memory
read page
JFS Cache read page
DB2 process -
shared memory DB2 UDB
write page
write page
file pages
SMS or DMS File Container
DB2 performs a read. If the required file page is not in JFS
cache, it is read from disk. File page is then copied from JFS
cache to DB2's process buffer. Writes are copied from
DB2 shared memory to JFS cache, then written to disk at a
later stage.
DB2_MMAP_READ=OFF
DB2_MMAP_WRITE=OFF required file page
not in JFS cache
The main advantage for DB2 is that this "late writing", which is known as
write-behind , allows the database to continue processing without having to
wait for an I/O request to complete.
system memory
page
DB2 UDB
db2 shared memory read
(segment 14)
page
write
DB2_MMAP_READ=ON
DB2_MMAP_WRITE=ON file data
In Figure 19 we show the default behavior, which is to have both variables set
to ON. Here we are utilizing mmap (memory mapped) I/O which allows files to
be mapped directly to one of DB2’s memory segments. When using mmap we
bypass the filesystem and the usual operating system kernel buffers.
Although this sounds like a major disadvantage, you must remember that if
your database has been designed with performance in mind, the majority of
table spaces should use DMS device containers. This means that the
database manager is responsible for these operations and not the operating
system. The performance impact in this case will be minimal.
With the introduction of DB2 UDB v7.1, total log files can now be up to 32 GB
in size, and you can perform extremely large amounts of work within a single
transaction. With customers now using log spaces which are gigabytes in
size instead of megabytes, the physical layout of the log files becomes very
important. Placement of these files needs to be optimize, not only for write
performance, but also for read performance, because the database manager
will need to read the log files during database recovery.
Note
Prior to Version 7.1, the total log files must be up to 4 GB.
Advantages:
• The I/O path is shorter, since you are now bypassing the operating
system’s filesystem.
• Raw device striping may provide faster I/O throughput.
• No restrictions are imposed by a filesystem.
• A raw device can span multiple disks.
Disadvantages:
• The device (logical volume) created for the logs must be dedicated to
DB2.
• The device (logical volume) created for the logs cannot be operated upon
by any operating system utility or third-party tools which would back up or
copy from the device.
• Currently, if using DPropR, the read log API will not call the user exit if you
use the raw log device. The recommendation is that DPropR should not be
used when using raw log devices. Similarly, do not use raw log devices if
you use the sqlurlog API.
3.5.3 Mirroring
Always mirror your log devices; the log files are crucial to your database and
you need to ensure that the disks they reside on are mirrored. It is
recommended that the log disks be entirely dedicated to DB2 and that no
other processes write to these disks. If possible, place the disks on separate
disk controllers to maximize availability.
If, for example, you have an OLTP type workload, then you would not obtain
good performance from log files that are too small, as you would fill them very
quickly. In this case, if a user exit were enabled, this would mean more work
for the database manager.
Most DSS workloads with little update, insert, or delete activity may benefit
from a smaller number of log files. However, in this environment, where
logging activity is low, it may be worthwhile using a larger log file size to
reduce administration overhead.
In this formula, LOGFILSIZ represents the Log File Size database configuration
parameter.
If you are using raw devices for logging, then remember that log records are
still grouped into log extents; the size of each is LOGFILSIZ (4 KB pages). DB2
places the log extents consecutively in the log device, and every log extent
carries with it a 2-page overhead for extent header information. This affects
the number of log extents which can be written to your raw log device. The
total number can be calculated by the formula:
raw-device-size / (logfilsz + 2)
The device must be large enough to support the active log space that you are
going to allocate. By this we mean that the number of log extents which can
be contained on your raw device must be greater than (or equal to) the value
of LOGPRIMARY.
For more details on this, please refer to the DB2 UDB Administration Guide:
Implementation, SC09-2946.
So if another UOW ’B’ tried to start at this point, and required MB of log space
it will receive SQL0964. The reason here is that the first UOW ‘A’ has not
completed. Once the UOW ‘A’, which commenced before the log truncation
took place, has completed, space reclamation will begin.
Note
SQL0964 ’Log Full’ is a logical error which indicates that active log space is
full. This is different from the physical log file being full.
When an on-line backup is restored, the logs must be rolled forward at least
to the point in time at which the backup was completed.
The log file used at backup time may continue to be open long past the time
of the backup completion.
So far, we have discussed the physical layout of the disk storage, the table
space design, and the layout of buffer pools in the previous chapter. The next
major consideration, in order to obtain acceptable response times, is the
design of tables and indexes. When you design tables, you must choose an
appropriate data model and data types for them. With respect to indexes, you
need to be aware of the advantages and disadvantages of creating indexes,
and create appropriate ones.
In this chapter, we will explain how each of these options affects database
performance, and provide helpful information that a database administrator
can use to design new tables and indexes or improve existing tables and
indexes.
4.1.1.1 Normalizing
Normalization reduces redundancy from your data and can improve the
performance of update and delete statements, since you only have to do it in
one place. By normalizing your data, you try to ensure that all columns in the
table depend on the primary key.
There are four “forms” of normalization (first, second, third, and fourth). We
will show an example of the third and fourth forms; however, examples of all
four forms can be found in the DB2 UDB Administration Guide: Planning,
SC09-2946.
In Table 3 we can see that the DeptName column is dependent on the DeptNo
column, so this table does not conform to the third normal form. If we update
DeptName for one employee, this would not update the DeptName column for
other employees belonging to the same department.
Table 3. Table not in third normal form
In this basic example using normalization to conform to the third normal form,
would produce two tables (Table 4 and Table 5). Now updating the DeptName
column is easy, as we just update column in Table 5.
Table 4. Table in third normal form (1)
001 Brown 01
002 Smith 02
01 Support
02 Sales
001 C++
001 Java
Note
It is our recommendation to start with tables in the fourth normal form, then
measure the performance. If performance is unacceptable, structure the
table in the third normal form, then reassess performance.
Note
In DSS environments where the data is never updated once it is loaded,
denormalizing can be a good choice, since it speeds up queries.
For more information on data types, please refer to the DB2 UDB
Administration Guide: Implementation, SC09-2944, and the SQL Reference,
SC09-2974.
Note
As of DB2 UDB V7.1, the data types LONG VARCHAR and LONG
VARGRAPHIC (not discussed here) will be marked as deprecated. This
data type will be supported, but enhancements may not be implemented for
this data type. If you are defining items such as structured types, do not
define them using LONG VARCHAR or LONG VARGRAPHIC types. Use
the CLOB or DBCLOB data type instead.
In the example shown the column col1 will not accept null values, and a
known value must be entered. You can also specify a default value to be
inserted by combining the WITH DEFAULT option and NOT NULL options of CREATE
TABLE. When this is done, if a row is inserted and a value is missed for the
column using the NOT NULL WITH DEFAULT definition, then the value used for the
WITH DEFAULT clause will be inserted, as we have specified that null values will
not be accepted.
In general, columns defined as NOT NULL perform better than nullable columns.
The reason for the performance gain is the path length reduction; the
database engine does not have to check for null values in a NOT NULL column.
It is worth mentioning that there are space savings as well when using NOT
NULL. Every nullable column requires one extra byte per column value. By
defining columns as NOT NULL, there will be space savings which may lead to a
reduced number of used tables, index pages, and index levels, which can
improve query performance.
Identity columns are ideally suited to the task of generating unique primary
key values. Applications can use identity columns to avoid the concurrency
and performance problems that can result when an application generates its
own unique counter outside the database. For example, one common
application-level implementation is to maintain a 1-row table containing the
counter, and having each transaction lock this table, increment the number,
and then commit (unlock); that is, only one transaction at a time can
increment the counter. In contrast, if the counter is maintained via an identity
column, then much higher levels of concurrency are achievable because the
counter is maintained by DB2 and is not locked by transactions, and thus one
uncommitted transaction that has incremented the counter will not prevent
other subsequent transactions from also incrementing the counter.
The sequential numbers that are generated by the identity column have the
following additional properties:
• The values can be of any exact numeric data type with a scale of zero.
( SMALLINT, INTEGER, BIGINT, or DECIMAL with a scale of zero). By contrast,
single and double precision floating point are considered approximate
numeric data types and are not allowed as identity columns.
• Consecutive values can differ by any specified integer increment. The
default increment is 1.
• The counter value for the identity column is recoverable. If DB2 should fail,
the counter value is reconstructed from the logs, thereby guaranteeing
that unique values continue to be generated across a DB2 failure.
• Identity column values can be cached to give better performance.
Each table may have a single column that is defined with the IDENTITY
attribute. Some examples of using an identity column would be an order
number, employee number, stock number, or incident number. The values for
an identity column can be generated by DB2 using the clauses ALWAYS or BY
DEFAULT. Following is an example of this; see DB2 UDB SQL Reference,
SC09-2974 for more details:
•CREATE TABLE TAB1 (col1 INT, col2 INT, coluniq INT GENERATED ALWAYS AS
IDENTITY (START WITH 0, INCREMENT BY 1))
Note
At the time of writing, Identity Columns are not supported in an EEE
database with more than one partition. Please check the Release Notes for
availability of this feature for EEE databases.
The following example shows an example which creates a table with two
regular columns COL1 and COL2 and a generated column COL3 which is derived
from the two regular columns.
CREATE TABLE TABLE1
(COL1 INT, COL2 INT, COL3 INT
GENERATED ALWAYS AS (COL1 - COL2))
Suppose that you now populate the table and wish to use the ALTER TABLE
statement to add a fourth column which is also a generated column. You must
first alter the table’s state by turning integrity checking OFF.
SET INTEGRITY FOR TABLE1 OFF
This needs to be done for TABLE1, as the table includes generated columns
which generate values based on other columns in the table. We can now add
another generated column to this table.
ALTER TABLE TABLE1
ADD COLUMN COL4 INT GENERATED ALWAYS AS
(CASE WHEN COL1 > COL2 THEN COL3 ELSE NULL END)
Now the new column has been added, we need to turn integrity checking
back ON.
SET INTEGRITY FOR TABLE1 IMMEDIATE CHECKED FORCE GENERATED
For more detailed information on the SET INTEGRITY command, see the DB2
UDB SQL Reference, SC09-2974.
Now let us assume that values were inserted in to the NAME column using both
uppercase and lowercase letter, so that when we ran the statement SELECT *
FROM TAB1, we saw the output as follows:
NAME
-------------------
JON smith
mark JONES
SARAH THOMPSON
Simon Woods
4 record(s) selected.
As you can see above, the values in the NAME column contain both uppercase
and lowercase lettering. Although this scenario might be unlikely in most
business applications, let us assume that you now want to perform another
select on the table but want the search to be case insensitive. In this case,
your application would run a statement such as SELECT * FROM TAB1 WHERE
LCASE(NAME)=’mark jones’. This query has a predicate with a specific value,
but the database manager cannot determine the start/stop index key value to
scan on the index. This is because each of all rows needs to be translated
into lower case by LCASE function, and then evaluated as to whether it is ’mark
jones’. This is not a problem if the TAB1 table is small; however, if it contains
thousands of rows, this processing cost would be considerably greater.
NAME NAMECASE
------------------- --------------------
JON smith jon smith
mark JONES mark jones
SARAH THOMPSON sarah thompson
Simon Woods simon woods
4 record(s) selected.
Now you can re-write the query SELECT * FROM TAB1 WHERE LCASE(NAME)=’mark
jones’ to SELECT * FROM TAB1 WHERE NAMECASE=’mark jones’ so that the index
IND1 on the NAMECASE column can be used.
This example is used to simply demonstrate one of the ways in which using a
generated column can improve the performance of your applications or
queries. Although the generated column formula used was simple, this
example may provide ideas for how this column type could be used in your
environment.
The LOB data types summarized above can be used to store data objects as
strings up to 2 GB in size. A single table row can contain up to 24 GB of LOB
data, and the table itself may hold a total of 4 TB of LOB data.
From a performance point of view, if you anticipate that you will be storing a
large amount of LOB data in your tables, then you may want to ensure that
you use DMS table spaces to hold these tables (SMS can also be used). The
advantage of using DMS is that you are able to specify an alternative table
space, using the LONG IN clause of CREATE TABLE. If using DMS, then use file
container types to hold your LOB data. Remember that LOB data is NOT
stored in the buffer pool, so by using the DMS file containers (or SMS table
space) you will benefit from the operating systems file system cache.
Note
You can only specify an alternative table space to hold when the table is
first created
Note
To create strings greater than 1 GB using the BLOB, CLOB, or DBCLOB
data types, you must use the NOT LOGGED option in your column definitions.
If you choose the NOT COMPACT option, then when you insert LOB data, some
free space is also inserted to assist in any future appends to this LOB data.
The NOT COMPACT option is the default option, and as most data defined as LOB
will be large in size, we would recommend using this default to take
advantage of the append performance improvement.
Expected activity is basically trying to understand how your table will be used,
if it will be heavily accessed and updated, if it will be read mostly, or if it will be
a table for historical/reference data that may be accessed only at certain
times of the year.
Try to categorize your tables and group them into table spaces accordingly.
For example, small infrequently accessed tables could be grouped together in
a single table space with a small buffer pool (or you could let them use the
default buffer pool). Larger tables which you expect to be heavily accessed
may be better in their own dedicated table space with its own buffer pool.
However, we are not recommending grouping all large tables in one table
space, as this would in most cases degrade performance. One example
When you insert data, a default INSERT search algorithm is used by DB2 to
perform the inserts. The algorithm uses Free Space Control Records
(FSCRs) to find pages with enough space. Even if the FSCR finds a page
which has enough free space, the space may not be usable if it is "reserved"
by an uncommitted DELETE from another transaction. This is one of the main
reasons we recommend that applications COMMIT frequently to free this space.
Not all of the FSCRs in the table are searched when an insert is performed.
The DB2MAXFSCRSEARCH=N registry variable limits the number of FSCRs visited
for an insert (default=5).
Note
You need to modify the value of DB2MAXFSCRSEARCH to balance insert speed
with space reuse. Large values optimize for space reuse. Small values
optimize for insert speed. Setting the value to -1 forces the database
manager to search all free space control records.
After searching five FSCRs, if we have not found space, the INSERT is
simply appended to the end of the table. Once this happens, subsequent
inserts also append to the table until two extents are filled, then the search
process repeats. Each search then starts at the FSCR where the last search
ended.
Once the entire table has been searched, we append without searching until
space is created elsewhere in the table, via a DELETE, for example.
To ensure that you have free space on the data pages in your tables, use
ALTER TABLE PCTFREE <value> before a LOAD or REORG operation. This will ensure
that the percentage value specified for PCTFREE will be left on each page
Other search algorithm options are APPEND MODE and clustered indexes, which
are discussed in 4.1.3.3, “Why use append mode?” on page 98 and 4.2.4,
“Clustering indexes” on page 109.
Another consideration for having free space is overflow records. These are
created by updates that enlarge existing rows such that the row no longer fits
on its page; the record is then inserted on another page (with enough free
space). This is an overflow record. The original RID (Record Identifier) is then
converted to a pointer record, which contains the overflow record's RID.
However, indexes keep the original RID, which means that for overflow
records, an extra page read is required to access data — this degrades
performance.
Where insert performance is a key criteria, then define your table with APPEND
MODE set to ON. New rows will be inserted at the end of the last extent, and no
searching for available space will be performed; neither will updates to FSCR
records.
There is one important consideration when using APPEND MODE set to ON.
Although inserts will be faster, more space will be needed (in most cases)
compared to using APPEND MODE set to OFF or by using a clustered index to try
to insert records on the same page as other records with the same index key
value.
If you leave enough free space in each table space to REORG the largest
table, then you will be able to perform the reorg "in-place" (in the same table
space). A performance benefit will be gained, because DB2 will not have to
copy the data to the temporary reorg files in the other table space and then
copy them back again to the base table. Remember, though, that the
temporary tables will still be larger than the base table, even if created in the
same table space.
In summary, for optimal performance, do the reorg "in-place" if you can spare
enough free space in the target table space.
Because the “not-logged” state is only active in the unit of work that was
generated by the CREATE TABLE or ALTER TABLE statement, only the application
that issued the CREATE TABLE or ALTER TABLE statement can access and change
the table without logging. During this unit of work, a Z table lock is held on the
table.
Note that the NOT LOGGED INITIALLY option does not imply better performance.
Although you can reduce logging overhead using this option, the data pages
changed must be flushed to disk at the commit time because changes are not
logged, and the commit can take a long time. If the buffer pool assigned to the
table space to which the table belongs is small, most of the changed pages
would have to be written to disk, and using the NOT LOGGED INITIALLY option
may improve performance. However, if the buffer pool is large enough for the
changed page not to be written to disk, using the NOT LOGGED INITIALLY option
may decrease performance. The NOT LOGGED INITIALLY option is intended to
overcome log space limitations. You may want to activate NOT LOGGED
INITIALLY if you want to perform large changes where normal logging would
give the log-full condition (SQL0964).
With DB2 UDB V7.1 we introduce a new type of temporary table known as a
declared temporary table. A declared temporary table is a temporary table
which is available externally to the users via SQL. However, from the
application perspective, only the application that creates the table may
access the table, and the table will exist as long as the application is
connected to the database.
These types of tables are very useful when you are running a complex SQL
query which needs to process large amounts of data. By creating
intermediate tables that are used to process the data and are then made
available for the duration of the applications connection, you reduce the need
to rebuild these intermediate tables; this results in a performance
improvement.
You can create a temporary table using the DECLARE GLOBAL TEMPORARY TABLE
statement. At this point the table will exist, but will contain no rows. This kind
of temporary table is called a declared temporary table.
Note
Before defining a declared temporary table space, you must create a user
temporary table space in advance using CREATE USER TEMPORARY TABLESPACE
statement. This is a new table space type introduced with DB2 UDB V7.1 to
allow greater control over the physical placement of this type of table.
COMMIT;
CONNECT RESET;
CONNECT TO sample;
First, a subset of the employee table is retrieved and inserted into the
declared temporary table DTT1. Notice that the schema name of the declared
temporary table is SESSION and the inserted rows are not logged. Then two
SELECT statements are performed for DTT1 before and after a COMMIT statement.
Both of them get the same result. The third SELECT statement after
reconnecting to the sample database would get an error (SQL0204), as the
declared temporary table DTT1 is dropped when the first connection was
terminated.
Summary tables are mostly a lot smaller than the base fact tables from which
they were created. The REFRESH option specified when the summary table is
created determines when data in the table is updated. For more information
on the options available, refer to the DB2 UDB SQL Reference, SC09-2974.
The optimizer will access a summary table if it determines that the results for
the query can be satisfied by accessing data in the summary table instead of
accessing the base fact tables.
There are a number of extensions in Version 7.1 to help in the use and
management of summary tables. In Version 7.1 a user can now:
• Use the refresh immediate option for a replicated table:
Starting with DB2 UDB V7.1, replicated summary tables can now be
created using the REFRESH IMMEDIATE option.
• Convert between a regular table (type 'T') and a summary table (type 'S'):
This can be done using the SET SUMMARY AS clause of the ALTER TABLE
statement. See the DB2 UDB SQL Reference, SC09-2974 for more detail.
• Refresh multiple tables concurrently:
You can specify multiple summary tables in a REFRESH TABLE statement
and the updates will take place concurrently.
4.1.4.1 LOCKSIZE
LOCKSIZE is a table parameter that can be changed using the ALTER TABLE
statement. In DB2, tables use row locking by default; by using the LOCKSIZE
parameter you can override this. The options available allow you to set
default locking to be either row or table. The example below shows how to set
table level locking as the default.
ALTER TABLE db2inst1.table1 LOCKSIZE TABLE
In terms of applications, the previous ALTER TABLE statement would mean that
a share or exclusive lock would be acquired on the table; intent locks (except
intent none) are not used. By using this value you may improve the
performance of queries simply by limiting the number of locks that need to be
acquired. Do not forget, though, that the trade-off is concurrency; this could
be reduced, since all locks will be held over the whole table.
Use of this option in the table definition will not prevent normal lock escalation
from occurring.
It is worth considering which tables in your database are the most important
— for example, those whose data is critical. For those tables, it might be
worth utilizing the dropped table recovery feature. This allows you to recover
a table by performing only a table space level restore and then rolling forward
through the logs. An obvious advantage here is speed and availability,
because the database is still accessible to users.
This functionality is enabled at the table space level and applies to regular
table spaces only. To find out which table spaces have this feature enabled,
you can run the following command when connected to your database:
SELECT TBSPACE,DROP_RECOVERY FROM SYSCAT.TABLESPACES
For more information on this, please refer to the DB2 UDB Administration
Guide: Implementation, SC09-2944.
Once you have created your tables, it is worth extracting a copy of the DDL
for the tables in your database. This is good for reference and to help
recreate the table structure; for example, accidentally dropping a table when
you have no database backup. The DDL can be extracted using the db2look
command:
db2look -d <databasename> -a -e -o <outputfile> -m
See the DB2 UDB Command Reference, SC09-2951 for details on db2look
options.
Indexes can reduce access time significantly; however, indexes can also
have adverse effects on performance. Before creating indexes, consider the
effects of multiple indexes on disk space and processing time:
• Each index takes up a certain amount of storage or disk space. The exact
amount is dependent on the size of the table and the size and number of
columns included in the index.
• Each INSERT or DELETE operation performed on a table requires
additional updating of each index on that table. This is also true for each
UPDATE operation that changes an index key.
When you create indexes, there are a number of options available to you,
which affect its performance. Here we will look at those which affect layout.
However, before you do this, you should see the other recommendations on
when to separate data and indexes provided in 3.3.9.4, “Considerations for
separating data and indexes” on page 70.
In the following cases, you should choose a smaller value for PCTFREE, which
will save space and reduce index I/Os:
• The index is never updated.
• The index entries are in ascending order and mostly high-key values are
inserted into the index.
• The index entries are in descending order and mostly low-key values are
inserted into the index.
If you have indexes which get updated frequently, then a larger value would
be recommended to avoid index page splits.
Note
Specifying a large value will also help ensure that there is enough free space
to maintain a clustered index if you have defined the index as such. With
clustering indexes DB2 attempts to keep the data in the same order as the
order specified by the index.
If a value of PCTFREE 25 was used, for example, then 25% of each index leaf
page would be kept as free space during initial index build or rebuild (as a
result of a load or reorg). PCTFREE can therefore help reduce the frequency of
index page splits, which will reduce performance. Usage of PCTFREE can also
reduce the need to reorganize the index.
Note
An index can be reorganized by dropping it and recreating it, or by using
the REORG utility. The REORG utility is costly, but does ensure that index
pages are clustered, which benefits index scans.
The MINPCTUSED value should be set to less than one hundred (100). This
value becomes the reorganization threshold. We recommended a value for
MINPCTUSED which is less than 50 percent, since goal is to merge two
neighboring index leaf pages.
Index leaf pages freed following an on-line index reorg are available for
re-use. The restriction is that freed pages are only available to other indexes
in the same table.
Index non-leaf pages will not be freed following on-line index reorg. Full table
reorg will make the index as small as possible. Leaf and non-leaf pages will
be reduced in number, as will index levels.
If MINPCTUSED has a value of zero, on-line reorg of that index will not be
performed. Existing indexes with a zero value that require this feature will
have to be dropped and recreated to enable it. The value of MINPCTUSED can be
obtained from the SYSCAT.INDEXES system catalog table using the following
statement:
SELECT INDNAME,MINPCTUSED FROM SYSCAT.INDEXES
The only restrictions are that the columns selected must be distinct from
those columns used to enforce uniqueness, and the total select cannot be
more than 16 columns (the sum of which cannot be greater than 255 bytes).
We can use a clustered index to try to optimize queries that retrieve multiple
records in index order. The result of clustering should be that fewer physical
I/Os are performed. When a clustered index is defined after a table exists,
then use ALTER TABLE PCTFREE <value> before performing any new LOAD or REORG
operations. By doing this, you will ensure that the percentage value specified
for PCTFREE will be left on each page during the LOAD or REORG. See the ALTER
TABLE statement in the DB2 UDB SQL Reference, SC09-2974 for more
information. By allocating this extra free space, we increase the probability
that the cluster insert algorithm can find free space on the desired page.
If you perform updates that considerably enlarge records, then we may get
pointer overflow records which degrade performance, as we then have rows
which no longer fit in their original data pages.
Note
A clustered index may not be defined for a table which is set to use
APPEND MODE. See the 4.1, “Tables and performance” on page 85 for
more information on APPEND MODE.
Control Center
To start the Index Advisor Wizard from the Control Center, you must first
highlight the Indexes folder for your database and then right-click to see the
Create menu as in Figure 20 below.
In Figure 20, notice that by selecting the Indexes folder and right-clicking, we
can see the option, Create. From here, we choose the Index Using Wizard
option.
The next screen shown in Figure 22 allows the user to set a specific value for
the maximum disk space you wish to allocate for any new indexes. It is
recommended that a value be specified if disk space is scarce.
If you decide to set a disk space limit, be aware that the indexes
recommended may not be the most optimal for your workload, as the Index
Advisor Wizard may discard some indexes because they would exceed the
available disk space limit. If you want to see what could be created
regardless of disk space, do not set a limit.
If your workload consists of many complex queries, then it may take some
time to calculate the recommended indexes. The screen shown in Figure 23
can be used to determine not only when the calculations will be performed,
but also the maximum amount of time they are allowed to run for.
By using a scheduled time, you can allow the index advisor to run at a time
when database resources are not being fully utilized (such as at night or on a
weekend). You can also limit the length of time the wizard can run, thereby
limiting execution time to a set window.
If you do specify a time limit in which the wizard can run, then the index
recommendations made may not be the most optimal, as the wizard may not
have been allowed the time required to calculate the best indexes for your
workload.
However, if the results are returned before the time limit, then assume that
these are the most optimal recommendations that the wizard was able to
make.
Once the Index Advisor Wizard has completed, you will see a screen similar
to that shown in Figure 24. We can see here that the wizard has
recommended that two indexes could be created to help minimize the overall
cost of this workload on the databases resources. For each index, we can
see the table the index was created against, what columns were used to
create the index, and what the disk space requirements to hold the index will
be. We can also change the index name from this screen.
In Figure 25, we can see which indexes the wizard flagged as being unused
during the execution of the workload. Do not remove indexes unless you are
sure that they are not required by other applications or workloads.
Note
Before running the Index Advisor Wizard or the db2advis utility against a
database, ensure that the Explain tables have been created for that
database. Run db2 -tf EXPLAIN.DDL against the database to create these
tables. EXPLAIN.DDL is found in the sqllib/misc directory in the instance
owner’s home directory
AIX and Solaris are the systems for which 64-bit DB2 UDB support is initially
targeted. For other operating systems, 64-bit support will follow.
Understanding your database and applications helps you tune your database
and improve its performance. To do this, you may need to monitor your
database system to gather performance and statistical information about the
operations and tasks that are executing.
This chapter describes how to monitor the system resource usage using AIX
commands such as iostat and vmstat. It also discusses the different methods
available to monitor the database activity, using tools such as the Snapshot
Monitor, the Event Monitor, the Performance Monitor, and the
CLI/ODBC/JDBC Trace Tool. Based on the information provided by these
commands and tools, you can make informed decisions about what actions
need to be taken to tune the database environment.
We have developed some sample shell scripts that execute these commands
and tools, and extract the useful information from the output. These scripts
are shown in Appendix A, “Sample scripts” on page 335. You can use them
as we show in this chapter, or modify them appropriately for your
environment.
When measuring and monitoring, each step of the test should be carefully
considered. The method you are going to use to measure must be clearly
established. You should be aware that the measuring and monitoring activity
may have some affect on the results obtained. Previous steps of the test, or
The directory structure which our sample scripts will use is shown in Table 9.
Table 9. Suggested directory structure for maintaining point-in-time results
Another standard which we have tried to maintain is that all of the scripts will
force you to enter a comment which is placed in the beginning of the
summary output (report) file; for example, "RUN BEFORE INDEX
CREATION" or "FIRST EXECUTION AFTER DB2START". The run date and
script parameters (invocation) are also put in the beginning of the summary
output file.
The following sections show each directory in the directory structure which
our sample shell scripts will use. You do not have to use our sample scripts or
exactly the same directories to save monitored data. However, we
recommend that you keep any performance monitoring results for tracking
the system performance and also for future performance references.
8 record(s) selected.
See the Command Reference , SC09-2951 for more details about db2look.
The parameters which offer the most complete information are:
db2look -d dbname -m -l -a -x -e -f
Sample script
We have written the sample shell script, db2look.ksh. This script can be used
to execute db2look with default parameters and place the output in a states
subdirectory. It also places a comment at the beginning of the script which is
generated. The following example shows a sample invocation:
The source file and the complete syntax of this sample script are included in
Appendix A, “Sample scripts” on page 335.
CONNECT TO TPC;
------------------------------------
-- DDL Statements for BUFFERPOOLS --
------------------------------------
CREATE BUFFERPOOL "TPCDDATABP" SIZE 5000 PAGESIZE 8192 NOT EXTENDED STORAGE;
CREATE BUFFERPOOL "TPCDTEMPBP" SIZE 10000 PAGESIZE 8192 NOT EXTENDED STORAGE;
CREATE BUFFERPOOL "TPCDINDEXBP" SIZE 5000 PAGESIZE 8192 NOT EXTENDED STORAGE;
For example, the sqlcache.ksh utility saves the output of a Snapshot Monitor,
and a summary of it as specified by parameters, in a subdirectory under
~/results. (Optionally, it could save it in the current directory.)
For example, once a process has completed spiking its CPU usage (and
thereby coming to the top of the list), it might quickly drop down the list of
processes, leaving you wondering what exactly it was that you saw. On the
other hand, indicators such as CPU and Disk do have a peak marker which
clearly shows the highest values which were hit during monitoring. It is also a
very simple tool that can be used to display the parallel activity of multiple
CPUs. However, one disadvantage is that the process list only shows the
names of the parent processes.
During the remainder of this chapter, we will not discuss using nmon. Instead,
we will concentrate on non-graphical monitoring tools whose output can be
saved and summarized into files and placed in the results directory.
# vmstat 2 10
kthr memory page faults cpu
----- ----------- ------------------------ ------------ -----------
r b avm fre re pi po fr sr cy in sy cs us sy id wa
0 0 44720 192928 0 0 0 0 0 0 103 66 11 0 0 99 0
1 1 44720 192928 0 0 0 0 0 0 785 1133 1115 34 3 39 24
0 1 44720 192928 0 0 0 0 0 0 770 1156 1085 33 2 40 26
0 1 44720 192928 0 0 0 0 0 0 762 1054 1040 32 2 38 28
0 1 44720 192928 0 0 0 0 0 0 773 1057 1078 33 2 41 24
0 1 44720 192928 0 0 0 0 0 0 757 1068 1042 33 2 40 25
1 1 44720 192928 0 0 0 0 0 0 773 1072 1053 34 2 39 26
1 1 44720 192928 0 0 0 0 0 0 777 1063 1065 33 1 39 26
2 1 44720 192928 0 0 0 0 0 0 755 1050 1034 32 2 43 24
4 1 44720 192928 0 0 0 0 0 0 760 1090 1056 34 2 41 23
The source file and the complete syntax of this sample script are included in
Appendix A, “Sample scripts” on page 335.
# lsps -a
Page Space Physical Volume Volume Group Size %Used Active Auto Type
hd6 hdisk0 rootvg 1024MB 1 yes yes lv
Another way to see this information is to use the nmon utility (see 5.3.1,
“Online monitor — nmon” on page 128).
The following are some guidelines to determine which tool you should use:
• Choose the Snapshot Monitor or Event Monitor if you want to gather data
about DB2’s operation, performance, and the applications using it. This
data is maintained as DB2 runs and can provide important performance
and troubleshooting information.
• Choose the Explain Facility if you want to analyze the access plan for an
SQL statement or a group of SQL statements.
• Choose the db2batch tool if you want to measure and analyze the
performance of a set of SQL statements. Performance times can be
returned along with Snapshot data for analysis. Explain information can be
gathered for use by the Explain Facility.
• Choose the CLI/ODBC/JDBC Trace Facility to track activity between a CLI
client and DB2. This facility can help pinpoint long running statements and
analyze the time spent in the client application, DB2, or the network.
Note
MON_HEAP_SZ indicates the amount of memory (in 4K pages) which is
allocated for database monitor data (at db2start). The amount of memory
needed will depend on the number of snapshot switches which are turned
on and active Event Monitors. If the memory heap is insufficient, an error
will be returned when trying to activate a monitor and it will be logged to the
db2diag.log file.
While there is always some basic information which is collected for each of
these levels by default, it is possible to turn on the collection of a broader
range of data for each level by turning on a Snapshot Monitor switch. The
switches are defined by the groups listed in Table 10 . The switches can be
set at the instance level using the UPDATE DBM CFG command or the application
level using UPDATE MONITOR SWITCHES. Snapshot Monitor switches and the
monitoring levels are combined to provide different monitoring information
when taking a snapshot. The two are very closely related. If the proper
monitor switch is not turned on, the snapshot level used may not return any
data.
Note
If you turn on the monitor switch UOW, only the next UOW will be
monitored.
Figure 29 shows that once the monitor switch was turned on in Application A,
the “get Snapshot Monitor” command can report data collected from the
activity performed in Application B. Even if the switch is turned on from
Application B later, it will be too late to display the activity which has already
passed. It is, however, possible for Application B to display data from
subsequent activity. So it is clear that different shell/sessions (instance
connections) maintain their own set of snapshot data, allowing each to
display different information based on active switches, when they were turned
on, and whether snapshot data was reset.
In order to make the snapshot information available and consistent for all
instance connections, the default monitor switches should be turned on from
the Database Configuration parameters. For example:
UPDATE DBM CFG USING DFT_MON_STMT ON
Note
When you change the value of the database manager configuration
parameters, you usually need to stop and start the instance to make those
changes effective; however, the changes of the default monitor switches
will be effective immediately. Therefore, you do not need to stop and start
the instance.
The following example shows the switch states. The timestamps correspond
to the last time the switches were reset or turned on.
The GET MONITOR SWITCHES command outputs the status of the monitor
switches for the current session. If you issue GET MONITOR SWITCHES from the
other session, the output may be different because each application using the
database system monitor interface has its own set of monitor switches. If you
want to see database manager-level switches status, execute the following
command:
GET DBM MONITOR SWITCHES
You can see that the buffer pool monitor switch is on in this sample output.
This means that there is another session which turned the buffer pool monitor
switch on.
Note
If you want to make sure that snapshot data (as well as the statement
cache) remains populated even after the last connection is closed, then be
sure to execute ACTIVATE DATABASE to keep the database activated. In this
case, even if there are no connections, the monitored and cached data is
preserved.
Resetting the monitor switches effectively starts all of the counters at zero,
and further snapshots are based on the new counter values.
To reset the monitor switches for all databases within an instance, the RESET
MONITOR ALL command should be used.
Note
Every application has its own copy of the Snapshot Monitor values.
Resetting the monitor switches only affects the counters of the application
that issues the reset.
Number of executions = 1
Number of compilations = 1
Worst preparation time (ms) = 13
Best preparation time (ms) = 13
Rows deleted = 0
Rows inserted = 0
Rows read = 17
Rows updated = 0
Rows written = 0
Statement sorts = 0
Total execution time (sec.ms) = 0.020399
Total user cpu time (sec.ms) = 0.010000
Total system cpu time (sec.ms) = 0.010000
Statement text = SELECT NAME, CREATOR, TYPE, CTIME FROM
SYSIBM.SYSTABLES WHERE CREATOR = USER ORDER BY CREATOR, NAME
As you can see in this example, you can use this information to know
currently cached dynamic SQL statements and their statistics.
You can also get data related to the acquired locks using the application level
or database level snapshot using the command below. Partial output follows:
Application handle = 36
Application ID = *LOCAL.db2inst1.000630235242
Sequence number = 0001
Application name = db2bp
Authorization ID = DB2INST1
Application status = UOW Waiting
Status change time = Not Collected
Application code page = 819
Locks held = 5
Total wait time (ms) = Not Collected
List Of Locks
Lock Object Name = 65795
Node number lock is held at = 0
Object Type = Row
Tablespace Name = TPCDDATA
Table Schema = DB2INST1
Table Name = REGION
Mode = X
Status = Granted
Lock Escalation = NO
.............
By analyzing the output, you can see which application holds which type of
locks on which database objects.
See the manual System Monitor Guide and Reference, SC09-2956 for a
detailed explanation of each output element. For the complete syntax of the
GET SNAPSHOT command, see the SQL Reference, SC09-2951.
The sample invocation shown below extracts all SQL statements from the
dynamic SQL cache of the TPC database. The specified comment is added to
the output which is saved into /home/tetsur3/work/results/26 directory. The
original output of the dynamic SQL snapshot is also saved into the same
directory. The -s option is used to specify the string length of the reported
SQL statements.
[Creating: /home/tetsur3/results/26/sqlcache_TPC.out]
SQL-Text
--------------------------------------------------------------------------------
SELECT NAME, CREATOR, TYPE, CTIME FROM SYSIBM.SYSTABLES WHERE CREATOR = USER ORD
select s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comme
select l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedpri
select count(*) from customer
SELECT colcount FROM SYSIBM.SYSTABLES WHERE creator = ’SYSIBM’ AND name= ’SYSTAB
[Creating: /home/tetsur3/results/26/sqlcache_TPC.out]
[Creating: /home/tetsur3/results/26/sqlcache_TPC.out]
The source file and the complete syntax of this sample script are included in
Appendix A, “Sample scripts” on page 335.
[Creating: /home/tetsur3/results/26/locks_TPC.out]
The COUNT column indicates the number of locks held for the table object with
the same Type, Escalation (YES or NO), Mode and Status.
Note
The "table" with the name "=.=" indicates an internal temporary table. See
the Administration Guide: Implementation,SC09-2944 for further details on
TYPE and MODE of locks.
Event Monitors are created using SQL DDL (Data Definition Language) like
other database objects. Event Monitors can be turned on or off much like the
Snapshot Monitor switches.
Note
SYSADM or DBADM authority is required to create an Event Monitor.
The event records written out by this command are noted in the Event
Monitor log with a partial record identifier. You should be aware that flushing
out the Event Monitor will not cause the Event Monitor values to be reset.
This means that the Event Monitor record that would have been generated if
no flush was performed will still be generated when the normal monitored
event is triggered.
Note
Event Monitors can be created using either using SQL or the db2emcrt GUI
tool.
Note
If you’re interested in only filtering certain information from the Event
Monitor, using a pipe is recommended in order to save disk space (and
maintenance) for the monitor storage files. See 5.4.3.6, “Working with
Event Monitors using a pipe” on page 155 for an example of using an Event
Monitor with a pipe.
If the target for an Event Monitor is a directory, then the stream of data will be
written to a series of files. The files are sequentially numbered and have a file
extension of evt (such as 00000000.evt, 00000001.evt, and so on). The
maximum size and number of Event Monitor files is specified when the
monitor is defined.
As an example, you could use the following DDL to create an Event Monitor
to track transactions and statements:
This Event Monitor is defined to allocate up to ten files, each 2 MB in size, for
a total monitor storage area of 20 MB. Other Event Monitor options include
specifying the size of the write buffer, synchronous (blocked) writes,
asynchronous (unblocked) writes, APPEND the Event Monitor data to
existing records, or REPLACE the Event Monitor data in the directory
whenever the monitor is activated.
Note
The GUI tool db2emcrt allows you to create and start an Event Monitor in
the one operation. It also allows you to stop the monitor.
SELECT evmonname
, EVENT_MON_STATE(evmonname) AS state
, io_mode
FROM syscat.eventmonitors;
2 d( ) l t d
The IO_MODE column indicates if the monitor uses a blocked file. The column
will be null for monitors using a names pipe.
To see which events were defined for each Event Monitor, you could use the
following statements:
10 record(s) selected.
Tip
Note that this example uses the VARCHAR function to truncate the FILTER
column rather that the SUBSTR function. In this way you will receive a
warning (SQL0445W) if the columns had values which were truncated.
Note
There is no limit in the number of defined Event Monitors, but a maximum
of 32 Event Monitors can be active per DB2 instance at a time.
To ensure that all of the event records have been written to disk (some may
be buffered), you could simply turn the Event Monitor off. You can also use
the BUFFER option of FLUSH EVENT MONITOR command as follows:
FLUSH EVENT MONITOR evmon1 BUFFER
This forces the Event Monitor buffers to be written out. The FLUSH EVENT
MONITOR command with the BUFFER option does not generate a partial record.
Only the data already present in the Event Monitor buffers are written out.
To generate the Event Monitor report for the mon_tr_st monitor, issue the
following command indicating where the Event Monitor files are located:
db2evmon -path /eventmonitors/mon_tr_st
or
db2evmon -db tpc -evm mon_tr_st
The output of the db2evmon utility will be displayed on the screen by default. It
is best to redirect the output to a file for analysis.
The following example shows a monitored event record for an SQL statement
issued by an applications. You can see executed SQL statements and the
statistics for the statements from the monitored event records.
.....
12) Statement Event ...
Appl Handle: 45
Appl Id: *LOCAL.db2inst1.000519225726
Appl Seq number: 0001
This script maintains the conventions discussed earlier (see 5.2, “Maintaining
tuning information” on page 120) to save output files in the directory
structure. The output that the script generates is dependant on the
parameters chosen and may include: SQL files for individual statements
captured; the entire results of the db2evmon command; and the summarized
(filtered) information and statistics on each statement.
-- ----------------------------------------
-- Invocation: mon_stmt.ksh -c PIPE -d tpc -m mon_all -o 24 -s 117
-- Wed May 31 17:56:02 PDT 2000
--
db2evmon TPC mon_all
Use the AIX command below to create the pipe for the Event Monitor and
give it the proper permissions:
mkfifo -m g+rw /eventmonitors/mon_all_pipe
The following list summarizes the different ways by which SQL statements
can be obtained for analysis:
• Directly from the user or developer, who can extract it from their source
code. There may be cases, however, when the SQL statements are
generated dynamically from some sort of querying tool, such as Business
Objects (R).
• From the Dynamic SQL Snapshot Monitor (also known as the global
package cache).
• From the Statements Event Monitor.
Before describing the capabilities and features of the Explain Facility, you
need to understand, at a high level, how SQL statements are processed by
the DB2 database engine. Each SQL statement is analyzed by DB2; then it is
determined how to process the statement during a static bind or when
executed dynamically. The method used to retrieve data from tables is called
the access plan.
The component within DB2 that determines the access plan to be used is
known as the optimizer. During the static preparation of an SQL statement,
the SQL compiler is called on to generate an access plan. The access plan
contains the data access strategy, including index usage, sort methods,
locking semantics, and join methods. The executable form of the SQL
statement is stored in the system catalog tables when a BIND command is
executed (assuming a deferred binding method). This is called a package.
Note
The method for retrieving data from a specific table, such as whether
indexes are used or not, is called the access path. The access plan
involves a set of access paths.
SQL COMPILER
Parse Query
Check Semantics
Execute Plan
Executable
Explain Tables Plan
Visual db2exfmt
db2expln
Explain Tool
The Explain information must be captured before you can review it using one
of DB2’s Explain tools. You can decide to capture detailed information
regarding the access plan. While the query is being compiled, the information
can be captured into a file or special tables known as Explain tables.
Note
Explain tables are created the first time you use Visual Explain.
Not all the Explain tools require the same kind of Explain data. Some tools
use the data captured using the EXPLAIN option and others, such as Visual
Explain, require snapshot data.
After creating the Explain tables, you can start capturing the Explain data that
will populate them. Not all the SQL statements can be Explained. The
Explainable SQL statements include: SELECT, SELECT INTO, UPDATE, INSERT,
DELETE, VALUES, and VALUES INTO statements.
You can control the amount of Explain information that the EXPLAIN statement
will store in the Explain tables. The default is to only capture regular Explain
table information and not the snapshot information. If you wish to modify this
behavior, this is done using the following EXPLAIN statement options:
• WITH SNAPSHOT— This option will capture Explain and Explain
snapshot data into the Explain tables. This will enable analysis from Visual
Explain.
• FOR SNAPSHOT — This option only captures the Explain snapshot
information. No other Explain information is captured other that normally
found in the EXPLAIN_INSTANCE and EXPLAIN_STATEMENT tables.
• The default case is used when no other Explain option is specified. In the
default case, the EXPLAIN statement will only gather the Explain data. No
Explain snapshot data is captured.
To issue the EXPLAIN statement, the user must have INSERT privilege on
the Explain tables.
Note
The SQL statement being Explained using the EXPLAIN statement will not be
executed; only the Explain data is captured.
The following statements are used to set the value of the Explain special
registers:
SET CURRENT EXPLAIN MODE option
SET CURRENT EXPLAIN SNAPSHOT option
The following two options are for the CURRENT EXPLAIN MODE register only:
• RECOMMEND INDEXES — This option will be discussed in the section
that discusses the Index Advisor.
EVALUATE INDEXES — This option will be discussed in the section that
discusses the Index Advisor.
Note
Once you have set a register to YES or EXPLAIN, any subsequent dynamic
SQL statements will be Explained until the register is reset to NO.
When ALL is specified for the EXPLAIN or EXPLSNAP options, instead of YES, then
the Explain tables will also be populated for dynamic SQL.
Note
Explain snapshots cannot be performed for DRDA application servers.
In our example, the Explain snapshot information will be populated for all of
the static SQL statements defined in the program1.bnd package. Because the
ALL option was specified, the dynamic SQL statements issued during
package execution will also have Explain snapshot information gathered at
run-time.
To examine the access plan data for individual dynamic SQL statements, the
special register technique is an easier method to use.
Using the Explain report tools to gather and analyze Explain data
There are alternative methods of gathering Explain data that is stored in a
report rather than in the Explain tables. They are the dynexpln tool and the
db2expln tool.
The db2expln tool describes the access plan selected for static SQL
statements in the packages stored in the system catalog tables. On the other
hand, the dynexpln tool describes the access plan selected for dynamic SQL
statements. It creates a static package for the statements and then uses the
db2expln tool to describe them.
The Explain output of both utility programs is stored in a readable report file.
The Explain report tools are useful as quick and easy methods for gathering
access plan information.
The following example shows the access plan selected for static SQL
statement in the package, CURSOR. This package has been created by
precompiling and binding the sample program cursor.sqc which you can find
in the ~/sqllib/samples/c directory.
SQL Statement:
Estimated Cost = 25
Estimated Cardinality = 12
End of section
By analyzing this output, you can see the information about how DB2 will
access the data in order to resolve the SQL statements. In this example, a
table scan is chosen to access the STAFF table, and a SARGable predicate is
applied (see Chapter 7 for the predicate types).
Visual Explain
Visual Explain is a GUI (Graphical User Interface) utility that gives the
database administrator or application developer the ability to examine the
access plan determined by the optimizer. Visual Explain can only be used
with access plans Explained using the snapshot option.
The Explain SQL... option, also shown in Figure 31, allows you to gather
Explain data and show the graphical representation of a dynamic SQL
statement. This is the easiest way to Explain a single SQL statement.
Once the Explained Statements History window has been opened, all of the
Explained statements will be listed as shown in Figure 32. The displayed
information may differ since it can be customized to your environment. In
Figure 32, the total costs and the SQL statements are shown.
Note
The Explain SQL option on the Control Center, or the Command Center are
useful to Explain a single dynamic SQL statement.
You can add comments to the Explain snapshots listed in the Explained
Statements History window. To add a comment describing a query, highlight
the entry and then select Statement ➔ Change. This option can be used to
provide a query tag, which can be used to help track the Explain snapshot
information. You may also wish to remove Explain snapshots. The snapshots
can be removed from the Explain tables by selecting Statement ➔ Remove
after highlighting the entry to be removed.
There are many operators that can be used by the DB2 optimizer to
determine the best access plan. Some of the operators used by Visual
Explain are shown in Figure 33.
INSERT
UPDATE
DELETE TABLE
FETCH
RETURN
UNION
UNIQUE
SORT
GRPBY INDEXES
TEMP
FILTER
Figure 34. VIsual Explain: graphical access plan for SQL Statement
Generating Explain data for an SQL statement is the only way to analyze the
access plan determined by the DB2 optimizer.
Each node, shown in an access plan graph, has detailed information that can
be accessed by double-clicking on the node or by choosing the Show details
option from the Node menu item.
Detailed information for operand nodes shows the table or index statistics,
including table space information, the number of columns, and the number of
rows in the object. Figure 36 shows the Explained and current statistics from
the system catalog tables. These statistics are used by the DB2 optimizer to
determine the access plan.
When the optimizer has no statistics to work with for a table, or if the statistics
for a table indicate that the cardinality of the table is relatively small, then the
optimizer itself will attempt to calculate the cardinality of the table. The
optimizer does this using certain factors including the average column length
of the table and the number of pages used by the table.
Current statistics are the key to good access plans. If DB2 is not aware of the
characteristics of objects involved in a query, it may not be able to generate a
good access plan. To ensure that the latest statistics are available for the
Statistics for the DB2INST1.ORDERS table are stored in the system catalog
tables. After running the RUNSTATS utility, rebind the packages against the
database and re-Explain the SQL statement.
When determining the access plan for dynamic SQL statements, the DB2
optimizer always uses the current statistics. For a static SQL statement, DB2
uses the statistics available at BIND time (when the package was created). To
ensure that current statistics are used with static SQL statements that were
compiled before the statistics were updated, the packages must be recreated.
This can be accomplished using the REBIND command.
Note
Updated statistics are always needed and become critical as your SQL
statements grow in complexity
You can also use the Explain Facility to evaluate whether a different index
can be used instead of an existing index or no index at all. After creating a
new index, collect statistics for that index using the RUNSTATS command and
rebind packages for static SQL programs.
The db2batch is usually fed by an input file. In this file, the user is able to set
the different options and write the SQL statements that are to be executed by
the utility. See the sample input file shown below:
--#SET perf_detail 2
--#SET rows_fetch 20
--#SET rows_out 10
select s_name from supplier;
--#SET rows_fetch -1
--#SET rows_out -1
select r_name,r_regionkey from region order by r_name;
The output of the db2batch utility can be sent to a file. The level of detail,
perf_detail, is set to 1 by default. This means that only the elapsed time for
each SQL statement, agent CPU time for each SQL statement and the mean
value of both will be returned. The default value for rows_fetch and rows_out is
-1, meaning to fetch all rows from the answer set and to send all rows fetched
to the output device.
R_NAME R_REGIONKEY
-----------------------------------------
AFRICA 0
AMERICA 1
ASIA 2
EUROPE 3
MIDDLE EAST 4
Summary of Results
==================
Elapsed Agent CPU Rows Rows
Statement # Time (s) Time (s) Fetched Printed
1 0.026 0.010 5 5
5.4.5.1 db2bench.ksh
We have written a sample shell script to execute db2batch tool and store the
output to the directory structure which all our sample scripts use (see 5.2,
“Maintaining tuning information” on page 120). The source file of this script is
included in Appendix A, “Sample scripts” on page 335.
To obtain a CLI trace, run the application after using one of these means to
activate tracing:
• Command Line Processor: See the following example:
db2 update cli cfg for section common using trace 1 tracepathname <fully
qualified pathname>
db2 update cli cfg for section common using tracecomm 1
• Client Configuration Assistant (OS/2 and Windows only): Select a
database (it must be one registered for ODBC), then Properties,
CLI/ODBC Settings, Advanced, and Service.
The TRACEPATHNAME keyword specifies the directory path name used to store
individual trace files.
(1) SQLFreeHandle( )
<--- SQL_SUCCESS Time elapsed - +2.758000E-003 seconds
(3) SQLDisconnect( )
<--- SQL_SUCCESS Time elapsed - +1.001400E-002 seconds
As useful as these elapsed times are (and later we'll discuss how to maximize
their usefulness), it is often more interesting to obtain the additional
information that comes with TRACECOMM.
Let us now look at how the trace records in the above example will change if
the fetch program is run again, this time with TRACECOMM activated (=1).
(Record numbers on the left in the trace records below were added to aid in
the discussion.)
(1)
SQLFreeHandle(
SQLFreeHandle(
) )
(1) <---
<---SQL_SUCCESS
SQL_SUCCESS Time
Timeelapsed
elapsed--+2.894000E-003
+2.758000E-003seconds
seconds
(2)SQLDisconnect(
SQLDisconnect(hDbc=0:1
hDbc=0:1))
(2) --->
--->Time
Timeelapsed
elapsed--+1.587000E-003
+8.430000E-004seconds
seconds
(3) sqlccsend( ulBytes - 72 )
(3)
(4) SQLDisconnect(
sqlccsend( Handle
) - 539269544 )
(5) sqlccsend(
<--- SQL_SUCCESS
) - rc - Time
0, time
elapsed
elapsed
- +1.001400E-002
- +1.960000E-004
seconds
sqlccrecv( )
(6) sqlccrecv( ulBytes - 27 ) - rc - 0, time elapsed - +4.278810E-001
SQLDisconnect( )
(7) <--- SQL_SUCCESS Time elapsed - +4.296480E-001 seconds
To see the derivation of the elapsed times in a different way, refer to the
following diagram (Figure 37). It shows the main components involved in
executing the calls in the previous trace snippet. The arrows represent the
flow of control as time passes (going down the page). The letters (a), (b), and
so on, represent the points at which the DB2 CLI driver records timestamp
information:
• The elapsed time in line (2) above is the difference between times (a) and
(b). This is the time spent in the application between the return to the
application after the SQLFreeHandle call was processed, and the entry to the
CLI Driver to process the SQLDisconnect call. (Actually, it also includes the
communication time from and to the CLI driver, and the time in the driver
between when the timestamp was taken and the exit or entry, but those
times are generally negligible.)
• The time in line (5) is the difference between (c) and (d), or the Send time.
• The time in line (6) is the difference between (d) and (e), or the Server and
Receive time.
TIME
Application CLI Driver Database
(or ODBC SQLFreeHandle
Driver Manager) (a) Server
SQLDisconnect
(b)
(c) Send
(d)
Receive
(e)
SQLDisconnect
(f)
Following are some sample outputs for the various combinations of values for
TRACETIMESTAMP and TRACEPIDTID. Note that the regular trace output is
unchanged, but is shifted to the right of the new information.
*********************
* TraceTimestamp=1 *
* TracePidTid=0 *
*********************
[ Process: 298, Thread: 317 ]
[ Date & Time: 02-11-2000 09:49:14.000025 ]
*********************
* TraceTimestamp=2 *
* TracePidTid=0 *
*********************
[950280554.000183] SQLSetEnvAttr( )
[950280554.000213] <--- SQL_SUCCESS Time elapsed - +3.000000E-005 seconds
*********************
* TraceTimestamp=3 *
* TracePidTid=0 *
*********************
[02-11-2000 09:49:15.000184] SQLSetEnvAttr( )
[02-11-2000 09:49:15.000233] <--- SQL_SUCCESS Time elapsed - +4.900000E-005 second
Some other typical objectives involve determining which CLI calls are
occurring (a third-party tool could be generating them), or to look for
execution errors, but these objectives are beyond the scope of this section.
Application and DB2 times can be summarized very easily using a Java tool
called CLITraceParser, which is available at:
ftp://ftp.software.ibm.com/ps/products/db2/tools/ in the file
CLITraceParser.zip. See the README.TXT file in that tool subdirectory for
information on installation and usage. Note that CLITraceParser replaces and
improves upon parseCLITrace, which is also available at that FTP site.
14 statements in trace.
93.110 seconds total trace time.
0.012 seconds spent for application processing.
93.098 seconds spent for CLI processing.
**************************************************************************
**************************************************************************
==========================================================
End of CLI Trace Report
The output clearly indicates that time in DB2 is the key component of elapsed
time to be addressed in this particular example.
The following example shows the output of CLITraceParser for a trace file
taken from the same application as for the summary above, but this time with
TRACECOMM=1. (A different run was made to collect this trace, so there are small
differences in elapsed times.)
14 statements in trace.
88.332 seconds total trace time.
0.014 seconds spent for application processing.
88.319 seconds spent for CLI processing.
*************************************************************************
*************************************************************************
==========================================================
End of CLI Trace Report
Note that the information in the report is the same as with TRACECOMM=0, except
that the network statistics, which were previously zero, are now supplied.
Search examples
Following are some examples of commands to do specific searches.
In each one, “trace_file” must be replaced by the name of the trace file being
analyzed.
Note that trace file lines that are specific to TRACECOMM contain “ E+” or “ E-”,
but not “<---” or “--->”. Therefore, the first example will find TRACECOMM
specific entries; but all of the other examples, because they include a search
for an “arrow”, will not:
• The following can be used on a Windows command line to list all elapsed
times, both in DB2 and the application, along with their line numbers in the
trace file:
findstr /n "E+ E-" trace_file | more
• The following can be used on a Windows command line to list elapsed
times of 10 to 999.9 seconds in DB2, with their line numbers in the trace
file:
findstr /n "E+001 E+002" trace_file | findstr /c:"<---"
• The following can be used on a Windows command line to list elapsed
times of 0.10 to 0.99 seconds in the application, with their line numbers in
the trace file:
findstr /n "E-001" trace_file | findstr /c:"--->"
• The sort command in Windows is quite limited, compared to sort in UNIX.
The following can be used on UNIX, or on Windows with the MKS toolkit
(or possibly via other tools from freeware or shareware sources), to list, in
descending order and with line numbers within the trace file, the 20
longest elapsed times in DB2 that are one second or longer.
grep -n -e "<---" trace_file | grep -e "E+" | sort
-k 6.12b,6rn -k 6.2b,6.9brn | head -n 20
Note that “ E+” is changed to “ E-”, and “ r” is omitted from “ -k 7.12b,7rn”. The
6's in the commands indicate that the 6th token in each line is to be used as a
sort key. If the “-n” option had not been specified in the grep command, there
would not be a line number in each grep output line (one less token per line),
and so the 6's in the sort commands would have to be changed to 5's. Similar
adjustments need to be made if non-zero values of the TRACETIMESTAMP or
TRACEPIDTID keywords are specified when generating the trace.
Merged file 000298.mrg, created by "sort -k 3.2n 000298.* > 000298.mrg" on Unix
One thing you may see in the merged trace file is one thread not having any
entries for a long period. This could simply indicate that a long-running task
was being executed, but it could also indicate that the thread is in a lock wait
state. Note that an application's multiple threads can have multiple
connections to a database, and from the database server's point of view there
is no special relationship between those connections. For instance, they can
lock each other out, even though they belong to the same application and are
executed through the same authorization ID.
In this chapter, we discuss how memory is used by DB2 UDB, and then
introduce configurable parameters of DB2 UDB to optimize the performance
of your database. You can see more than one hundred configurable
parameters in the manual DB2 UDB Administration Guide - Performance,
SC09-2945, although you do not have to tune all of them. You can focus on a
few important parameters which highly impact the database performance
only. Here we will introduce some parameters, grouped according to which
areas of system resource usage these parameters affect.
As you have seen in Chapter 2, “Setting up the Control Center” on page 15,
when you create a new database, you should use the Configure Performance
Wizard to obtain the recommended values of the performance related
configuration parameters. You should also use this wizard to obtain new
recommended values when your database has been significantly updated.
You can start with the recommendations made by this wizard, and then make
further adjustments to optimize the performance of your database. This
chapter is intended to aid you in making those further adjustments.
To view, set, and reset the database manager configuration parameters, you
can use the following methods:
To view, set, and reset the database configuration parameters, you can use
the following methods:
• Control Center
The Control Center provides the Configure Database notebook which you
can use to view, set, and reset the database configuration parameters.
See 2.3.1, “Setting up configuration parameters” on page 22.
• Database Parameters
From the Command Line Processor or the Command Center, you can
execute these commands:
GET DB CFG FOR database_name
UPDATE DB CFG FOR database_name USING parameter_name value
RESET DB CFG FOR database_name
Database M anager
Shared M em ory
(1) (maxagents)
The Agent Private Memory is allocated for each DB2 agent when the DB2
agent assigned to work for an application. The Agent Private Memory
contains memory areas which will be used only by this specific agent, such as
sort heaps and application heaps.
The Agent Private Memory remains allocated even after the DB2 agent
completes tasks for the application and gets into idle state. However, if you
set the DB2 registry variable DB2MEMDISCLAIM to YES, then DB2 disclaims some
or all memory once freed, depending on the value given with the DB2 registry
variable DB2MEMMAXFREE which defines the amount of the memory to be retained
by each DB2 agent. We discuss these registry variables later in this chapter.
Note
Application Global Memory is allocated if you enable intra-partition
parallelism, or if the database manager is in a partitioned database
environment using DB2 UDB Enterprise-Extended Edition, which is beyond
our discussion
For valid ranges and default values of these configuration parameters, see
the DB2 UDB Administration Guide - Performance, SC09-2945.
For complex SQL type workloads with relatively few users (such as OLAP or
DSS), then enable intra-partition parallelism (set to YES). For SQL which is
simple, repetitive and the number of queries are large (such as OLTP), then
do not enable intra-partition parallelism (set to NO).
Having a huge number of DB2 agent processes may cause CPU constraints
due to context switching, as well as memory constraints.
To control the number of DB2 agents, you have the following configuration
parameters:
• The database manager configuration parameter MAXAGENTS defines the
maximum number of database manager agents, whether it is coordinator
How the sort is handled within these two steps results in different categories
or types by which we can describe the sort. When considering the sort phase,
the sort can be categorized as overflowed or non-overflowed. When
considering the return of the results of the sort phase, the sort can be
categorized as piped or non-piped.
The sort heap is used for each application sort request. The DB2 optimizer
may decide to attempt to perform a non-overflowed piped sort. However, if
there is not enough available memory to allocate another sort heap at run
time, then the sort may be performed using a temporary table.
Note
You can use the Explain Facility to see which type of parallel sort is
performed for a query.
The SHEAPTHRES parameter is used differently for private and shared sorts.
For private sorts, this parameter is an instance-wide soft limit on the total
amount of memory that can be consumed by private sorts at any given time.
When the total private-sort memory consumption for an instance reaches this
limit, the memory allocated for additional incoming private-sort requests will
be considerably reduced.
You can calculate the percentage of piped sorts accepted by Piped Sorts
Accepted/Piped Sorts Requested and determine if piped sorts are being chosen
by the optimizer but not accepted. If the percentage is low, consider
increasing the SORTHEAP and/or SHEAPTHRES.
Note
In a piped sort, the sort heap does not get freed until the application closes
the cursor associated with the sort. So a piped sort can use up memory
until the cursor is closed.
The following two sample outputs show monitored sorting related elements
by the snapshot monitor:
Setting the appropriate value for this parameter can reduce the cost to create
and terminate DB2 agent processes. Too high a value for this parameter may
waste the memory due to many idle agents.
For dynamic SQL, even though your application does not execute exactly the
same queries, it may benefit by the package cache using parameter markers.
See 7.3.2.2, “Avoid repeated PREPARE statements” on page 246.
There are a number of package cache related performance variables that can
be monitored using the system performance monitor. These parameters
include:
• Package cache insert — This variable indicates the total number of times
that a requested section was not available for use and had to be loaded
into the package cache. If this number is high, it may mean that the cache
is too small.
You can calculate the package cache hit ratio using the following formula:
1 - (Package Cache Inserts / Package Cache Lookups)
Normally, a low hit ratio would mean that the cache is too small. But as a
result of running DDL statements, a low hit ratio does not always mean that
the cache is small. It may be caused by invalidated dynamic sections and the
need of information to be reinserted back into the cache. In this case,
increasing PCKCACHESZ will not improve the cache performance.
You should take your application type into account when you tune the
package cache size. For example, if your applications rarely execute the
same query, increasing the package cache to keep the package may not be
worthwhile to do.
The package cache is a working cache, so you cannot set this parameter to
zero. There must be sufficient memory allocated in this cache to hold all
sections of the SQL statements currently being executed. If there is more
space allocated than currently needed, then sections are cached. These
sections can simply be executed the next time they are needed without
having to load or compile them.
The limit specified by the PCKCACHESZ parameter is a soft limit. This limit may
be exceeded, if required, if memory is still available in the database shared
set. You can use the Package Cache High Water Mark monitor element to
determine the largest that the package cache has grown, and the Package
Cache Overflows monitor element to determine how many times the limit
specified by the PCKCACHESZ parameter has been exceeded. The following
example shows monitored package cache related elements by the snapshot
monitor:
Parameters that allocate memory should never be set to their highest values,
unless it is fully justified, even on systems with the maximum amount of
memory installed. A few tuning parameters that have implications associated
with performance of I/O are discussed here.
On OLTP (that is, random access) environments, you need as many disks in
the table spaces as are necessary to support the I/O rates required. For
example, if your table space needs to process 100 IO/sec and your disks can
service 60 IO/sec, then you would need two disks. Often writes are more
expensive than reads (as with RAID systems, since they may require multiple
physical writes for redundancy), and thus the read/write ratio, along with the
true I/O cost of one write, has to be considered.
On DSS (that is, sequential access) environments, you need as many disks
as are necessary to meet the I/O rates required. Note, however, that DSS
workloads are more “disk-friendly”, mainly due to their larger I/O sizes.
Because of this, and the prefetching/caching abilities built into many file
systems and disk subsystems (for example, RAID/Extended Storage
Subsystem), a DSS workload can often get by with less disks than an OLTP
system with similar I/O needs. Normally, 5 disks per CPU are often sufficient
for simple DSS scans. With full SMP parallelism enabled, this number can
increase to 10 or more disks per CPU.
When creating a buffer pool, by default, the page size is 4 KB, but you can
choose to have the page size set at one of these values: 4 KB, 8KB, 16 KB,
or 32 KB.
If buffer pools are created using one page size, then only table spaces
created using the identical page size can be associated with them. You
cannot alter the page size of the buffer pool following its creation.
Each database has at least one buffer pool ( IBMDEFAULTBP, which is created
when the database is created), and you can have more also. All buffer pools
reside in the Database Global Memory (as shown in Fig. 39 on page 197),
which is available to all applications using the database. All buffer pools are
allocated when the first application connects to the database, or when the
database is explicitly activated using the ACTIVATE DATABASE command. Use
this ACTIVATE DATABASE command to keep buffer pool primed even if all the
connections terminate. This will be very useful when connection load is highly
dynamic (for example, Web servers).
Note
After changed pages are written out to disk, they are not removed from the
buffer pool unless the space they occupy is needed for other pages.
Note
NPAGES in SYSCAT.BUFFERPOOLS overrides BUFFPAGE.
To determine whether the BUFFPAGE parameter is active for a buffer pool, issue
this command:
SELECT * FROM SYSCAT.BUFFERPOOLS
Instead of using the BUFFPAGE configuration parameter, you can use the CREATE
BUFFERPOOL and ALTER BUFFERPOOL SQL statements to create and change buffer
pools and their sizes. See SQL Reference, SC09-2974 for the syntax.
6.5.1.1 Buffer pool hit ratio and index pool hit ratio
If you create your own buffer pools in addition to the default buffer pool, you
must be careful how you allocate space for each one. Allocating a large buffer
pool to a table space containing a large number of small, rarely used tables
and a small buffer pool to a tables space containing a large, frequently
accessed table will lead to performance problems. The size of the buffer
pools should reflect the size of table in the table space, and how frequently
they are updated or queried.
The I/O costs of reading the tables can have an impact on:
• How two tables are joined, for example, outer versus inner.
• Whether an index will be used to read the data.
Snapshot monitor for buffer pools can be used to capture information on the
number of reads and writes and the amount of time taken. Before getting the
snapshot, set the buffer pool monitor switch on by performing either of the
following actions:
• Execute UPDATE MONITOR SWITCHES command which affect only the current
session.
• Update the DBF_MON_BUFPOOL database manager configuration parameter to
ON.
Snapshot monitor will provide information about buffer pool activity for all
active databases when you run the following command:
GET SNAPSHOT FOR ALL BUFFERPOOLS
Bufferpool Snapshot
If the server needs to read a page of data, and that page is already in the
buffer pool, then it will be accessed faster than the one from the disk. It is
then desirable to “hit” as many pages as possible in the buffer pool.
The following data elements can be measured to evaluate how the buffer pool
is being used:
• Buffer Pool Data Logical Reads: Denotes the total number of read data
requests that went through the buffer pool.
• Buffer Pool Data Physical Reads: Denotes the number of read requests
performed that required I/O to place data pages in the buffer pool.
• Buffer Pool Index Logical Reads: Denotes the total number of read
requests for index pages that went through the buffer pool.
The buffer pool hit ratio indicates the percentage of time that the database
manager did not need to load a page from disk in order to service a page
request. That is, the page was already in the buffer pool. The greater the
buffer pool hit ratio, the lower the frequency of disk I/O.
The overall buffer pool hit ratio can be calculated as the difference between
the number of all (data + index) logical reads and number of all (data + index)
physical reads divided by the total number of read requests.
Σ LogicalReads – Σ PhysicalReads
BufferPoolHitRatio = -------------------------------------------------------------------------------------------------- × 100
Σ LogicalReads
Similarly, an index pool hit ratio is calculated as the difference between the
number of the index logical reads and the number of index physical reads
divided by the total number of index read requests.
Σ IndexLogicalReads – Σ IndexPhysicalReads
IndexPoolHitRatio = ----------------------------------------------------------------------------------------------------------------------------------- × 100
Σ IndexLogicalReads
Increasing buffer pool size will generally improve the hit ratio, but you will
reach a point of diminishing returns. Ideally, if you could allocate a buffer pool
large enough to store your entire database, then once the system is up and
running, you would get a hit ratio of 100%. However, this is unrealistic in most
cases. The significance of the hit ratio depends on the size of your data, and
the way it is accessed.
For a large database, increasing the buffer pool size may have minimal effect
on the buffer pool hit ratio. Its number of data pages may be so large, that the
statistical chances of a hit are not improved increasing its size. But you might
find that tuning the index buffer hit ratio achieves the desired result. This can
be achieved using two methods:
1. Split the data and indexes into two different buffer pools and tune them
separately.
2. Use one buffer pool, but increase its size until the index hit ratio stops
increasing.
A very large database where data is accessed evenly would have a poor hit
ratio. There is little you can do with very large tables. In such a case, you
would focus your attention on smaller, frequently accessed tables, and on the
indexes — perhaps assigning them to individual buffer pools, in which you
can aim for higher hit ratios.
The index pool hit ratio and the buffer pool hit ratio are influenced by data
reorganization. it is always advisable to perform a REORGCHK command to
check these hit ratios before tuning.
6.5.1.2 Prefetching
Prefetching means retrieving one or more pages from disk in anticipation of
their use. Prefetching index and data pages into the buffer pool can help
improve performance by reducing the time spent waiting for I/O to complete.
Setting the prefetch size has significant performance implications, particularly
for large table scans.
Prefetchers are used to bring data into the buffer pool and also look after
dropping temporary tables. Page cleaners are used to move data from the
buffer pool back out to disk. For example, applications needing to scan
through large volumes of data would have to wait for data to be moved from
disk to buffer pool, if there were no data prefetchers. Agents of the application
send asynchronous read-ahead requests to a common prefetch queue. When
prefetchers are available, they perform these requests by using big-block or
scatter read operations to bring the requested pages from disk to the buffer
pool.
If the prefetchers and page cleaners are not specified, then the application
agents would have to do all the reading and writing of data between the buffer
pool and disk storage.
Dirty pages are pages where data has been changed but has not yet been
written to disk. After a page is written to disk, it is considered clean, and
remains in the buffer pool.Page cleaners check the buffer pool, and write
pages asynchronously to disk. Page cleaners basically perform two
operations:
• Assure that an agent will always find free pages in the buffer pool.
• Copy the oldest unwritten change of Logical Sequence Number (LSN) to
the buffer pool.
Without the existence of the independent page cleaners, the DB2 agents
have to clean dirty pages by themselves, and the application being served by
these agents ends up with a poor response.
Pages are written from buffer pool to disk when the percentage of space
occupied by changed pages in the buffer pool has exceeded the value
specified in the CHNGPGS_THRESH configuration parameter. Page cleaner agents
( NUM_IOCLEANERS) write out changed pages to disk. Page cleaners are
sometimes referred to as asynchronous page cleaners or asynchronous
buffer writes because they are independent of DB2 agents.
You may use the changed pages threshold ( CHNGPGS_THRESH) to specify the
level (in percentage) of changed pages at which the asynchronous page
cleaners will be activated, if they are not currently active. When the page
cleaners are started, they will build a list of pages to write to disk. Once they
have completed writing those pages to disk, they will become inactive again
and wait for the next trigger to start. For the databases with a heavy update
transaction workload, setting CHNGPG_THRESH to default (60) is recommended. A
percentage larger than the default can help performance if your database has
a small number of very large tables.
If the NUM_IOCLEANERS parameter is zero (0), no page cleaners are started and,
as a result, database agents will perform all the page writes from the buffer
pool to disk. If you have many physical storage devices, this leads to a
significant performance impact, and there is a greater chance that one or
more devices will be idle.
A good value for CHNGPGS_THRESH is to use default value (60%), is suitable for
typical workloads. A percentage larger than the default can help performance
if your database has a small number of very large tables.
When sequential I/O is important (for example, DSS workloads) ensure DMS
table spaces are set up well for prefetching and parallel I/O:
1. Multiple containers, ideally at least 5
2. Each container mapped to its own disk(s)
3. Set PREFETCHSIZE to at least (#containers * EXTENTSIZE)
ESTORE is a second level page cache, and the buffer pool is the primary
cache. Because an extended storage cache is an extension to a buffer pool, it
must always be associated with one or more specific buffer pools. Each
buffer pool can be configured to use it or not. ESTORE is used when the
amount of memory that is allowed to be mapped by a single process is less
than the total amount of memory available. For UNIX platforms, this extra
memory can be accessed by cycling many segments through one address.
Copying pages to and from ESTORE costs CPU (for both the copies and
attaches), but it saves I/O every time a disk read is avoided. If you are
continually copying pages to ESTORE but rarely read from it, or if you are
already more CPU-bound than I/O-bound, then ESTORE will not help much in
performance.
6.5.3 Logging
All changes to data pages are logged, and the updated data page is not
written to disk storage before its associated log record is written to the log.
Therefore, improving the logging performance is very important to improve
the overall performance if your application performs frequent updates. The
following configuration parameters affect the logging performance.
The log records are written to disk when one of the following occurs:
1. A transaction commits, or a group of transactions commits ( MINCOMMIT).
2. The log buffer is full.
3. As a result of some other internal database manager event.
When you set the log buffer size, consider the size of database heap ( DBHEAP),
since LOGBUFSZ allocated from the database heap (DBHEAP). Also note that
using larger log buffers will not reduce data integrity, as data base commits
will still force log file writes.
If there are not enough transactions to commit their work, the database
manager will commit transactions every second.
When transactions are short, the log I/O can become a bottleneck due to the
frequency of the flushing of the log at COMMIT time. In such environments,
setting the MINCOMMIT configuration parameter to a value greater than 1 can
remove the bottleneck. When a value greater than 1 is used, the COMMITs
for several transactions are held or batched. The first transaction to COMMIT
waits until (MINCOMMIT - 1) more transactions COMMIT; and then the log is
forced to disk and all transactions respond to their applications. The result is
only 1 log I/O instead of several individual log I/Os.
Changes to the value specified for this parameter take effect immediately;
you do not have to wait until all applications disconnect from the database.
Increase or change in this parameter from its default value when there are
multiple or write applications typically request concurrent database
COMMITs. This will result in writing more log records each time it occurs. If
you increase MINCOMMIT, you may also need to increase the LOGBUFSZ
parameter to avoid having a log-full buffer force a write during these heavy
load periods.
If you use very large log files, consider lowering this parameter, as this will
reduce the time required to restart a database in the event of a crash
recovery. However, lowering the value can increase the database logging
overhead, which may impact performance. Lowering the value is not
recommended if you have relatively small log files, as the checkpoint will be
reached when these logs become full. See Administration Guide:
Performance, SC09-2945 for additional information.
If the disk space is scarce, the value of the LOGFILSIZ should be reduced,
since primary logs are preallocated at this size.
The timing of the writing of auditing records to the audit log file can have a
significant effect on the performance of databases in the instance. The writing
of audit records can take place synchronously or asynchronously with the
occurrence of the events causing the generation by those records.
For more information about the DB2 Audit Facility, refer to “Auditing DB2
Activities” in the DB2 UDB Administration Guide: Planning, SC09-2946.
The default value can be overridden when the DB2TCPCONNMGRS registry value is
set; then the number of TCP/IP connection managers specified (to the
maximum of 8) will be created.
If the DB2TCPCONNMGRS value is less than 1, then the DB2TCPCONNMGRS value is set
to 1, and a warning message is logged that the value is out of range.
If the DB2TCPCONNMGRS values are between 1 and 8, then they are used as
given.
6.6.2 Blocking
Row blocking is a technique that reduces database manager overhead by
retrieving a block of rows in a single operation. These rows are stored in a
cache, and each fetch request in the application gets the next row from the
cache. When all the rows in a block have been processed, another block of
rows is retrieved by the database manager.
The cache is allocated when an application issues an OPEN CURSOR request and
is deallocated when the cursor is closed. The size of the cache is determined
by a configuration parameter which is used to allocate memory for the I/O
block. The parameter used depends on whether the client is local or remote:
• For local applications, the parameter ASLHEAPSZ is used to allocate the
cache for row blocking
• For remote applications, the parameter RQRIOBLK (client I/O block size) on
the client workstation is used to allocate the cache for row blocking. The
cache is allocated on the database client
For local applications, you can use the following formula to estimate how
many rows are returned per block:
Rows per block = ASLHEAPSZ * 4096 / ORL
Here, ASLHEAPSZ is in pages of memory 4096 is the number of bytes per page,
and ORL is the output row length in bytes.
For remote applications, you can use the following formula to estimate how
many rows are returned per block:
Rows per block = RQRIOBLK / ORL
Here, RQRIOBLK is in bytes of memory, and ORL is the output row length in
bytes.
Refer to the SQL Reference , SC09-2974 for more information about cursors.
By default, this value is 15 (4 KB) pages. This value can contain an average
request or reply between the application and its agent. Its size can be
increased if queries retrieving large amounts of data.
If the request or reply do not fit into the buffer, they will be split into two or
more send-and-receive buffers. This size should be set appropriately, so that
it is able to handle the majority of requests using a single send-and-receive
buffer. The size of the request is based on the storage required to hold:
• The input SQLDA
• All of the associated data in the SQLVARs
• The output SQLDA
• Other fields which do not generally exceed 250 bytes
This parameter is also used to determine the I/O block size when a blocking
cursor is opened and allocated in the application’s private address space. So,
this is an additional parameter to be considered while allocating an optimal
amount of private memory for each application program. If the database client
cannot allocate space for a blocking cursor out of an application’s private
memory, then a non-blocking cursor will be opened.
The ASLHEAPSZ parameter is used to determine the initial size of the query
heap for both local and remote clients. The maximum size of the query heap
is defined by the QUERY_HEAP_SZ parameter. QUERY_HEAP_SZ is the set of
contiguous memory allocated by the database manager to receive the data
sent by the local application. The query heap is used to store each query in
the agent’s private memory.
This query heap parameter is provided to ensure that an application does not
consume unnecessarily large amount of virtual memory within an agent, and
it initially set with the value equal to ASLHEAPSZ.
Larger record blocks may also cause more fetch requests than are actually
required by the application. Control the fetch requests by using the OPTIMIZE
FOR clause on the SELECT statement in your application.
You need to increase the value of RQRIOBLK for the following conditions or
scenarios:
• A single SQL statement transmits large data (for example, large object
data).
• The number or size of rows being transferred is large (for example, if the
amount of data is greater than 4096 bytes). However, this will increase the
size of the working set memory for each connection, a trade-off has to be
done.
• Larger record blocks may also cause more fetch requests than are
actually required by the application. Control the fetch requests by using
the OPTIMIZE FOR clause on the SELECT statement in your application.
When you are trying to design a new database system or analyze an existing
database system, one of the most important considerations is your
application design. Even though your database is well designed and tuned,
inappropriate design of applications may cause performance problems. If
your application has a design problem, fixing this often improves the
application performance much more than tuning the configuration parameters
of DB2 UDB.
Study this chapter and apply these considerations when you develop or
evaluate your database applications.
The SQL compiler then generates many alternative execution plans for
satisfying the user’s request. It estimates the execution cost of each
alternative plan using the statistics for tables, indexes, columns, and
functions, and chooses the plan with the smallest execution cost. This is
known as query optimization.
Range delimiting predicates are those used to bracket an index scan. They
provide start and/or stop key values for the index search. Index SARGable
predicates are not used to bracket a search, but can be evaluated from the
index because the columns involved in the predicate are part of the index key.
For example, assume that an index has been defined on the NAME, DEPT, and
YEARS columns of the STAFF table, and you are executing the following select
statement:
The database manager will make use of the index data in evaluating these
predicates, rather than reading the base table. These range delimiting
predicates and index SARGable predicates reduce the number of data pages
accessed by reducing the set of rows that need to be read from the table.
Index SARGable predicates do not affect the number of index pages that are
accessed.
For example, assume that a single index is defined on the projno column of
the project table but not on the deptno column, and you are executing the
following query:
Residual predicates, typically, are those that require I/O beyond the simple
accessing of a base table. Examples of residual predicates include those
using quantified sub-queries (sub-queries with ANY, ALL, SOME, or IN), or reading
LONG VARCHAR or large object (LOB) data (they are stored separately from the
table).
As residual predicates and data SARGable predicates cost more than range
delimiting predicates and index SARGable predicates, you should try to limit
the number of rows qualified by range delimiting predicates and index
SARGable predicates whenever possible.
Let us briefly look at the following DB2 components: Index Manager, Data
Management Service, and Relational Data Service. Figure 41 shows each
DB2 component and where each category of predicates is processed.
Data
Note
Figure 41 provides a simplified explanation. Actually, DB2 has more
components than are shown in this diagram.
Relational Data Service (RDS) receives SQL requests from applications and
returns the result set. It sends all predicates to Data Management Service
(DMS) except residual predicates. Residual predicates are evaluated by
Relational Data Service (RDS).
DMS evaluates data SARGable predicates. Also, if the select list has
columns which cannot be evaluated by the index search, DMS scans data
pages directly.
The other benefit to specifying the FOR UPDATE clause is that can decrease the
possibility of deadlock. As we will discuss later in 7.6.8.2, “Deadlock
behavior” on page 269, deadlock is a situation in which more than one
application is waiting for another application to release a lock on data, and
each of the waiting applications is holding data needed by other applications
through locking. Let us suppose two applications are trying to fetch the same
row and update it simultaneously in the following order:
1. Application1 fetches the row.
2. Application2 fetches the row.
3. Application1 updates the row.
4. Application2 updates the row.
row1
DEAD
LOCK!
If you specify the FOR UPDATE clause in the DECLARE CURSOR statement, the U
lock will be imposed when Application1 fetches the row, and Application2 will
wait for Application1 to release the U lock. Thus, no deadlock will occur
between the two applications.
Note
In this example, we assume either of the two applications does not use the
isolation level UR (Uncommitted Read). We will discuss isolation levels in
7.6, “Concurrency” on page 258.
Note
The OPTIMIZE FOR n ROWS clause does not limit the number of rows that can
be fetched or affect the result in any way other than performance. Using
OPTIMIZE FOR n ROWS can improve the performance if no more than n rows
are retrieved, but may degrade performance if more than n rows are
retrieved.
For example, with the following coding, you will not receive more than 5 rows:
The FETCH FIRST n ROWS ONLY clause also determines the number of rows that
are blocked in the communication buffer. If both the FETCH FIRST n ROWS ONLY
and OPTIMIZE FOR n ROWS clause are specified, the lower of the two values is
used to determine the communication buffer size.
Note
Instead of the FOR FETCH ONLY clause, you can also use the FOR READ ONLY
clause. ‘ FOR READ ONLY’ is a synonym for ‘FOR FETCH ONLY’.
If columns A1 and B1 are the same data type, no data type conversion is
required. But if they are not the same data type, a data type conversion
occurs to compare values at run time and it might affect the performance. For
example, if A1 is a decimal column and B1 is an integer column and each has
a value ‘123’, data type conversion is needed, as TableA stores it as x‘123C’,
whereas TableB stores it as x‘7B’.
For detailed information about the supported data types, refer the DB2 UDB
SQL Reference, SC09-2974.
Note
If there is a relatively small set of queries in the application, db2batch is a
good tool to investigate the queries. See 5.4.5, “The db2batch utility” on
page 173.
If the network itself is in good shape, you should focus on reducing the
number of calls that flow from the application to the database (even for local
applications).
There are several ways to reduce network costs. Here we will introduce two
ways which involve having multiple actions take place through one call.
Atomic: If one of the statements in the block ends in error, the entire block is
considered to have ended in and error, and any changes made to the
database within the block will be rolled back.
You can also use compound SQL to improve performance of the IMPORT
utility, which repeats data inserts. When you specify MODIFIED BY COMPOUND=x
option (x is the number of inserts compounded into one block), the IMPORT
utility builds a block from multiple inserts. You will gain significant
performance improvement from this option. See the 8.3, “IMPORT utility” on
page 279 for more information.
Note
Since the release of Version 7.1, you can write a stored procedure using
SQL statements within a CREATE PROCEDURE statement.
If your system has a large number of stored procedure requests, you should
consider tuning some database manager configuration parameters, which are
explored in the following sections.
Note
For Java stored procedures, even though you set KEEPDARI=YES, you
can force DB2 to load new classes instead of stopping the database
manager. See “Refresh Java stored procedure classes” on page 243.
This parameter could increase the initial load time for non-Java fenced stored
procedures, as they do not require the JVM.
To force DB2 to load the new class, you have two options. One is restarting
the database manager, which may be not always acceptable. The other
option is executing a SQLJ.REFRESH_CLASSES statement. By executing this
command, you can replace Java stored procedure classes without stopping
the database manager even if you set KEEPDARI=YES. Execute the following
from the command line:
db2 CALL SQLJ.REFRESH_CLASSES()
Note
You cannot update a not-fenced Java stored procedure without stopping
and restarting the database manager.
You must pre-compile and bind such applications to the database so that the
database manager analyzes all of static SQL statements in a program,
determines its access plan to the data, and store the ready-to-execute
Since static SQL statements are processed based on the access plans
determined during the bind, there might be better access plans if you make
numerous changes to the database after the bind. For example, assuming
you have a very small table with an index and your application has static SQL
statements retrieving data from the index keys, then the application tends to
access the table using table scans rather than index scans because the size
is too small to benefit from index scans; however, if the table considerably
grows up, index scans are preferable. In such a case, you should consider
executing RUNSTATS to refresh the table and index’s statistical information
stored in the system catalog, and execute the REBIND command to take new
access plans for the static SQL statements.
There are various forms of RUNSTATS, but a good default to use is:
RUNSTATS ON TABLE xxx AND DETAILED INDEXES ALL
Adding the WITH DISTRIBUTION clause can be a very effective way to improve
access plans where data is not uniformly distributed.
When a table is known to be volatile to the optimizer, it will favor index scans
rather than table scans. This means that access paths to a volatile table will
not depend on the existing statistics on this table. These statistics will be
ignored by the optimizer because they can be misleading, in the sense that
they are static and do not reflect the current content of the table.
To deactivate the volatile option and let the DB2 optimizer choose access
paths based on the existing statistics, execute the following statement:
ALTER TABLE tablename NOT VOLATILE
An embedded dynamic SQL programming module will have its data access
method determined during the statement preparation and will utilize the
database statistics available at query execution time. Choosing an access
plan at program execution time has some advantages as well as a drawback.
One drawback is that dynamic SQL statements can take more time to
execute, since queries are optimized at run time. To improve your dynamic
SQL program’s performance, the following are key:
• Execute RUNSTATS after making significant updates to tables or creating
indexes.
• Minimize preparation time for dynamic SQL statements.
In the following section, we will discuss how to minimize preparation time for
dynamic SQL statements.
For example, suppose the application issues a PREPARE statement for the
statement "SELECT * FROM EMPLOYEE WHERE empno = ‘000100' ", then issues
another PREPARE statement for " SELECT * FROM EMPLOYEE WHERE empno = ‘000200'
" (the same statement but with a different literal value). The cached plan for
the first statement cannot be reused for the second, and the latter's PREPARE
time will be non-trivial. See the following example:
The solution is to replace the literal ‘000100' by a question mark (?), issue a
PREPARE, declare the cursor for the statement, assign the literal when opening
the cursor. By changing the program variable(s) appropriately before each
OPEN statement, you can reuse the prepared statement. See the following
example:
Parameter markers can and should be used, not just for SELECT, but also for
repeated executions of INSERT, UPDATE, or DELETE statements. For example, if
your application is using EXECUTE IMMEDIATE to execute multiple statements
that differ only in the literal values they contain, those EXECUTE IMMEDIATE
statements should be replaced by PREPARE and EXECUTE statements using
parameter markers. See the following example to read records from a file and
insert them into a table:
This example can complete the insert job faster, since only one INSERT
statement is prepared and reused for all rows being inserted.
Moreover, DB2 CLI and ODBC applications have the following advantages:
• Can store and retrieve sets of data.
• Can use scrollable and updatable cursors.
• Easy porting to other database platforms.
A drawback to using DB2 CLI and ODBC is that the dynamic preparation of
SQL statements can result in slower query execution.
As we have already discussed, since the DB2 optimizer tries to find the best
access plan for each SQL statement based on the current statistics
information saved in the system catalog, refreshing statistics information
using RUNSTATS will help the DB2 optimizer to determine the best access plan.
The db2ocat tool solves both problems by creating separate system catalog
tables called the ODBC optimized catalog tables that has only the columns
necessary to support ODBC/CLI operations.
The db2ocat tool is a 32-bit Windows program that can be used on Windows
workstations running the DB2 Version 6.1 (or later) client. You can create
ODBC optimized catalog tables in DB2 databases on any platform from this
tool running on Windows workstations.
Using the db2ocat tool, you can identify a subset of tables and stored
procedures that are needed for a particular application and create a ODBC
optimize catalog that is used to access data about those tables. Figure 43
shows the db2ocat tool GUI which is used to select tables that will be
accessible through the ODBC optimized catalog:
An ODBC optimized catalog consists of ten tables with the specified schema
name. If you specify OCAT as the schema name during the creation of the
ODBC optimized catalog, the following tables will be created:
• OCAT.TABLES
• OCAT.COLUMNS
• OCAT.SPECIALCOLUMNS
• OCAT.TSTATISTICS
• OCAT.PRIMARYKEYS
• OCAT.FOREIGNKEYS
• OCAT.TABLEPRIVILEGES
• OCAT.COLUMNTABLES
• OCAT.PROCEDURES
• OCAT.PROCEDURESCOLUMNS
These tables contain only the rows representing database objects you
selected and the columns required for ODBC/CLI operations. Moreover, the
tables are pre-formatted for the maximum ODBC performance. By using the
You can have multiple ODBC optimized catalogs for different clients. The
ODBC optimized catalog is pointed to by the CLISCHEMA keyword. If the
schema name of the ODBC optimized catalog is OCAT, then set CLISCHEMA=OCAT
in db2cli.ini file on the client. You can directly edit the db2cli.ini file or
execute the following command:
UPDATE CLI CFG FOR SECTION database1 USING CLISCHEMA OCAT
The readme file is available in the db2ocat.zip file at the same site.
Note
You need to use DB2 UDB Version 7.1 or later to convert ODBC/CLI
applications to static SQL applications.
These modes are specified using the STATICMODE keyword of the db2cli.ini file
as in the following example:
[SAMPLE]
STATICCAPFILE=/home/db2inst1/pkg1.txt
STATICPACKAGE=DB2INST1.ODBCPKG
STATICMODE=CAPTURE
DBALIAS=SAMPLE
You can directly edit the db2cli.ini file as shown above, or use the UPDATE CLI
CFG command as the following example (the captured text file is shown in
Figure 45).
[BINDOPTIONS]
COLLECTION=DB2INST1
PACKAGE=ODBCPKG
DEGREE=
FUNCPATH=
GENERIC=
OWNER=DB2INST1
QUALIFIER=DB2INST1
QUERYOPT=
TEXT=
[STATEMENT1]
SECTNO=
ISOLATION=CS
STMTTEXT=select DEPTNO,DEPTNAME,MGRNO,ADMRDEPT,LOCATION from DEPARTMENT
STMTTYPE=SELECT_CURSOR_WITHHOLD
CURSOR=SQLCURCAPCS1
OUTVAR1=CHAR,3,,FALSE,FALSE,DEPTNO
OUTVAR2=VARCHAR,29,,FALSE,FALSE,DEPTNAME
OUTVAR3=CHAR,6,,FALSE,TRUE,MGRNO
OUTVAR4=CHAR,3,,FALSE,FALSE,ADMRDEPT
OUTVAR5=CHAR,16,,FALSE,TRUE,LOCATION
Note
Although this captured file has only one SQL statement, you can have
more statements in a captured file.
If necessary, you can edit the captured file to change the bind options such as
QUALIFIER, OWNER, and FUNCPATH.
Then the db2cap bind command should be executed to create a package. The
captured file and the database name must be specified as the following
example:
db2cap bind /home/db2inst1 -d sample
The created package name have the suffix number depending on its isolation
level. The suffix for the package is one of the following:
• 0 = Uncommitted Read
In our example, only one package DB2INST1.ODBCPKG1 will be created, since our
example shown in Figure 45 has only one SQL statement using the isolation
level Cursor Stability. If the captured file has more than one statement and
their isolation levels are different, multiple packages will be created with
different suffixes.
You can have more than one captured file to create multiple packages in the
same database by executing the db2cap bind command for each captured file.
Be sure that the PACKAGE keyword of each captured file has a different value,
since it is used to determine the package name.
Lastly, you should distribute both the captured file and the application to all
client machines on which you intend to utilize the pre-bound package. On
each client, the STATICMODE keyword of the db2cli.ini file should be set as
MATCH, and the captured file should be specified using the STATICCAPFILE
keyword.
[SAMPLE]
STATICCAPFILE=/home/db2inst1/pkg1.txt
STATICMODE=MATCH
DBALIAS=SAMPLE
The greatest benefit of using Java, regardless of the database interface, is its
write once, run anywhere capability, allowing the same Java program to be
distributed and executed on various operating platforms in a heterogeneous
environment. And since the two Java database interfaces supported by DB2
are industry open standards, you have the added benefit of using your Java
program against a variety of database vendors.
With DB2 SQLJ support, you can build and run SQLJ programs that contain
static embedded SQL statements. Since your SQLJ program contains static
SQL, you need to perform steps similar to precompiling and binding. Before
you compile an SQLJ source file, you must translate it with the SQLJ
translator to create native Java source code. After translation, you can create
the DB2 packages using the DB2 for Java profile customizer ( db2profc).
Mechanisms contained within SQLJ rely on JDBC for many tasks, like
establishing connections.
Since SQLJ contains static SQL statements and their access plans are
determined before being executed, the same considerations as static
embedded SQL programs are applicable to SQLJ applications. See 7.3.1,
“Static SQL” on page 243.
7.6 Concurrency
When many users access the same database, you must establish some rules
for the reading, inserting, deleting, and updating of data records. The rules for
data access are set by each application connected to a DB2 database and
are established using locking mechanisms. Those rules are crucial to
guarantee the integrity of the data, but they may decrease concurrency on
database objects. On a system with much unnecessary locking, your
application may take a very long time to process queries due to lock-waiting,
even if the system is rich in hardware resources and well tuned. In this
section we will discuss how you can control concurrency appropriately and
minimize lock-waits to improve your application’s performance.
Be aware that you should commit a transaction even though the application
only reads rows. This is because shared locks are acquired in read-only
applications (except for the uncommitted read isolation level, which will be
discussed in the next section) and held until the application issues a COMMIT or
closes the cursor using the WITH RELEASE option (it will be discussed later in
this chapter).
Note
If you opened cursors declared using the WITH HOLD option, locks protecting
the current cursor position of them will not be released when a COMMIT is
performed. See the pages describing DECLARE CURSOR in the DB2 UDB SQL
Reference, SC09-2974 for the WITH HOLD option in detail.
Uncommitted Read transactions will hold very few locks. Thus they are not
likely to wait for other transaction to release locks. If you are accessing
read-only tables or it is acceptable for the application to retrieve uncommitted
data updated by another application, use this isolation level, because it is
most preferable in terms of performance.
Note
Dynamic SQL applications using this isolation level will acquire locks on
the system catalog tables.
When you want the maximum concurrency while seeing only committed data
from concurrent applications, this isolation level should be chosen.
Note
Remember that selected rows are locked until the end of the unit of work.
Therefore, do not forget to issue a COMMIT (or ROLLBACK) statement even if
your application is read-only. A COMMIT (or ROLLBACK) statement will terminate
the unit of work and release held locks.
If you are using the command line processor, you may change the isolation
level of the current session using the CHANGE ISOLATION command.
For DB2 Call Level Interface (DB2 CLI), you can use the SQLSetConnectAttr
function with the SQL_ATTR_TXN_ISOLATION attribute at run time. This will set the
transaction isolation level for the current connection referenced by the
ConnectionHandle. The accepted values are:
• SQL_TXN_READ_UNCOMMITTED : Uncommitted Read
• SQL_TXN_READ_COMMITTED : Cursor Stability
• SQL_TXN_REPEATABLE_READ : Read Stability
• SQL_TXN_SERIALIZABLE : Repeatable Read
You can also set the isolation level using the TXNISOLATION keyword of the DB2
CLI configuration as follows:
UPDATE CLI CFG FOR SECTION sample USING TXNISOLATION 1
You can use the DB2 CLI configuration for JDBC applications as well. If you
want to specify the isolation level within the JDBC application program, use
the setTransactionIsolation method of java.sql.Connection. The accepted
values are:
• TRANSACTION_READ_UNCOMMITTED : Uncommitted Read
• TRANSACTION_READ_COMMITTED : Cursor Stability
• TRANSACTION_REPEATABLE_READ : Read Stability
• TRANSACTION_SERIALIZABLE : Repeatable Read
This setting affects the instance level, and you need to stop and start the
database manager after changing the value.
If you look at your application using Read Stability or Repeatable Read, you
may find that all queries in the application do not need the protection which
Read Stability or Repeatable Read provides, that means, there may be
queries which can release locks before the end of the unit of work. For such
queries, use a CLOSE CURSOR statement that includes the WITH RELEASE clause
when closing the cursor.
CLOSE c1 WITH RELEASE
If the WITH RELEASE clause is specified, all read locks (if any) that have been
held for the cursor will be released. If it is not specified, held locks will not be
released until the unit of work ends.
The WITH RELEASE clause has no effect for cursors that are operating under the
CS or UR isolation levels. When specified for cursors operating under RS or
RR isolation levels, the WITH RELEASE clause ends some of the guarantees of
those isolation levels, because all read locks will be released before the end
of the unit of work. An RS and an RR cursor may experience the
nonrepeatable read phenomenon, which means that if you open a cursor,
fetch rows, close the cursor with WITH RELEASE clause, reopen the cursor, and
fetch rows again, then the second query can retrieve the different answer set
as the first because other applications can update the rows that match to the
query. An RR cursor may experience the phantom read phenomenon as well.
After closing the cursor with the WITH RELEASE clause, the second query can
Each lock requires 72 bytes of memory for an object that has no other locks
held on it, or 36 bytes of memory for an object that has existing locks held on
it. If a number of row locks can be replaced with a single table lock, the
locking storage area can be used by other applications.
When DB2 converts the row locks to a table lock on your behalf, this is called
lock escalation. DB2 will perform lock escalation to avoid resource problems
by too many resources being held for the individual locks.
Also note that the isolation level used by the application has an effect on lock
escalation:
• Cursor Stability will acquire row level locks initially. If required, table level
locks can be obtained in such a case as updating many rows in a table.
Usually, a very small number of locks are acquired by each cursor stability
Once the lock list is full, performance can degrade, since lock escalation will
generate more table locks and fewer row locks, thus reducing concurrency on
shared objects in the database. Your application will receive an SQLCODE of
-912 when the maximum number of lock requests has been reached for the
database.
If you have no idea of the average number of locks per application, execute
an application and monitor the number of held locks at the application level
using the Snapshot Monitor. To get the number of locks held by a particular
application, execute the Snapshot Monitor as in the following example:
GET SNAPSHOT FOR LOCKS FOR APPLICATION AGENTID 15
In this example, 15 is the application handle number, which you can obtain
using the LIST APPLICATIONS command.
See Chapter 5, “Monitoring tools and utilities” on page 119 for detailed
information about the database system monitor including the Snapshot
Monitor and Event Monitor.
Then perform the following steps to determine the size of your lock list:
• Calculate a lower and an upper bound for the size of your lock list using
the following formula:
(Average number of locks per application * 36 * maxappls) / 4096
(Average number of locks per application * 72 * maxappls) / 4096
In the formula above, 36 is the number of bytes required for each lock
against an object that has an existing lock, and 72 is the number of bytes
required for the first lock against an object.
• Estimate the amount of concurrency you will have against your data, and
based on your expectations, choose an initial value for the LOCKLIST
parameter that falls between the upper and lower bounds that you have
calculated.
When setting MAXLOCKS, you should consider the size of the lock list (LOCKLIST)
and how many locks you will allow an application to hold before a lock
escalation occurs. If you will allow any application to hold twice the average
number of locks, the value of the MAXLOCKS would be calculated as following:
100 * (average number of locks per application * 2 * 72 bytes per locks)
/ (lock list * 4096 bytes)
You can increase MAXLOCKS if few applications run concurrently, since there will
not be a lot of contention for the lock list space in this situation.
Once you have set the LOCKLIST and MAXLOCKS database configuration
parameters, you can use the Snapshot Monitor and Event Monitor to validate
or adjust the value of the values of these parameters. Here are the monitor
elements which you should be interested in:
• Maximum number of locks held by a given transaction
• Total lock list memory in use
• Number of lock escalations that have occurred
You can check the maximum number of locks held by a given transaction
using the Event Monitor. You need to create an event monitor to get
transaction events to get this information. This information can help you to
determine if your application is approaching the maximum number of locks
To check the total lock list memory in use, you should use the Snapshot
Monitor at the database level. If you notice that the monitored value is getting
closer to the lock list size, consider increasing the value of the LOCKLIST
parameter. Note that the LOCKLIST configuration parameter is allocated in
pages of 4K bytes each, while this monitored value is in bytes.
To check the number of lock escalations that have occurred, you can use the
Snapshot Monitor at database level. If you observe many lock escalations,
you should increase the value of the LOCKLIST and/or the MAXLOCKS parameters.
See Chapter 5, “Monitoring tools and utilities” on page 119 for detailed
information about the Event Monitor and Snapshot Monitor.
To ensure that the waiting application can continue without needed to wait
indefinitely, the LOCKTIMEOUT database configuration parameter can be set to
define the length of the time-out period. The value is specified in seconds. By
default, the lock time-out is disabled (set to a value of -1). This means the
waiting application will not receive a time-out and wait indefinitely.
This command should be executed by the instance owner, and you need to
stop/start the database manager to make this change effective. If you set
DB2LOCK_TO_RB=STATEMENT, lock time-outs cause only the current statement to
be rolled back.
In this situation, both A and B will wait indefinitely for each other’s locks, until
an external event causes one or both of them to roll back.
DB2 uses a background process, called the deadlock detector, to check for
deadlocks. The process is activated periodically as determined by the
DLCHKTIME parameter in the database configuration file. When activated, it
checks the lock system for deadlocks.
When the deadlock detector finds a deadlock situation, one of the deadlocked
applications will receive an error code and the current unit of work for that
application will be rolled back automatically by DB2. When the rollback is
complete, the locks held by this chosen application are released, thereby
allowing other applications to continue.
To monitor deadlocks, you can use the Snapshot Monitor at the database
level as well as the application level.
Data and information are the lifeblood of every organization. With the
increasing presence of the Internet, e-business solutions, business
automation, and data warehousing demands, continuous data availability is
now a requirement. When business processes are affected by an outage, it is
very critical to be able to define both a recovery point and recovery time
objectives to specify how fast we need to recover data and how recent the
data will be. Whenever an outage occurs, we must recover quickly to a point
at which usable data is available.
In the art of performance tuning, the objective is usually to keep the output
device busy (for example, tape). As long as the buffers are being filled as
quickly as they can be written to the device, then we have done well.
8.1.1.1 TO dir/dev
The target directory and devices must reside on the database server. This
parameter is repeated to specify the target directories and devices that the
backup image will span across. If more than one target is specified (for
example bkup_dir1, bkup_dir2, and bkup_dir3), then bkup_dir1 is opened first,
and the media header and special files are placed along with the
configuration file, table space table, and history file. All the remaining targets
are opened, and are then used in parallel during backup, thereby increasing
the performance and reducing the time for overall backup operation.
In order to take a backup quickly for large databases, when you have only a
few tape devices, it is preferable to back up the database on multiple target
directories on multiple disks or on different mounted volumes. Then this can
be moved to tape at the earliest convenient time.
BACKUP DATABASE sample TO /bkup_dir1,/bkup_dir2,/bkup_dir3
For a user on most versions of Linux, using DB2's default buffer sizes for
backup and restore to a SCSI tape device results in the error “SQL2025N,
reason code 75”. To prevent the overflow of Linux internal SCSI buffers, use
the following formula to determine the appropriate buffer size:
Bufferpages <= ST_MAX_BUFFERS * ST_BUFFER_BLOCKS / 4
ST_MAX_BUFFERS and ST_BUFFER_BLOCKS are defined in the Linux kernel under the
drivers/scsi directory.
and
(num-buffers * buffer-size) < UTIL_HEAP_SZ
If you use a variable block size with your tape devices, ensure that the DB2
buffer size is either less than or equal to the maximum variable block size for
which the device is configured. After choosing the configuration, make sure to
test both backup and restore with those settings. Otherwise, the backup will
succeed, but the resulting image may not be guaranteed to be recoverable.
8.1.1.4 PARALLELISM n
Using this parameter, we can dramatically reduce the time required to
complete the backup. This parameter defines the number (n) of processes
that are started to read data from the database. Each process is assigned to
backup a specific table space. When it completes backing up the table space,
it requests another. Each process will be assigned a table space to complete,
therefore, to get better performance, let this value be less than the number of
table spaces; since setting up the value higher than the number of table
spaces does not show any significant difference in performance. However,
each process requires both memory and CPU overhead; for a heavily loaded
system, you should leave this parameter at its default value of 1.
Note
Tips
It is recommended to have the following values set:
util_heap_sz > 2* (backbufsiz + restbufsiz
8.1.2.2 DB2_DISABLE_FLUSH_LOG
Though this registry variable does not result in a direct performance impact, it
provides an option to disable the inclusion of the last active log file in any
on-line backups. When an on-line backup completes, the last active log file is
truncated, closed, and archived as part of the backup. This behavior gives us
a complete backup, including all of the logs required for the restoring of that
backup.
For a detailed description, please refer to 3.5.7, “Flushing logs during on-line
backup” on page 81.
8.1.3 DB2CHKBP
It is always important to ensure that the backup images are restorable. The
db2chkbp utility helps to test the integrity of a backup image and determine
whether or not it can be restored. If the backup was created using multiple
sessions, db2ckbkp can examine all of the files at the same time. Users are
responsible for ensuring that the session with sequence number 001 is the
first file specified. This utility also verifies backup images on tape.
8.1.5 DB2LOOK
It is recommended to have all the DDL statements to reproduce the database
objects of a production database. The db2look tool extracts the required DDL
and also generates the required UPDATE statements used to replicate the
current statistics on the objects in test database, updates database
configuration, and updates database manager configuration parameters and
db2set statements, so that the registry variables and configuration parameter
settings on the test database match those of the production database. With
this tool, we can make a test system containing a subset of the production
system’s data, where access plans are similar to those that would be used on
the production system. Thus, without affecting the production system, we can
try to test performance measurements in the test system.
The exported data can then be imported or loaded into another DB2
database, using the IMPORT or the LOAD utility, respectively; or it can be
imported into another application (for example, a spreadsheet)
Also, check for restrictions for EXPORT in Data Movement Utilities Guide and
Reference, SC09-2955.
Note
When using IXF, Version 7 tables with a schema name greater than 8
characters cannot be imported or exported with pre-Version 7 code
because of truncation occurs
For additional information on file formats, please see the Data Movement
Utilities Guide and Reference, SC09-2955.
The EXPORT utility is an embedded SQL application and does SQL fetches
internally. This means that all optimizations on those SQL operations apply
for export too (for example, a large buffer pool size). Changes on the server
side that improve fetch performance can have a larger impact.
Note
Do not set the agent pool size (NUM_POOLAGENTS) to zero. If the agent
pool size is zero, an agent process will be generated and terminated
repeatedly for each row, and will impact on the import performance
significantly.
Before invoking the IMPORT utility, you must be connected to (or able to
perform an implicit connect to) the database into which the data will be
imported. Since the utility will acquire a table level exclusive lock, you should
complete all transactions and release all locks on the target table. You can
invoke the IMPORT utility either from Command Line Processor (CLP) or from
Control Center.
Also, check for Restrictions and limitations for Import in the Data Movement
Utilities Guide and Reference, SC09-2955.
The IMPORT utility creates two temporary files, one for data, and the other for
messages generated. These temporary files are located in the tmp
subdirectory under the sqllib directory or the directory indicated by the
DB2INSTPROF registry variable.
CONNECT TO SAMPLE
IMPORT FROM myfile OF IXF MODIFIED BY COMPOUND=100 INSERT INTO mytable
The above IMPORT command will wait for the SQL return code about the insert
results after inserting 100 records, instead of inserting each record.
See the Data Movement Utilities Guide and Reference, SC09-2955 for more
information.
8.3.3 COMMITCOUNT n
By default, with no COMMITCOUNT specified, an IMPORT will issue a commit at the
end of a successful IMPORT. Requesting periodic COMMITs reduces the number
of rows that are lost if a failure occurs during the import operation. It also
prevents the DB2 logs from getting full when processing a large input file.
The log full condition is possible with both circular and archival logging. In the
case of circular logging, if an open transaction holds the first log file, when
other transactions use the last defined log file, they cannot continue by
writing over the first. Similarly, archival logging cannot have more than the
maximum number ( LOGPRIMARY + LOGSECOND) of defined active log files. Until the
first log file in the sequence of active log files is released, the next one cannot
be created.
You should have LOAD authority to run the LOAD utility without the need for
SYSADM or DBADM authority. This gives database administrators more
granular control over the administration of their database. See the Data
Movement Utilities Guide and Reference, SC09-2955 for more information.
Since all load processes are owned by the instance owner, the instance
owner must have read access to input data files. These input data files must
be readable by the instance owner, regardless of who invokes the LOAD utility.
Also, check for Restrictions and Limitations for LOAD in Data Movement
Utilities Guide and Reference, SC09-2955.
The LOAD utility is faster than the IMPORT utility for bulk data, because it writes
formatted pages directly into the database, while the import utility performs
SQL inserts. The LOAD utility can take advantage of intra-partition parallelism
and I/O parallelism. Loading data is a heavily CPU-intensive task. The LOAD
utility takes advantage of multiple processors for tasks such as parsing and
formatting data. Also, the LOAD utility can use parallel I/O servers to write the
data to the containers in parallel.
Note
Since the LOAD utility does not check any constraints defined on the table
(such as check constraints and referential constraints) except unique
constraints, you need to execute a SET INTEGRITY statement after the
loading to make the table usable. If all the load operations are performed in
INSERT mode, the SET INTEGRITY statement will check the table for constraint
violations incrementally, by checking only the appended portion of the
table.
Using the LOAD utility is a very efficient way to insert data, for the following
reasons:
• Data I/O is performed only once for all three phases.
• In case of index creation, LOAD uses a heavily optimized sort routine which
is considerably faster than the generic sort routine of the DBMS.
Note
In Version 7, SORT BUFFER and temporary sorting directories for LOAD are now
obsolete. LOAD uses a sort heap for sorting, and performs I/O in temporary
table spaces.
Since the LOAD utility will lock the table spaces to which the table belongs, you
should complete all transactions and release all locks by performing a COMMIT
or ROLLBACK.
The Version 7 LOAD utility can load data residing on a remotely connected
client, by specifying the CLIENT parameter. Data residing on the server may be
in the form of a file, tape, or named pipe. Data residing on a remotely
connected client may be in the form of a fully qualified file or named pipe.
This CLIENT option is ignored if the load operation is not being invoked from a
remote client. Separate files containing LOB values, when the lobsinfile file
type modifier is specified, should be located on the server. Also, if the CLIENT
option is specified, the path must be fully qualified.
8.4.1.1 SAVECOUNT n
This parameter value represents the interval, in number of rows, between
consistency points. During the LOAD process, after every n rows are loaded, a
consistency point will be established. Table objects like long field, LOB, BLOB
are stored in table spaces. I/O to each table space is performed in extents
and the extent size is measured in 4K pages, specified during table space
creation parameter. LOAD builds extents for each table object in the
appropriate form, converts into page count, and rounded up to intervals of
extents size and writes the resulting pages to disk.
8.4.1.4 CPU_PARALLELISM n
This parameter value specifies the number of processes that the load utility
will spawn for parsing, converting, and formatting data records, while building
the table data objects. If your machine has the capability, this parameter will
exploit intra-partition parallelism and significantly improve load performance.
This parameter can be used in non-SMP environments also, but performance
benefit is not perceptible.
CPU parallelism does not lose data set order, that is, the data provided in a
sequence a, b, c, d will be loaded in parallel, but will arrive on disk in the
identical order a, b, c, d.
Although you can specify a maximum value of 30, the utility adjusts the value
if there is insufficient memory. If the value of this parameter is zero, or has not
been specified, the load utility uses an intelligent default value, usually based
on the number of CPUs available, at run time. It is highly recommended not to
specify this parameter, so that DB2 will allocate the best value.
Note
Parallelism is not supported in cases where tables include LOB or LONG
VARCHAR data.
8.4.1.5 DISK_PARALLELISM n
This parameter values specifies the number of processes used by the load
utility to write data records to disk. Use this parameter to exploit available
containers when loading data, and get significant improvement in load
performance. The maximum number allowed is the greater of four times the
CPU_PARALLELISM value (used by the LOAD utility), or 50. If the value of this
parameter is zero, or has not been specified, the load utility uses intelligent
default value based on the number of table space containers and the
characteristics of the table. It is highly recommended not to specify this
parameter, so the LOAD utility will use an intelligent default value.
FASTPARSE
The modifier FASTPARSE will reduce the syntax checking and data checking that
is performed on user-supplied column values, and enhance performance.
Though this option performs sufficient data checking to prevent a
segmentation violation or trap, this option should be used only when the data
being loaded is known to be valid and architecturally correct, since FASTPARSE
assumes that your data is clean and yields a performance gain when
CPU-bound.
This increases performance more on ASCII data than on PC/IXF data, since
IXF is a binary format, and FASTPARSE affects parsing and conversion from
ASCII to internal forms. Data that is in correct form will be loaded correctly
and care must be taken to use this modifier with clean data only. If you have
confidence that your data is clean, use this option for additional performance
gains, especially with character data files (DEL and ASC).
Note
This option is not supported if SAVECOUNT > 0, since the recovery process
after a consistent point requires that data to be loaded in sequence. When
SAVECOUNT > 0, avoid using the ROWCOUNT option along with ANYORDER, because
which row(s) get loaded cannot be guaranteed
BINARYNUMERICS
Use this type of file-type modifier only when loading positional numeric ASC
(non-delimited ASCII) data into fixed length records specified by the RECLEN
option ( NOEOFCHAR is assumed). When numeric ( INT, REAL, FLOAT, and not
DECIMAL) data be in binary form and not in the character representation,
avoids costly conversions, thereby providing a performance gain. Use IXF or
positional ASCII with BINARYNUMERICS whenever possible, since binary data
loads much faster than text data.
Note
NULLs cannot be present in the data for columns affected by this modifier.
Blanks are interpreted as binary value when this modifier is used.
Apart from tuning LOAD, it is recommended to tune job stream also. Thus,
when you consider the end-to-end time to get the table populated and ready
for access, it is recommended to combine index creation, and RUNSTATS with
your load. With a single pass through the data, you can create an index,
collect statistics, and make the table available for queries (single I/O against
many operations).
Once the statistics are updated, applications can use new access paths to
the table data from the latest statistics. However, new access paths to the
table can be created by rebinding the application packages using the REBIND
command.
When distribution statistics are being gathered or when loading data into
large tables, it is recommended to have a larger value for the database
configuration parameter Statistics Heap Size ( STAT_HEAP_SZ). For more
information about STAT_HEAP_SZ, see Database Parameters, in the
Adminstration Guide: Performance, SC09-2945.
8.4.1.8 NONRECOVERABLE
This parameter can improve the load performance when forward recovery is
enabled ( LOGRETAIN or USEREXIT is ON) . Use this parameter if you do not need
to recover load transactions against a table. Many users do not want certain
loaded tables to be recoverable because the data is transient (replaced
frequently). When LOGRETAIN or USEREXIT is ON, performing a load operation
without the COPY YES option will bring the table space into backup pending
state; however, using the NONRECOVERABLE option completes the load operation
without leaving the table spaces in backup pending state. This load is
non-recoverable, although the database has LOGRETAIN and USEREXIT ON, and
a copy of the loaded data does not have to be made during the load
operation.
For information about when the above modes can be used, see Chapter 3:
LOAD in the Data Movement Utilities Guide and Reference, SC09-2955.
8.4.2.1 SORTHEAP
This parameter defines the maximum number of private memory pages used
for private sorts, or the maximum number of shared memory pages to be
used for shared sorts. If the sort is a private sort (this is what LOAD uses), then
this parameter affects the agent private memory. If the sort is a shared sort,
then this parameter affects the database global memory. This sort heap is the
area where data is sorted.
When the total amount of instance-wide memory allocated for private sorts
exceeds SHEAPTHRES, then subsequent sorts will try to allocate fewer than
SORTHEAP pages of memory. SHEAPTHRES should be set to some reasonable
multiple of SORTHEAP.
Sort overflows (or sort-spill) are sorts that ran out of sort heap and required
disk space for temporary storage. That is, the data is divided for several sort
runs and stored in a temporary table space that will be merged later. These
sorts are not efficient, and when this value is consistently high for a number
of intervals, then it may be necessary to increase the SORTHEAP configuration
parameter. If the sort spill occurs even after increasing the SORTHEAP
parameter, make the buffer pool for temporary table space large enough to
minimize the amount of disk I/O.
To set the sheapthres value to 32768 (or whatever value you desire):
DB2 UPDATE DBM CFG USING sheapthres 32768
To set the sortheap value to 8192; try this, using 8192 of 4K pages for sorting
each index:
DB2 UPDATE DB CFG FOR <dbname> USING sortheap 8192
In terms of performance, the higher the value of SORTHEAP, the less likely a
sort-spill will be and you will get better performance due to reduced I/O.
8.4.2.2 SHEAPTHRES
This performance variable sort heap threshold (sheapthres), is used to tune
the database manager configuration. This controls the total amount of
memory for sorting across the entire instance for all sorts. On the first
connect we calculate the total size of the database shared memory set, which
includes BUFFERPOOLS, UTILHEAPSZ, SHEAPTHRES, PACKAGE CACHE, and LOCKLIST. The
database shared memory set cannot be dynamically modified, that is, you
must terminate all connections to the database and reconnect.
Please see 6.4.1, “Sorting methods” on page 201 for more information.
Note
Since the LOAD utility preserves the order of the input file and does not
consider the cluster factor, when load data into a table with a clustered index,
you should:
• Use the IMPORT utility instead of the LOAD utility.
• If you are performing the LOAD in REPLACE mode (or loading into a new
table), pre-sort the input file and execute the LOAD command without the
ANYORDER option.
• If you are performing the LOAD in APPEND mode, execute the REORG TABLE
command after the load.
You can restore backup images which are produced by previous versions
(V2.x or higher) of DB2, in case migration is required, it will be issued
automatically at the end of restore. If you are using the Control Center, then
you cannot restore backups that were taken in previous versions of DB2.
The database to which you restore the data may be the same one as the data
was originally backed up from, or it may be different (in addition to being able
to restore to a new database). If, at the time of backup operation, the
database was enabled for roll-forward recovery, the database can be brought
to the state that it was in, prior to the occurrence of the damage or corruption,
by issuing ROLLFORWARD DATABASE after successful execution of RESTORE
DATABASE.
You can select a type at the time of restore, from three types:
1. A full restore of everything from the backup.
2. A restore of only the recovery history file.
3. A subset of the table spaces in the backup.
Tips
The number of buffers to allocate should be #sessions +#parallelism +2
and (num-buffers * buffer-size) < util_heap_sz.
Note
We recommend setting the restore buffer size to a multiple of the extent size;
however, the value you specify must be equal or a multiple of the backup
buffer size that you specified when the backup image was taken. Otherwise,
the smallest acceptable size of the buffer (4KB) is used for the restore buffer.
If you do not specify the number of pages, each buffer will be allocated based
on the database manager configuration parameter RESTBUFSZ.
You can also specify the number of the restore buffer. When restring from
multiple locations using multiple sessions of TSM or multiple local devices, a
larger number of buffers may be used to improve performance.
and
(num-buffers * buffer-size) < UTIL_HEAP_SZ
Note
When you set the number and size of the restore buffer, try to use more
buffers of smaller size rather than a few large buffers.
Tips
It is recommended to have the following values set:
util_heap_sz > 2* (backbufsiz + restbufsiz)
To identify the performance problem, ask your users, who should be able to
tell you which operations of an application are suffering from performance
problems. This will help you determine exactly when to monitor your system
in order to isolate the problem. Alternatively, you may want to perform a
general analysis of your system to try to isolate possible bottlenecks during
peak periods.
After the problem is reproduced or identified, it will fall into one of two groups:
1. Problems affecting one application or a group of applications:
Problems that affect a single application or a group of applications can be
further subdivided into two categories:
- Applications that have had a good performance history in a
development or testing environment, but do not perform as expected
when working against production databases. Working against low
volumes of data may hide problems. Some of the non-detected
problems may be those associated with casting, lack of indexes, joins,
sorts, access plans, isolation levels, or size of the answer set.
- Applications whose behavior is erratic. These applications may usually
have good response times, but under certain conditions, their response
times are very degraded. These applications may have
concurrence-related problems: deadlocks, waits, and so on.
Once you have found that most of the elapsed time is spent in DB2, then you
should analyze the SQL statements issued in the application. Pick up the
most time-consuming SQL statements from the dynamic SQL Snapshot
Monitor (for dynamic SQL) or from the Statements Event Monitor (for both
dynamic and static SQL), then analyze these SQL statements using the
following two basic procedures:
• Explaining the statements
• Monitoring the application/database
The access plan provides information not only about the work that the
database manager has to perform, but also how the work will be done.
Run custom queries to get information about your Explain plans and check
the following:
1. Search for SORT, or GROUP BY operators on sets of columns and base
tables that occur frequently, which could be beneficial as an index or
summary tables.
2. Search for expensive operations, such as large or spilling sorts, high
buffer usage, or high table queue usage.
3. Search for expensive plans to further examine for database optimizations.
4. Search for common predicates that could form potential start/stop keys for
an index.
5. Check for missed index opportunities.
6. Look for any other better join opportunities.
7. Search for poor predicate selectivities due to insufficient statistics.
8. Search for FETCH used because an index could use INCLUDE columns.
9. Search for I/O increase during SORT (using vmstat or iostat).
If you are not satisfied with the access plan being shown, you can obtain
different access plans for different levels of optimization (see 7.3.2.3, “Tune
optimization level” on page 248) without needing to execute the statement.
The steps of an access plan and its description are presented in Description
of db2expln and dynexpln Output in the Administration Guide: Performance,
SC09-2945.
Data elements whose values are collected when monitoring the application
include: deadlocks; lock escalations; lock waits and lock wait time; index and
data reads and writes; number of sorts and sort time; and the package cache
hit ratio.
Define a method for resolving problems, and use it consistently. Here are
some guidelines for establishing a problem-determination method:
• Choose the monitoring tool.
• Define the period of time and the environment in which the database will
be monitored.
• Start monitoring the database
• Obtain the results of the monitoring tool.
When a database is monitored, a large set of values for data elements may
be collected. Some values may point directly to the cause of a problem, but
that is not always the case. Table 12 shows some of the data elements that
can be collected, their related configuration parameters and the problems
caused by incorrect configuration values. The table is only an example and is
not intended as a complete listing for problem determination. Many of the
data elements collected will relate directly to configuration parameters. When
using the performance monitor, is it possible through the online help to
identify which configuration parameter relates to the data elements.
Table 12. Data elements and configuration problems
The best way to evaluate if there are “too many” overflows, time-outs, or
waits is to compare results to previous results or a similar environment. When
possible, results should be compared to those obtained when the database
did not have a performance problem.
Data elements can be grouped to obtain ratios. Ratios are presented by the
performance monitor or can be calculated by the database administrator. The
manual, System Monitor Guide and Reference, SC09-2956 contains a
description of all the data elements for which information can be collected
and how to calculate ratios using the different elements. An example of these
ratios and their relationship to configuration parameters is shown in Table 13.
Buffer Pool Hit Ratio Specified buffer pool size If too low, prefetchers not
(CREATE BUFFERPOOL working, buffer pool too
or ALETER small.
BUFFERPOOL)
Buffer Pool Index Hit Ratio Specified buffer pool size If too low, prefetchers not
(CREATE BUFFERPOOL working, buffer pool too
or ALTER BUFFERPOOL) small.
Operating system tools indicating I/O contention may point to problems with
the physical design of the database, such as placement of containers across
physical drives, or containers allocated to table spaces (see Chapter 3, “Data
storage management for performance” on page 31).
L_ORDERKEY FLOAT 8
L_PARTKEY INTEGER 4
L_SUPPKEY INTEGER 4
L_LINENUMBER INTEGER 4
L_QUANTITY FLOAT 8
L_EXTENDEDPRICE FLOAT 8
L_DISCOUNT FLOAT 8
L_TAX FLOAT 8
L_RETURNFLAG CHAR 1
L_LINESTATUS CHAR 1
L_SHIPDATE DATE 4
L_COMMITDATE DATE 4
L_RECEIPTDATE DATE 4
L_SHIPINSTRUCT CHAR 25
L_SHIPMODE CHAR 10
L_COMMENT VARCHAR 44
O_ORDERKEY FLOAT 8
O_CUSTKEY INTEGER 4
O_ORDERSTATUS CHAR 1
O_TOTALPRICE FLOAT 8
O_ORDERDATE DATE 4
O_ORDERPRIORITY CHAR 15
O_CLERK CHAR 15
O_SHIPPRIORITY INTEGER 4
O_COMMENT CHAR 79
The LINEITEM table has 6001215 rows and the ORDERS table has 1500000 rows.
Using the following select statement, we show how we could improve the
performance:
In this case study, we set 10 seconds of the elapsed time as the performance
tuning goal.
To execute the select statement, we used the db2batch tool with PERF_DETAIL
level 5 (see 5.4.5, “The db2batch utility” on page 173) so that we could get a
snapshot for the database manager, database, and this query statement. We
also used the dynamic Explain tool ( dynexpln) with the -g option to get the
section information and the access plan graph of the query.
The page size of the table space for the LINEITEM and ORDERS was 8 KB,
therefore, the page size of the buffer pool for this table space was also 8 KB.
This buffer pool was called TPCDATABP in this case study.
The SYSCATSPACE used the buffer pool IBMDEFAULTBP. . The page size of
IBMDEFAULTBP was 4 KB.
Note
Normally you should not use the default values. You should use the
Configure Performance Wizard to obtain recommended values for your
environment instead
The following is the package information from the dynamic Explain output:
Package Name = TETSUR3.DYNEXPLN
Prep Date = 2000/07/07
Prep Time = 12:55:57
Partition Parallel = No
Intra-Partition Parallel = No
Function Path = "SYSIBM", "SYSFUN", "TETSUR3"
Note that the partition parallelism is NO, which is the default value.
Here is the access plan graph section information from the Explain output:
RETURN
( 1)
|
GRPBY
( 2)
|
TBSCAN
( 3)
|
End of section
End of section
As you can see in this output, the performance was improved (from 216.471
sec. to 133.157 sec.); however, actually we saw that excessive activities to
the paging space were occurring during the query was processed. The
following is a vmstats report at that time:
kthr memory page faults cpu
----- ----------- ------------------------ ------------ -----------
r b avm fre re pi po fr sr cy in sy cs us sy id wa
0 0 268029 110 0 0 0 3 22 0 107 83 23 1 0 97 1
1 0 271706 119 0 2 538 740 13649 0 650 549 520 18 24 36 22
1 1 273093 125 0 36 277 314 368 0 572 540 477 12 21 28 39
1 1 273191 127 0 58 72 78 93 0 726 652 829 30 7 42 21
1 1 274158 0 0 33 168 210 296 0 647 601 687 20 15 37 29
1 1 275092 127 0 101 262 305 450 0 680 416 659 23 6 47 24
2 1 275092 122 0 8 7 9 18 0 825 768 1043 47 3 31 19
2 1 275092 123 0 0 4 5 10 0 829 775 1061 50 3 30 17
Excessive activities to the paging space normally cause I/O bottleneck and
impact on the overall system performance. One of the common causes of this
situation is setting too big buffer pools (or other memory areas).
In our case study, we set the recommended values for each buffer pool size
as well as the database manager and the database configuration parameters.
Probably the Configure Performance Wizard had suggested too big values for
some parameters and therefore this excessive paging activity was occurred.
The access plan was not changed by this modification though, reducing the
size of IBMDEFAULTBP improved the performance (from 133.157 sec. to 111.762
sec.) as the following db2batch output (partial) shows:
Elapsed Time is: 111.762 seconds
:
:
Sort heap allocated = 0
Total sorts = 6
Total sort time (ms) = 109099
Sort overflows = 2
Active sorts = 0
:
:
Bufferpool Name = IBMDEFAULTBP
:
Buffer pool data logical reads = 221
Buffer pool data physical reads = 25
Buffer pool data writes = 1
Buffer pool index logical reads = 45
Buffer pool index physical reads = 7
Buffer pool index writes = 0
Total buffer pool read time (ms) = 2
Total buffer pool write time (ms) = 23
:
:
Bufferpool Name = TPCDATABP
:
Buffer pool data logical reads = 229689
Buffer pool data physical reads = 121194
Buffer pool data writes = 0
Buffer pool index logical reads = 0
Buffer pool index physical reads = 0
Buffer pool index writes = 0
Total buffer pool read time (ms) = 52119
Total buffer pool write time (ms) = 0
:
As you can see in the db2batch output, the total sort time was very big
(109099 ms). Thus, we decided take the first option, which is creating new
indexes to avoid heavy sort operations.
After creating indexes, you must not forget to execute a RUNSTATS command.
RUNSTATS ON TABLE db2inst1.orders AND DETAILED INDEXES ALL
Then we executed the dynamic Explain tool again and saw whether the
different access plan would be taken.
End of section
From the Explain and db2batch tools output, you can see that:
• Many buffer pool physical reads were required
• Entire rows of the ORDERS table were scanned
End of section
As you can see above, the access plan was not changed by increasing the
buffer pool size.
In the db2batch output, you can see that the buffer pool data physical reads
were not decreased and the performance was not improved.
We also tested the same query using the db2batch tool after increasing the
size of the buffer pool TCPDATABP from 90000 pages to 100000 pages;
however, that resulted in worse performance due to an excessive activity on
the paging space.
In the query we used in this case study, you can see a predicate "WHERE
O_ORDERDATE >= ’01/01’98’". We created an index called O_OD on the
O_ORDERDATE column to satisfy the predicate:
CREATE INDEX O_OD on ORDERS (O_ORDERDATE)
You should not forget to execute a RUNSTATS command after creating new
indexes.
RUNSTATS ON TABLE db2inst1.orders AND DETAILED INDEXES ALL
In the db2batch output, you can see that the performance was not improved
very much (from 15.232 sec. to 14.810 sec.).
To increase the cluster ratio, you can reorganize the table using a REORG TABLE
command.
Index statistics:
You can see that the cluster ratio (F4) of O_OD is very low (2%). To increase
the cluster ratio, we reorganized the ORDERS table using the following
command:
REORG TABLE db2inst1.orders INDEX db2inst1.o_od
End of section
As the db2batch output shows, the performance goal we had set was finally
achieved and we decided to stop tuning the database.
We have written some useful shell scripts to maintain monitored data. These
scripts call the Operating System commands or DB2 UDB Monitoring Tools,
format the outputs, and save them into the directory structure that we
discussed in Chapter 4, “Database design” on page 85.
You can use these sample shell scripts for your environment, or modify them
for your own purpose. The source of each sample script can be found on the
companion diskette.
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" -d dbname [-p \"params\"] [-o N] [-v] [-b]
Execute db2look tool to extract database definitions into an executable script
which can be used to restore the definitions.
-c: Comment placed on first line of Summary output file (required)
-d: Database name (required)
-p: db2look parameters (default=\"${DB2LOOK_PARAMS}\")
-o: Save output in dir N under \$RESULTS
(0=Current dir,default; -1=Not Valid)
-v: Verbose (default is NOT to display db2look script)
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Value for -d is part of output filename.
"
}
# Constants
RESULTS=~/states
RESULTS_FILE=`basename $0 .ksh`
RES_EXT=".sql"
# Defaults
QUIET=1
DB_NAME=""
RESULTS_DIR=0# 0 defaults to current dir
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
DB2LOOK_PARAMS="-m -l -a -x -e -f"
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
if [ $RESULTS_DIR -gt 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
RES_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${RES_EXT}.$$
else
RES_OUT=${RESULTS_FILE}${RES_EXT}
fi
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak2>/dev/null
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
fi
fi
# BEGIN .......
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" [-d dbname] [-o N] [-v] [-r] [-b]
Create an SQL script which can be used to restore the current settings of the
DBM CFG or DB CFG.
-c: Comment placed on first line of Summary output file (required)
-d: Database name, indicates to use DB CFG (default is DBM CFG)
-o: Save output in dir N under \$RESULTS
(0=Current dir,default; -1=Not Valid)
-v: Verbose (default is NOT to display generated SQL script)
-r: Don't get DB/M CFG, reuse existing output file
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Output of DB/M CFG also saved in -o directory.
Value for -d is part of output filename and generated script filename.
"
}
# Constants
# Defaults
QUIET=1
DB_NAME=""
RESULTS_DIR=0# 0 defaults to current dir
REUSE_OUT=0
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
if [ "$DB_NAME" != "" ]
then
DB_NAME=`echo $DB_NAME | tr [a-z] [A-Z]`
RESULTS_FILE="db_cfg"
RES_EXT="_${DB_NAME}${RES_EXT}"
SUM_EXT="_${DB_NAME}${SUM_EXT}"
fi
if [ $RESULTS_DIR -gt 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${SUM_EXT}
RES_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${RES_EXT}.$$
SUM_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${SUM_EXT}.$$
else
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak2>/dev/null
[ $REUSE_OUT -eq 0 ] && \
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
cp $SUM_OUT $SUM_BAK 2>/dev/null && echo "[Created: $SUM_BAK]"
fi
fi
# BEGIN .......
if [ $REUSE_OUT -eq 0 ]
then
echo "[Creating: $RES_OUT]"
echo ""
if [ "$DB_NAME" = "" ]
then
eval echo "-- db2 get dbm cfg"$Q_OUTPUT
db2 get dbm cfg > $RES_OUT
else
eval echo "-- db2 get db cfg for $DB_NAME" $Q_OUTPUT
db2 get db cfg for $DB_NAME> $RES_OUT
fi
else
echo "[Reusing: $RES_OUT]"
fi
BEGIN{once = 0 ; set_NEWLOGPATH=0 }
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" -d dbname [-o N] [-f] [-s N] [-sql]
[-t] [-w] [-q] [-r] [-b]
Summerize the Statement statistics captured by the Dynamic SQL Snapshot.
-c: Comment placed on first line of Summary output file (required)
-d: Database name (required)
-o: Save output in dir N under \$RESULTS
(0=Current dir; -1=Not Saved,default)
-f: Save each SQL stmt to a different file in the \$QUERIES dir
-s: Display N characters of SQL stmt (-1=all, default)
-sql: Only display SQL statements, without statistics
-t: DONT display Timing stats
-w: DONT display Row Count stats
-q: Quiet (default is to display output)
-r: Don't get snapshot, reuse existing snapshot output file
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Value for -d is part of snapshot output filename.
Values for -d, -s, -f and -sql are part of Summary output filename.
# Constants
QUERIES=~/queries
RESULTS=~/results
RESULTS_FILE="`basename $0 .ksh`"
RES_EXT=".out"
SUM_EXT=".sum"
AWKSCRIPT="`dirname $0`/`basename $0 .ksh`.awk"
# Defaults
QUIET=0
DISPLAY_SQL=-1
SAVE_SQL=0
SQL_ONLY=0
RESULTS_DIR=-1# -1 defaults to not saved
REUSE_OUT=0
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
NO_TIMING=0;
NO_ROWS=0;
WINCOLS=`stty size | awk '{print $2}'`
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
if [ $SAVE_SQL -eq 1 ]
then
# Get last query file number
mkdir $QUERIES 2>/dev/null
LAST_QUERY=`ls $QUERIES | sort -n | tail -1`
LAST_QUERY=`basename $LAST_QUERY .sql`
fi
RES_EXT="_${DB_NAME}${RES_EXT}"
SUM_EXT="_${DB_NAME}_${DISPLAY_SQL}${SAVE_SQL}${SQL_ONLY}${NO_TIMING}${NO_ROWS}${SUM_EXT
}"
if [ $RESULTS_DIR -gt 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${SUM_EXT}
RES_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${RES_EXT}.$$
SUM_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${SUM_EXT}.$$
else
RES_OUT=${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS_FILE}${SUM_EXT}
fi
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak2>/dev/null
[ $REUSE_OUT -eq 0 ] && \
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
cp $SUM_OUT $SUM_BAK 2>/dev/null && echo "[Created: $SUM_BAK]"
fi
TMP_SQL="${QUERIES}/sql.$$.tmp"
# BEGIN .......
if [ $RESULTS_DIR -ge 0 ]
then
echo "[Creating: $SUM_OUT]"
else
Q_OUTPUT=""
echo "[No Output Saved]"
fi
if [ $RESULTS_DIR -eq -1 ]
then
echo db2 get snapshot for dynamic sql on $DB_NAME
echo ""
db2 get snapshot for dynamic sql on $DB_NAME | awk -f $AWKSCRIPT
else
if [ $REUSE_OUT -eq 0 ]
then
eval echo db2 get snapshot for dynamic sql on $DB_NAME $Q_OUTPUT
eval echo "" $Q_OUTPUT
echo "[Creating: $RES_OUT]"
db2 get snapshot for dynamic sql on $DB_NAME > $RES_OUT
else
echo ""
echo "[Reusing: $RES_OUT]"
fi
/SQL1611W/{ print }
/ Number of executions/{
N_EXECUTIONS= "";
N_COMPILES= "";
T_W_PREP= "";
T_B_PREP= "";
R_DELETED= "";
R_INSERTED= "";
R_READ= "";
R_UPDATED= "";
R_WRITTEN= "";
S_SORTS= "";
T_T_EXECUTION= "";
T_T_USER= "";
T_T_SYSTEM= "";
}
/ Number of executions/{ N_EXECUTIONS=$NF}
/ Number of compilations/{ N_COMPILES=$NF}
/ Worst preparation time \(ms\)/{ T_W_PREP=$NF}
/ Best preparation time \(ms\)/{ T_B_PREP=$NF}
/ Rows deleted/{ R_DELETED=$NF}
/ Rows inserted/{ R_INSERTED=$NF}
/ Rows read/ { R_READ=$NF}
/ Rows updated/{ R_UPDATED=$NF}
/ Rows written/{ R_WRITTEN=$NF}
/ Statement sorts/{ S_SORTS=$NF}
/ Total execution time \(sec.ms\)/{ T_T_EXECUTION=$NF}
/ Total user cpu time \(sec.ms\)/{ T_T_USER=$NF}
/ Total system cpu time \(sec.ms\)/{ T_T_SYSTEM=$NF}
STMT_NUM=STMT_NUM + 1;
S_TEXT=substr( $0, index( $0, "=")+2 );
SQL_OUT="";
if (R_READ == "Collected")
COLLECTED=0;
if (DISPLAY_SQL == -1)
SQL_LEN = length( S_TEXT);
else
SQL_LEN = DISPLAY_SQL;
if ( SQL_ONLY )
{
if (SAVE_SQL)S_Save_Info();
}
else
{
T_A_EXEC= T_T_EXECUTION / N_EXECUTIONS;
T_A_USER= T_T_USER/ N_EXECUTIONS;
T_A_SYSTEM= T_T_SYSTEM / N_EXECUTIONS;
A_R_READ= R_READ/ N_EXECUTIONS;
A_R_WRITTEN= R_WRITTEN/ N_EXECUTIONS;
A_R_INSERTED= R_INSERTED/ N_EXECUTIONS;
A_R_UPDATED= R_UPDATED/ N_EXECUTIONS;
A_R_DELETED= R_DELETED/ N_EXECUTIONS;
S_Exec_Info();
# if ( SAVE_SQL ||
# ((! SAVE_SQL) && ! (NO_TIMING || NO_ROWS || ! COLLECTED)) )
if ( SAVE_SQL )
S_Save_Info();
S_SQL_Text();
rm_Trailing();
print headline;
print underline;
header = 1;
}
################################################################################
function round_MIL( val ) {
################################################################################
function S_Timing_Info() {
################################################################################
function S_Rows_Info() {
SPACERHEAD="";
SPACER="";
WINCOL_Spacing();
################################################################################
function S_Save_Info() {
################################################################################
function S_SQL_Text() {
if ( DISPLAY_SQL )
headline = headline sprintf( \
"%-*s | ",
SQL_LEN, "SQL-Text");
if (S_TEXT && SQL_LEN)
dataline = dataline sprintf( \
"%-*.*s | ",
SQL_LEN, SQL_LEN, S_TEXT);
}
################################################################################
function WINCOL_Spacing() {
################################################################################
function rm_Trailing() {
# Get rid of trailing separator
################################################################################
function Save_Sql() {
# Save SQL Text to a file, or get name of existing (duplicate) file
DUPFILE="";
print S_TEXT > TMP_SQL;
close( TMP_SQL);
if ( DUPFILE != "" )
{ # A duplicate SQL file was found
SQL_OUT = DUPFILE;
}
else
{ # Create SQL file
LAST_QUERY=LAST_QUERY + 1;
SQL_OUT=LAST_QUERY ".sql";
print S_TEXT > QUERIES "/" SQL_OUT;
}
}
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" [-i m] [-p] [-o N] [-s n ] [-r] [-b]
Summerize the output of iostat.
-c: Comment placed on first line of Summary output file (required).
-i: Interval for iostat (default=1).
-p: Only display peak values, when they change, for all disks, etc.
Default is to display all values, as they change.
-o: Save output in dir N under \$RESULTS (-1=current dir, default).
-s: Save iostat output with n in the filename (0=dont save,default).
-r: Don't get iostat, reuse iostat output specifies by -s.
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Stop the utility by hitting Ctrl-C.
Values for -i, -s and -p are part of Summary output filename.
In most cases, best viewed in window-width which is multiple of 10.
"
}
# Constants
RESULTS=~/results
RESULTS_FILE="`basename $0 .ksh`"
RES_EXT=".out"
SUM_EXT=".sum"
# Defaults
INTERVAL=1
SAVE_NAME=0
ONLYPEAKS=0
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
RES_EXT="_${INTERVAL}${SAVE_NAME}${RES_EXT}"
SUM_EXT="_${INTERVAL}${SAVE_NAME}${ONLYPEAKS}${SUM_EXT}"
if [ $RESULTS_DIR -ge 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${SUM_EXT}
export ONLYPEAKS
# BEGIN .......
if [ $REUSE_OUT -eq 1 ]
then
[ ! -f $RES_OUT ] && echo "Can't reuse $RES_OUT - Missing" && exit
BEGIN{
HEADCOUNTMAX=10; # Heading every x lines
ONLYPEAKS=ENVIRON[ "ONLYPEAKS"]; # All changes or all Peaks
/^tty:/{
++cnt;
get_iowait=1;
next;
}
get_iowait{
get_iowait=0;
iowait=$NF;
next;
}
END{
if (! ALLCHANGES)
{
headcount = HEADCOUNTMAX - 1;
display_results( "=" );
##########################
function display_results( underline_char )
{
# Build heading, then replace spaces with dashes
headcount+=1;
headline1="";
for (disk in changed)
if (changed[disk] > 0)
headline1 = headline1 sprintf( " %-9.9s", disk);
gsub( / /, underline_char, headline1);
if ( (headline1 != headline) || (headcount == HEADCOUNTMAX) )
{
headline = headline1;
print headline;
headcount=0;
}
###########################
function display( RW, activity )
{
got_activity=0;
line="";
for (disk in changed)
{
if (changed[disk] > 0)
{
if ( (activity[disk]) && (changed[disk] || ! ALLCHANGES))
{
line = line sprintf( "%s%9s", RW, activity[disk]);
if (disk != IOWAIT)
got_activity=1;
}
else
line = line sprintf( "%s%9s", RW, "");
RW="|";
}
if (ALLCHANGES)
activity[disk]="";
}
if (got_activity)
print line;
}
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" -d dbname [-o N] [-a] [-db] [-q] [-r] [-b]
Summerize the LOCKS information being captures by a LOCKS snapshot.
-c: Comment placed on first line of Summary output file (required)
-d: Database name (required)
-o: Save output in dir N under \$RESULTS
(0=Current dir; -1=Not Saved,default)
-a: DONT display Application level information
-db: DONT display Database level information
-q: Quiet (default is to display output)
-r: Don't get snapshot, reuse existing snapshot output file
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Value for -d is part of snapshot output filename.
Values for -d, -a and -db are part of Summary output filename.
"
}
# Constants
RESULTS=~/results
RESULTS_FILE="`basename $0 .ksh`"
# Defaults
QUIET=0
RESULTS_DIR=-1# -1 defaults to not saved
REUSE_OUT=0
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
NO_APPS=0;
NO_DB=0;
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
RES_EXT="_${DB_NAME}${RES_EXT}"
SUM_EXT="_${DB_NAME}_${NO_APPS}${NO_DB}${SUM_EXT}"
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak2>/dev/null
[ $REUSE_OUT -eq 0 ] && \
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
cp $SUM_OUT $SUM_BAK 2>/dev/null && echo "[Created: $SUM_BAK]"
fi
fi
# BEGIN .......
if [ $RESULTS_DIR -ge 0 ]
then
echo "[Creating: $SUM_OUT]"
else
Q_OUTPUT=""
echo "[No Output Saved]"
fi
if [ $RESULTS_DIR -eq -1 ]
then
echo db2 get snapshot for locks on $DB_NAME
echo ""
db2 get snapshot for locks on $DB_NAME | awk -f $AWKSCRIPT
else
if [ $REUSE_OUT -eq 0 ]
then
eval echo db2 get snapshot for locks on $DB_NAME $Q_OUTPUT
echo ""
echo "[Creating: $RES_OUT]"
/SQL1611W/{ print }
# Application info
/Application handle /{ A_HAND = "" ;
A_NAME= "" ;
A_USER= "" ;
H_HAND= "" ;
A_ID = "" ;
A_STATUS= "" ;
A_LOCKS= "" ;
A_WAIT= "" ;
}
/Application handle /{ A_HAND = $NF }
/Application ID /{ A_ID = $NF ; sub( /\.[0-9]*$/, "", A_ID) }
/Application name /{ A_NAME = $NF }
/Authorization ID /{ A_USER = $NF }
/Application status /{ A_STATUS = substr( $0, index( $0, "=") + 2 ) }
/Status change time /{ A_TIME = $NF }
/Locks held / && A_HAND{ A_LOCKS = $NF }
/Total wait time \(ms\)/{ A_WAIT = $NF }
if (! headline )
{
headline = sprintf( \
"%-10.10s %-8.8s %-6.6s %-20.20s %-15.15s %-5.5s %-7.7s",
"APP.NAME",
"APP.USER",
"HANDLE",
"APP.ID",
"APP.STATUS",
underline = sprintf( \
"%-10.10s %-8.8s %-6.6s %-20.20s %-15.15s %-5.5s %-7.7s",
dashes,
dashes,
dashes,
dashes,
dashes,
dashes,
dashes);
print headline;
print underline;
}
dataline = sprintf( \
"%-10.10s %-8.8s %6.6s %-20.20s %-15.15s %5.5s %s",
A_NAME,
A_USER,
A_HAND,
A_ID,
A_STATUS,
A_LOCKS,
A_WAIT);
print dataline;
}
# Lock info
/ Object Type /{ L_TYPE = "" ;
L_SCHEMA = "" ;
L_TABLE = "" ;
L_MODE = "" ;
L_STATUS = "" ;
L_ESC = "" ;
}
/ Object Type /{ L_TYPE = $NF }
/ Table Schema /{ L_SCHEMA = $NF }
/ Table Name /{ L_TABLE = $NF }
/ Mode /{ L_MODE = $NF }
/ Status /{ L_STATUS = $NF }
/ Lock Escalation /{ L_ESC = $NF ;
LOCKS [ L_SCHEMA ,
L_TABLE ,
L_TYPE ,
L_ESC ,
L_MODE ,
L_STATUS ] ++;
}
END{
headline = "";
for (ind in LOCKS)
{
if (! headline)
{
headline = sprintf( \
"%-30.30s | %-10.10s | %-3.3s | %-4.4s | %-10.10s | %5.5s",
"TABLE NAME",
"TYPE",
"ESCALATED",
"MODE",
"STATUS",
underline = sprintf( \
"%-30.30s | %-10.10s | %-3.3s | %-4.4s | %-10.10s | %5.5s",
dashes,
dashes,
dashes,
dashes,
dashes,
dashes);
# underline = headline;
# gsub( /./, "-", underline);
print "" ;
print headline;
print underline;
}
if (! headline)
{
print "";
print "*** NO LOCKS ***";
}
}
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" -d dbname -m mon_name [-o N] [-f]
[-s N] [-sql] [-i Q] [-p] [-ps] [-q] [-r] [-b]
Summerize STATEMENT statistics captured from an Event Monitor.
-c: Comment placed on first line of Summary output file (required)
-d: Database name (required)
-m: Monitor name (required)
-o: Save output in dir N under \$RESULTS
(0=Current dir; -1=Not Saved,default)
-f: Save each SQL stmt to a different file in the \$QUERIES dir
-s: Display N characters of SQL stmt (-1=all, default)
-sql: Only display SQL statements, without statistics
-i: Include info in output, where Q could contain any of the following
S=Start-Time ; O=Operation ; T=Timing ; R=Row-Counts; X=Sort-Info
N=None_of_the_above (default=SORTX)
-p: mon_name is a PIPE; Don't save the summary to an output file.
-ps: mon_name is a PIPE; Save the summary to an output file.
Summary output is only visible when the event monitor closes.
-q: Quiet (default is to display output)
-r: Don't read the monitor files, reuse existing output (extraction)
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Value for -d is part of monitor output filename.
Values for -s, -f, -sql and -i are part of Summary output filename.
Pipes: Make sure to run this utility BEFORE starting the event monitor
(prompts given). For -ps only flushed summary output is
visible in real-time (instructions given). So for real-time
viewing, use -p, which doesn't save summary to a file.
In most cases, best viewed in 132 column window.
"
}
# Constants
QUERIES=~/queries
RESULTS=~/results
RESULTS_FILE="`basename $0 .ksh`"
RES_EXT=".out"
SUM_EXT=".sum"
AWKSCRIPT="`dirname $0`/`basename $0 .ksh`.awk"
# Defaults
QUIET=0
DISPLAY_SQL=-1
SAVE_SQL=0
SQL_ONLY=0
RESULTS_DIR=-1# -1 defaults to not saved
REUSE_OUT=0
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
INCLUDE_OPT="SORTX"
PIPE=0
PIPE_SAVE=0
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
if [ $SAVE_SQL -eq 1 ]
then
# Get last query file number
mkdir $QUERIES 2>/dev/null
LAST_QUERY=`ls $QUERIES | sort -n | tail -1`
LAST_QUERY=`basename $LAST_QUERY .sql`
fi
RES_EXT="_${DB_NAME}${RES_EXT}"
SUM_EXT="_${DB_NAME}_${DISPLAY_SQL}${SAVE_SQL}${SQL_ONLY}${INCLUDE_OPT}${SUM_EXT}"
if [ $RESULTS_DIR -gt 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${SUM_EXT}
RES_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${RES_EXT}.$$
SUM_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${SUM_EXT}.$$
else
RES_OUT=${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS_FILE}${SUM_EXT}
fi
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak2>/dev/null
[ $REUSE_OUT -eq 0 ] && \
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
cp $SUM_OUT $SUM_BAK 2>/dev/null && echo "[Created: $SUM_BAK]"
fi
fi
TMP_SQL="${QUERIES}/sql.$$.tmp"
# BEGIN .......
echo ""
eval awk -f $AWKSCRIPT $RES_OUT $Q_OUTPUT
fi
else
echo "\
--------------------------------------------------------------------
Start the event monitor to begin summarizing (filtering) as follows:
Use: db2 SET EVENT MONITOR $MON_NAME STATE 1
--------------------------------------------------------------------"
# or: . `dirname $0`/mon_state.ksh $MON_NAME 1
if [ $PIPE_SAVE -eq 0 ]
then
# Gives better real-time display without pipe after awk
echo ""
echo db2evmon $DB_NAME $MON_NAME
echo ""
eval db2evmon $DB_NAME $MON_NAME $R_OUTPUT | awk -f $AWKSCRIPT
else
echo "\
Only when all pipe buffers are flushed will be output be visible.
The mon_stmt.ksh script uses the mon_stmt.awk file as the following source:
BEGIN{
OS = "AIX";
QUERIES = ENVIRON[ "QUERIES" ];
DISPLAY_SQL = ENVIRON[ "DISPLAY_SQL" ];
SAVE_SQL = ENVIRON[ "SAVE_SQL" ];
SQL_ONLY = ENVIRON[ "SQL_ONLY" ];
LAST_QUERY = ENVIRON[ "LAST_QUERY" ];
TMP_SQL = ENVIRON[ "TMP_SQL" ];
INCLUDE_OPT = ENVIRON[ "INCLUDE_OPT" ];
STMT_NUM = 0;
MIL = 1000000;
CON_REC = 0;
header = 0;
h=0; # Counter of Handles
}
STMT_NUM=STMT_NUM + 1;
SQL_OUT="";
headline = "";
dataline = "";
if ( SQL_ONLY )
{
if (SAVE_SQL)S_Save_Info();
}
else
{
S_App_Info();
if (SAVE_SQL)S_Save_Info();
if (OPT_OPER) S_Oper_Info();
if (OPT_TIMES) S_Timing_Info();
if (OPT_ROWS) S_Rows_Info();
if (OPT_SORTS)
{
# When all options displayed, remove '|' to fit in 132
if (INCLUDE_OPT ~ /[SORTX]{5}/)
{
rm_Trailing();
headline = headline " ";
dataline = dataline " ";
}
S_Sort_Info();
}
}
S_SQL_Text();
rm_Trailing();
print headline;
print underline;
header = 1;
}
################################################################################
function S_App_Info() {
if (OPT_ST_TIME)
{
headline = headline sprintf( \
" %-15.15s",
"Start-Time");
dataline = dataline sprintf( \
" %15s",
S_START_T);
}
################################################################################
function S_Save_Info() {
################################################################################
function S_Oper_Info() {
################################################################################
function S_Timing_Info() {
################################################################################
function S_Rows_Info() {
################################################################################
function S_Sort_Info() {
################################################################################
function S_SQL_Text() {
if ( DISPLAY_SQL )
headline = headline sprintf( \
"%-*s | ",
SQL_LEN, "SQL-Text");
if (S_TEXT && SQL_LEN)
dataline = dataline sprintf( \
"%-*.*s | ",
SQL_LEN, SQL_LEN, S_TEXT);
################################################################################
function rm_Trailing() {
# Get rid of trailing separator
################################################################################
function Save_Sql() {
# Save SQL Text to a file, or get name of existing (duplicate) file
DUPFILE="";
print S_TEXT > TMP_SQL;
close( TMP_SQL);
if ( DUPFILE != "" )
{ # A duplicate SQL file was found
SQL_OUT = DUPFILE;
}
else
{ # Create SQL file
LAST_QUERY=LAST_QUERY + 1;
SQL_OUT=LAST_QUERY ".sql";
print S_TEXT > QUERIES "/" SQL_OUT;
}
}
display_syntax()
{
echo "\
SYNTAX: `basename $0` -c \"comment\" -d dbname [-u user/pwd] -q queryNum -o N
[-ir rows] [-if rows] [-e m] [-v] [-b]
Execute db2batch tool which executes the SQL found in a file and reports on
execution times and snapshot information.
-c: Comment placed on first line of Summary output file (required)
-d: Database name (required)
-u: Userid and password seperated by slash (default=db2inst1/db2inst1)
-q: Query number to execute. File with .sql extension must exist in
\$QUERIES directory (required)
-o: Save output in dir N under \$RESULTS (required)
(0=Current dir; -1=Not Valid; no default)
-ir: Rows to return to output file (-1=all,default=10)
-if: Rows to fetch even if not returned (-1=all,default)
-e: Explain level: 0=ExecuteOnly; 1=ExplainOnly; 2=Explain&Execute
(default=2)
-v: Verbose (default is NOT to display output)
-b: DONT save prior (old) results to bak directory (default=save)
(Not saved anyway unless -o is greater than 0)
Notes:
Value for -d is part of output and summary filename.
"
}
# Constants
# Defaults
QUIET=1
RESULTS_DIR="" # no default
SAVE_OLD_RESULTS=1
PARSE_ERROR=""
PARAMS=$*
USERPASS="db2inst1/db2inst1"
QRYNUM=""
IROWS=10
IFETCH=-1
EXPLAIN=2
# Parse parameters
# Verify parameters
if [ "$PARSE_ERROR" != "" ]
then
echo ""
echo $PARSE_ERROR
echo ""
display_syntax
exit
fi
RES_EXT="_${DB_NAME}${RES_EXT}"
SUM_EXT="_${DB_NAME}${SUM_EXT}"
if [ $RESULTS_DIR -gt 0 ]
then
RES_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS}/${RESULTS_DIR}/${RESULTS_FILE}${SUM_EXT}
RES_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${RES_EXT}.$$
SUM_BAK=${RESULTS}/${RESULTS_DIR}/bak/${RESULTS_FILE}${SUM_EXT}.$$
else
RES_OUT=${RESULTS_FILE}${RES_EXT}
SUM_OUT=${RESULTS_FILE}${SUM_EXT}
fi
if [ $RESULTS_DIR -gt 0 ]
then
mkdir $RESULTS 2>/dev/null
mkdir $RESULTS/$RESULTS_DIR 2>/dev/null
if [ $SAVE_OLD_RESULTS -eq 1 ]
then
mkdir $RESULTS/$RESULTS_DIR/bak 2>/dev/null
cp $RES_OUT $RES_BAK 2>/dev/null && echo "[Created: $RES_BAK]"
cp $SUM_OUT $SUM_BAK 2>/dev/null && echo "[Created: $SUM_BAK]"
[ -f $RES_BAK ] && \
echo "[Modifying: $RES_BAK]" && \
`dirname $0`/db2bench_prefix.ksh $RES_BAK
fi
fi
# BEGIN .......
echo db2batch \
-d $DB_NAME \
-f $QUERIES/${QRYNUM}.sql \
-r ${RES_OUT},${SUM_OUT} \
-a db2inst1/db2inst1 \
-c off \
-i complete \
-o r $IROWS f $IFETCH p 5 e $EXPLAIN \
-v $VERBOSE >> $RES_OUT
echo "" >> $RES_OUT
db2batch \
-d $DB_NAME \
-f $QUERIES/${QRYNUM}.sql \
-r ${RES_OUT}.tmp,${SUM_OUT}.tmp \
-a db2inst1/db2inst1 \
-c off \
-i complete \
-o r $IROWS f $IFETCH p 5 e $EXPLAIN \
-v $VERBOSE
SOURCE1=$1
SOURCE=`basename $0`.$$.source
TARGET=`basename $0`.$$.tmp
PREFIX=${2:-`basename $SOURCE1`}
export PREFIX
The db2bench.ksh script calls the following db2bench_prefix.awk file. You need
to have it in the same directory.
BEGIN{
TOP = 1;
PREFIX = ENVIRON[ "PREFIX" ];
}
{
PUT_PREFIX = 0 ;
}
#/Statement number: / { TOP=0 }
#TOP { PUT_PREFIX=1 }
(NR <= TOP) { PUT_PREFIX=1 }
/ \*\*\* Database Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Bufferpool Snapshot \*\*\*/ { PUT_PREFIX=1 }
/Bufferpool Name .* = / { PUT_PREFIX=1 }
/ \*\*\* Bufferpool Info Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Application Info Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Application Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Statement Details \*\*\*/ { PUT_PREFIX=1 }
/Statement operation .* = / { PUT_PREFIX=1 }
/ \*\*\* List of Associated Agents \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Tablespace Header Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Tablespace Snapshot \*\*\*/ { PUT_PREFIX=1 }
/Tablespace Name .* = / { PUT_PREFIX=1 }
/ \*\*\* Table Header Snapshot \*\*\*/ { PUT_PREFIX=1 }
/ \*\*\* Table Snapshot \*\*\*/ { PUT_PREFIX=1 }
/Table Name .* = / { PUT_PREFIX=1;TAB=$NF}
This redbook also contains additional material in diskette format. See the
appropriate section below for instructions on using or downloading each type
of material.
Before using the scripts, execute the following command to make them
executable:
chmod +x *.ksh
ftp://www.redbooks.ibm.com/redbooks/SG246012
ibm.com/redbooks
Select the Additional materials and open the directory that corresponds with
the redbook form number.
IBM may have patents or pending patent applications covering subject matter
in this document. The furnishing of this document does not give you any
license to these patents. You can send license inquiries, in writing, to the IBM
Director of Licensing, IBM Corporation, North Castle Drive, Armonk, NY
10504-1785.
Licensees of this program who wish to have information about it for the
purpose of enabling: (i) the exchange of information between independently
created programs and other programs (including this one) and (ii) the mutual
use of the information which has been exchanged, should contact IBM
Corporation, Dept. 600A, Mail Drop 1329, Somers, NY 10589 USA.
The information contained in this document has not been submitted to any
formal IBM test and is distributed AS IS. The use of this information or the
implementation of any of these techniques is a customer responsibility and
depends on the customer's ability to evaluate and integrate them into the
customer's operational environment. While each item may have been
reviewed by IBM for accuracy in a specific situation, there is no guarantee
Any pointers in this publication to external Web sites are provided for
convenience only and do not in any manner serve as an endorsement of
these Web sites.
Java and all Java-based trademarks and logos are trademarks or registered
trademarks of Sun Microsystems, Inc. in the United States and/or other
countries.
SET, SET Secure Electronic Transaction, and the SET Logo are trademarks
owned by SET Secure Electronic Transaction LLC.
The publications listed in this section are considered particularly suitable for a
more detailed discussion of the topics covered in this redbook.
All DB2 UDB manuals are available at the DB2 Product and Service Technical
Library. Visit the following URL:
http://www-4.ibm.com/software/data/db2/library
This section explains how both customers and IBM employees can find out about IBM Redbooks,
redpieces, and CD-ROMs. A form for ordering books and CD-ROMs by fax or e-mail is also provided.
• Redbooks Web Site ibm.com/redbooks
Search for, view, download, or order hardcopy/CD-ROM Redbooks from the Redbooks Web site.
Also read redpieces and download additional materials (code samples or diskette/CD-ROM images)
from this Redbooks site.
Redpieces are Redbooks in progress; not all Redbooks become redpieces and sometimes just a few
chapters will be published this way. The intent is to get the information out much quicker than the
formal publishing process allows.
• E-mail Orders
Send orders by e-mail including information from the IBM Redbooks fax order form to:
e-mail address
In United States or Canada [email protected]
Outside North America Contact information is in the “How to Order” section at this site:
http://www.elink.ibmlink.ibm.com/pbl/pbl
• Telephone Orders
United States (toll free) 1-800-879-2755
Canada (toll free) 1-800-IBM-4YOU
Outside North America Country coordinator phone number is in the “How to Order”
section at this site:
http://www.elink.ibmlink.ibm.com/pbl/pbl
• Fax Orders
United States (toll free) 1-800-445-9269
Canada 1-403-267-4455
Outside North America Fax phone number is in the “How to Order” section at this site:
http://www.elink.ibmlink.ibm.com/pbl/pbl
This information was current at the time of publication, but is continually subject to change. The latest
information may be found at the Redbooks Web site.
Company
Address
We accept American Express, Diners, Eurocard, Master Card, and Visa. Payment by credit card not
available in all countries. Signature mandatory for credit card payment.
393
REORG 276 Recovering Dropped Tables 105
REORGCHK 276 table scan 169
REORGCHK command 214 Table Space
RESET MONITOR ALL 140 DMS Table Space 53
Resetting Snapshot Monitor Switches 140 Extent Size 65
RESTBUFSZ 297 Long Table Space 55
RESTORE DATABASE 294 Overhead 62
RQRIOBLK 199 Page Size 63
RUNSTATS 276 Prefetch Size 67
when to use 172 Regular Table Space 54
Rename 70
SMS Table Space 52
S System Temporary Table Spaces 55
Scheduling Policy 38
Transfer Rate 62
SET EVENT MONITOR 150
User Temporary Table Spaces 55
Snapshot Monitor 136
resetting counters 140
switches 139 U
SOFTMAX 221 UDF_MEM_SZ 199
SORTHEAP 198, 201 UPDATE MONITOR SWITCHES 136
sorting 201–204 UPDATE MONITOR SWITCHES command 211
Overflowed and Non-Overflowed 201 UTIL_HEAP_SZ 198, 208, 275
Piped and Non-Piped 201
SHEAPTHRES 202
special registers
V
Visual Explain
CURRENT EXPLAIN MODE 162
dynamic 167
CURRENT EXPLAIN SNAPSHOT 162
interpreting output 167
Explain 162
invoking 165
SQL compiler 229
operators 168
SQL optimizer 171
vmtune command 37
SQL statements (DDL)
DROP EVENT MONITOR 151
STAT_HEAP_SZ 199, 290 W
static embedded SQL 243 Write Scheduling Policy 40
STMTHEAP 199 Write Verify 41
stored procedure 240
nested procedure 241
Striping 35, 37
Summary Tables 103
T
Table
APPEND MODE 98
Data Types 88
Denormalizing 88
Normalizing 85
NOT LOGGED INITIALLY option 99
Not Null 89
Performance 85
Review
Questions about IBM’s privacy The following link explains how we protect your personal information.
policy? ibm.com/privacy/yourprivacy/
(0.5” spine)
0.475”<->0.875”
250 <-> 459 pages
®