DB2 troubleshooting for performance symptoms

Db2 for z/OS performance troubleshooting works best when you treat every complaint as a testable symptom. A slow screen, rising CPU graph, table-space scan, timeout, or failed utility is a starting point—not a diagnosis. This beginner-friendly guide shows how to collect evidence, compare it with a known-good period, and narrow the problem before changing SQL, indexes, subsystem settings, or application behavior.

Evidence-first diagnosis
Progress0 of 0 lessons

Begin with an evidence-first diagnostic workflow

Before tuning, define exactly what changed. Record the first known bad time, the last known good time, affected applications, Db2 subsystem or data-sharing member, SQL identity, package and collection, connection type, and business volume. “The query is slow” is too vague. “This statement rose from 200 milliseconds to 8 seconds after 14:00, while input volume stayed stable” gives you a comparison that can be tested.

  • Confirm the symptom from both the user's view and Db2's view. Separate network, application, queue, lock-wait, and database execution time.
  • Capture a baseline from a comparable healthy interval. Match day, workload, input values, commit pattern, subsystem member, and data volume as closely as possible.
  • Use Db2 accounting traces for thread or package execution, statistics traces for subsystem and buffer-pool trends, and performance traces only when the extra detail is justified. Relevant IFCIDs feed these records; your site monitor usually presents them without requiring beginners to decode raw trace records.
  • Inspect current threads, DDF activity, utilities, locks, and object status with the appropriate Db2 displays or monitoring product. Save timestamps and complete messages so separate observations can be correlated.
  • Form one hypothesis, make the smallest safe test, and check the same metrics again. Keep a rollback plan. Do not change several knobs and then guess which one helped.
text
1
2
3
4
5
6
7
8
Symptom -> scope -> baseline -> Db2 evidence -> hypothesis -> controlled test For every incident, ask: 1. What became worse, and when? 2. Which SQL, object, thread, connection, or utility is involved? 3. What differs from the last healthy period? 4. Is time spent on CPU, I/O, locks, Db2 queues, or outside Db2? 5. Which single observation would prove or disprove the leading theory?
Symptom-to-evidence starting points
SymptomCapture firstDiagnostic question
Query suddenly slowElapsed time, class 1/class 2 time, SQL identity, access path, waitsDid execution, data, statistics, contention, or the access path change?
Index access became a table-space scanCurrent and previous EXPLAIN rows, RUNSTATS history, package changeWhy did the optimizer estimate that scanning was cheaper?
CPU or getpages increasedAccounting CPU, getpages, rows examined/returned, synchronous readsIs Db2 doing more logical work, more physical I/O, or both?
Buffer-pool hit ratio droppedPool-level and object-level reads, writes, thresholds, residencyWhich objects displaced useful pages, and did response time worsen?
Sort activity explodedSort counts, work-file use, rows sorted, EXPLAIN sort indicatorsDid SQL shape, access path, cardinality, or memory pressure change?
Locks, threads, or DDF connections built upWaiters and holders, unit-of-work age, thread state, DBAT and connection countsWhat is holding progress, and why has it not committed or ended?

Query suddenly slow

A statement that was fast yesterday can be slow today even when its SQL text looks unchanged. The access path may have changed after RUNSTATS, REORG, index DDL, a bind, package invalidation, maintenance, or an application deployment. The path may be unchanged while input values now select far more rows. Contention, storage latency, CPU pressure, or a different member can also increase elapsed time without changing the optimizer's decision.

Start with accounting data for the affected execution. Compare elapsed time, general processor CPU, zIIP-eligible or consumed time where applicable, getpages, synchronous reads, prefetch activity, rows processed, sorts, lock/latch waits, and number of executions. Normalize totals per execution or per business transaction. A daily total can rise simply because the application did more work.

Compare old and new access paths with EXPLAIN

EXPLAIN records the optimizer's proposed access path in PLAN_TABLE and related tables. Use the same SQL, schema, special registers, parameter markers or representative literals, optimization environment, and catalog statistics when recreating a path. For static SQL, also inspect the package's captured access-path information and bind history available at your site. Do not assume a fresh ad hoc EXPLAIN exactly represents the package that ran during the incident.

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- Simplified dynamic EXPLAIN example. -- Use the same qualifiers and relevant special-register context as the application. EXPLAIN PLAN SET QUERYNO = 4101 FOR SELECT O.ORDER_ID, O.ORDER_DATE, O.TOTAL_AMOUNT FROM APP.ORDERS O WHERE O.CUSTOMER_ID = ? AND O.ORDER_DATE >= ? ORDER BY O.ORDER_DATE DESC; -- Read your site's PLAN_TABLE with the columns supported at its Db2 level. SELECT QUERYNO, QBLOCKNO, PLANNO, METHOD, ACCESSTYPE, MATCHCOLS, ACCESSNAME, INDEXONLY, PREFETCH FROM PLAN_TABLE WHERE QUERYNO = 4101 ORDER BY QBLOCKNO, PLANNO;
Useful EXPLAIN evidence
EXPLAIN areaWhat it describesTroubleshooting clue
ACCESSTYPEHow Db2 reaches the data, such as index access or a scanA changed value can explain a large increase in rows examined and getpages
MATCHCOLSLeading index columns matched by predicatesFewer matching columns often means less selective index navigation
INDEXONLYWhether all required values can come from the indexLosing index-only access adds data-page visits
PREFETCHWhether Db2 expects sequential, list, or dynamic prefetchUseful context for scan behavior and synchronous read changes
SORT indicatorsWhether Db2 plans sorts for joins, grouping, ordering, or distinct workNew sort indicators can predict work-file and CPU growth
Join sequence and methodOrder and technique used to combine tablesA poor outer-table estimate can multiply work in later steps

It used an index before, but now it scans

A table-space scan is not automatically wrong. If a query returns a large percentage of a table, sequential access with prefetch can cost less than jumping between an index and many data pages. The diagnostic question is not “How do I force the index?” but “What changed in Db2's cost estimate or in the available choices?”

  • Check whether the index still exists, is available, has the same key order, and can support the predicates. A function or expression on an indexed column can make a predicate less usable unless a suitable expression-based index exists.
  • Compare table, column, distribution, frequency, correlation, and index statistics. Stale, missing, default, or unrepresentative statistics can distort cardinality.
  • Check predicate changes, implicit casts, data-type mismatches, parameter markers, host-variable behavior, and range size. Similar-looking SQL can estimate very different row counts.
  • Review binds, APPLCOMPAT and optimizer-level context, package invalidation, access path reuse, and relevant subsystem changes. Record facts before considering a hint or plan-management action.

If the scan is genuinely harmful, correct the cause: collect suitable statistics, rewrite a non-indexable predicate, restore or improve an index, or safely rebind after testing. Forcing yesterday's path can preserve a plan that no longer fits today's data.

CPU and getpages increased

CPU measures processor work. Getpages measure logical requests for Db2 pages. They are related but not identical to physical I/O. A page already resident in a buffer pool can satisfy many getpages without a disk read. Compare getpages per execution, rows examined versus rows returned, synchronous reads, prefetch reads, and CPU per execution.

Rising getpages with stable result rows often points to less selective access, fewer matching index columns, loss of index-only access, a changed join order, repeated probes, or poor clustering. Rising CPU without a similar getpage increase may suggest more sorting, expression evaluation, data conversion, compression work, or application calls. Both may rise when a query scans and filters far more rows. Confirm with EXPLAIN and accounting evidence rather than assigning every CPU increase to one SQL statement.

Buffer-pool hit ratio dropped

Hit ratio is the share of logical page requests satisfied without a new read, but an aggregate percentage is not a verdict. A deliberate sequential scan can lower a pool ratio while finishing efficiently. A high ratio can coexist with poor performance if the application repeatedly touches too many cached pages. Always correlate the ratio with synchronous I/O, read latency, getpages, writes, threshold events, and response time.

Use Db2 statistics monitoring to find the affected buffer pool, then move toward object-level evidence. Ask whether a new scan displaced frequently reused pages, whether one object grew, whether pool assignment changed, whether page size or sequential thresholds fit the workload, and whether storage became slower. Resize or reassign a pool only after proving capacity or isolation is the constraint. Otherwise, SQL that reads fewer pages is often the stronger fix.

Sort explosion and work-file pressure

A sort explosion means more sorts, larger sorts, or more concurrent sort work. ORDER BY, GROUP BY, DISTINCT, merge scan joins, duplicate removal, and some subqueries can require sorting. A useful index may previously have supplied the desired order. A join order or cardinality change may now create a huge intermediate result before sorting.

Compare accounting sort counts and records processed, statistics for the work-file database, and EXPLAIN sort indicators. Check SQL changes, access-path changes, data growth, inaccurate statistics, and concurrency. Work-file space or sort-memory tuning may relieve a proven resource bottleneck, but it does not repair a query that sorts millions of unnecessary rows.

Lock contention, deadlocks, and timeouts

Lock contention begins when a thread needs an incompatible lock held by another unit of work. A timeout means the wait exceeded its allowed duration. A deadlock means a cycle exists—for example, thread A holds row 1 and wants row 2 while thread B holds row 2 and wants row 1. Waiting longer cannot solve that cycle, so IRLM chooses a victim.

Capture the waiter, holder, object, partition, lock mode, SQL, authorization or correlation identity, connection type, and unit-of-work age. Look for infrequent commits, user think time inside a transaction, large updates, inconsistent object access order, lock escalation, and queries reading more rows than expected. The durable fix is usually shorter transactions, consistent access order, selective SQL, and intentional isolation—not a blanket timeout increase.

Thread buildup and DDF connection buildup

Thread buildup is a queueing symptom. Local allied threads and distributed DBATs are different populations, so identify the attachment type first. Inspect thread states: are they executing, waiting on locks, waiting for Db2 resources, inactive, or stalled in long units of work? A surge can come from slower SQL, a blocked transaction, application retry storms, a downstream outage, or traffic growth. Raising CTHREAD or MAXDBAT without finding the bottleneck may admit more work and make CPU, storage, locks, or another service collapse faster.

DDF also distinguishes network connections from active DBATs. Connection pooling and high-performance DBAT behavior can make counts differ from a simple one-client, one-thread model. Use DDF displays and your monitor to compare remote location, authorization ID, application name, connection count, active DBAT count, queued work, idle age, and transaction state. Coordinate with application owners to check pool maximums, leaked connections, retry policy, commit behavior, and whether requests are actually completing.

CHECK INDEX failure

CHECK INDEX verifies consistency between index entries and table data. A nonzero result is not merely a performance statistic. Preserve the complete utility output, return code, messages, object identity, scope, and resulting restrictive state. Check preceding hardware, I/O, recovery, LOAD, REORG, or utility events. The corrective path depends on exactly what Db2 found and on the installed release.

Do not jump directly to REPAIR. First protect recoverability, understand whether the data or index is authoritative, and follow documented procedures. A rebuild may be appropriate for an index inconsistency, but the DBA must account for availability, image copies, related objects, pending states, and the original cause.

REBUILD INDEX failure

Read utility output from the first relevant error, not only the final failure code. Determine the phase and whether the problem is an unavailable input object, insufficient sort or work space, full target data set, authorization issue, I/O failure, duplicate key, damaged data, concurrent utility, or drain problem. Confirm the index and table space states before retrying.

Correct the named cause and use the documented restart or rerun behavior. Repeatedly submitting identical JCL can consume the window while preserving the same failure. After success, verify object state and consistency, and capture why the failure occurred so space estimates, utility controls, or scheduling can be corrected.

Utility drain timeout

A utility requests a drain when it needs existing claims to leave and may need to prevent new incompatible claims. A drain timeout means an application claim remained too long. Find the claim holder, application owner, SQL, transaction age, and whether work is active or idle. A long cursor, uncommitted batch update, forgotten connection, or continuous application traffic can all block the utility.

Coordinate before canceling production work. The safest action may be a normal commit, ending an idle session, pausing traffic, or rescheduling the utility. Increasing UTIMOUT only allows a longer wait; it does not make the claim disappear. Also inspect retry behavior and the utility's options so repeated drain attempts do not create an avoidable application impact.

Utility failure triage
FailurePreserve and inspectSafe direction
CHECK INDEX failureUtility return code, messages, object state, inconsistent key detailsPreserve output, determine whether data or index is inconsistent, then use the documented repair path
REBUILD INDEX failurePhase, failing data set, space, sort, I/O, authorization, and object messagesCorrect the named resource problem and restart according to utility guidance
Utility drain timeoutUtility messages, active claim holders, unit-of-work age, application ownerResolve the holder or schedule conflict; do not merely extend the wait without evidence

Explain It Like I'm Five

Imagine Db2 is a supermarket. A slow query is a shopper taking too long, but you should not immediately build a new checkout lane. First watch what happened. Did the shopper lose the aisle map and walk past every shelf? That is like losing an index and scanning. Did too many shoppers reach for the same freezer door? That is lock contention. Did carts fill every aisle? That resembles thread buildup. Did the cleaning crew wait because one shopper would not leave? That is a utility drain wait. EXPLAIN is the planned route through the store, while accounting and statistics show what the trip actually cost. Good troubleshooting compares the old trip with the new one before moving shelves.

Exercises

  • Create a baseline worksheet for a query regression. Include elapsed time, CPU, getpages, reads, rows returned, sorts, lock waits, package, member, and input values.
  • Explain three valid reasons why Db2 might prefer a scan over an index, then list the EXPLAIN and RUNSTATS evidence you would use to test each reason.
  • A statement's getpages doubled but physical reads stayed flat. Describe what this proves, what it does not prove, and which metric you would inspect next.
  • Draw a two-thread deadlock. Label the held and requested locks, then propose an application change that prevents the cycle.
  • A utility timed out waiting for a drain. Write a safe five-step response that identifies the claim holder before any cancellation decision.
  • Compare CHECK INDEX and REBUILD INDEX. Explain what each utility does and why their failure messages must be preserved before choosing corrective action.

Quiz

Test Your Knowledge

1. What should you do first when a Db2 query is suddenly slow?

  • Rebind every package
  • Increase every buffer pool
  • Define the time window and capture comparable evidence
  • Cancel all DDF connections

2. Why might Db2 change from index access to a table-space scan?

  • A scan is always an error
  • Statistics, predicates, data distribution, indexes, or bind context changed
  • Indexes expire every night
  • Buffer pools prohibit indexes

3. What does a getpage increase usually tell you?

  • Db2 performed more logical page requests
  • Every page request caused disk I/O
  • A deadlock occurred
  • DDF stopped

4. Which evidence is most useful for a lock timeout?

  • Only the timeout count
  • Waiter, holder, object, lock mode, SQL, and unit-of-work age
  • Only the buffer-pool hit ratio
  • Only the package name

5. What is the best first response to a utility drain timeout?

  • Keep raising the timeout forever
  • Drop the table space
  • Identify the claim holder and why it remains active
  • Delete utility output

6. Why is an overall buffer-pool hit ratio insufficient by itself?

  • Hit ratios are never calculated
  • A combined percentage can hide one hot object or changed read pattern
  • It measures only locks
  • It proves that CPU is low

Frequently asked questions

How do I troubleshoot a DB2 query that suddenly became slow?

First establish the regression window and identify the exact SQL, package or statement token, workload, and subsystem member. Compare Db2 accounting data, elapsed and CPU time, getpages, reads, sorts, and lock waits against a healthy baseline. Then compare EXPLAIN access paths and verify changes to RUNSTATS, indexes, binds, data volume, predicates, and subsystem conditions.

Why did DB2 stop using an index and start scanning?

Db2 chooses the eligible access path with the lowest estimated cost. It may favor a table-space scan after data growth, changed distribution statistics, stale or default statistics, a dropped or altered index, a predicate change, host-variable selectivity assumptions, or a bind and optimizer-level change. Compare old and new EXPLAIN evidence before forcing an index.

Are DB2 getpages the same as physical disk reads?

No. A getpage is a logical request for a page. The page can already be in a buffer pool, or Db2 may need I/O to read it. Compare getpages with synchronous and prefetch reads to distinguish extra logical processing from extra physical I/O.

What causes DB2 sort activity to increase?

Common causes include a changed access path, ORDER BY, GROUP BY, DISTINCT, merge scan joins, large intermediate results, inaccurate cardinality estimates, and lost index ordering. Use EXPLAIN sort indicators together with accounting sort counts and work-file statistics.

How should I investigate DB2 deadlocks and timeouts?

Capture both the waiter and holder, the locked object, lock mode, SQL, transaction age, commit behavior, and order in which resources are accessed. A deadlock is a cycle and requires a victim; a timeout is a wait that exceeded its limit without necessarily forming a cycle.

What should I do after CHECK INDEX reports a failure?

Keep the complete utility output and identify the object, inconsistency, return code, and resulting object state. Determine whether the index, data, or both require corrective action. Follow the documented Db2 procedure for the installed release and protect recoverability; do not use REPAIR casually.

Why does a DB2 utility receive a drain timeout?

The utility could not acquire the required drain because one or more application claims remained. Identify the claim holders, active SQL, and unit-of-work age, then coordinate a safe commit, application stop, or utility reschedule. Increasing UTIMOUT only changes how long the utility waits.