Reorgs are one critical piece of both performance maintenance and maintaining how much disk space is used. In my first blog entry in this series, DB2 Basics: What is a Reorg, I talked about some purposes of reorgs. In this entry, I’m going to talk about how to determine what kind of reorg is needed on what tables. I will have a future blog entry to discuss index reorgs in detail. The advice I’m giving here is directed at single-partition databases with non-partitioned tables.
Reorg’s Place in the Database Maintenance Cycle
I run a standard maintenance cycle weekly. It consists of:
- RUNSTATS on all tables (yes, including system tables)
- REORGCHK on all tables
- REORGS of tables that indicate a need
- RUNSTATS on tables that have been REORGed
- rbind with the \all option
- flush package cache
REORGCHK
Reorgchk is a DB2 utility that calculates a number of formulas to determine what kinds of reorgs are needed on what tables. You can run reorgchk on a single table, on a schema, or on all tables in a database. While you can optionally have reorgchk update statistics, I do not recommend it. Reorgchk is supposed to detect the type of statistics that were last gathered and base what kind of statistics on that, but do you really want to take the chance with something as critical as RUNSTATS? Since I have scripts already from older versions, I collect runstats first, then run reorgchk.
The Reorgchk page in the Knowledge Center actually has a lot of good information on it. It tells you things like the recommended types of reorgs based on the output of reorgchk.
The simplest form of the reorgchk command is this:
db2 "reorgchk current statistics on table all" >reorgchk.out
Running that statement requires a database connection. The output may be extensive, especially if you have a significant number of tables.
When you run reorgchk, there are two sections – one for tables and one for the indexes on tables. To make things easier, those are covered separately below.
Tables
The table section of reorgchk looks something like this:
Table statistics: F1: 100 * OVERFLOW / CARD < 5 F2: 100 * (Effective Space Utilization of Data Pages) > 70 F3: 100 * (Required Pages / Total Pages) > 80 SCHEMA.NAME CARD OV NP FP ACTBLK TSIZE F1 F2 F3 REORG ---------------------------------------------------------------------------------------- Table: WSCOMUSR.ATTRIBUTE 0 0 0 68 - 0 0 0 0 -** Table: WSCOMUSR.ATTRTYPE 7 0 1 1 - 448 0 - 100 --- Table: WSCOMUSR.ATTRVAL 29097 653 623 624 - 2473245 2 99 100 --- Table: WSCOMUSR.ATTRVALDESC 29013 6 874 874 - 3452547 0 99 100 --- Table: WSCOMUSR.ATTRVALUE 0 0 0 1386 - 0 0 0 0 -** Table: WSCOMUSR.DMEXPLOG 34165 0 847 1056 - 3348170 0 79 80 --* Table: DBAMON097.TABLE_HIST_CRON 256149 0 1652 2284 - 53535140 0 71 72 --*
The above output gives a lot of information including information on the size of the tables. There are three formulas that reorgchk calculates – F1, F2, and F3. They are described at the top of the reorgchk output, and calculated for each table. The column at the far right is what tells us that a table reorg is actually needed. Note that there are three values – either dashes -
or asterisks *
. Each of these represents one of the three formulas, in order. An asterisk indicates that a table reorg is needed for that table, based on the results of that specific query.
F1
F1 is described in the reorgchk header as:
F1: 100 * OVERFLOW / CARD < 5
What this formula is looking for is overflow records. In DB2 a row is stored contiguously on a single page. When actions like updates to VARCHAR columns cause a row to no longer fit on a page, DB2 will replace the original row on the page with a pointer to the new location for the row. If more than one relocation of the row is done, the original location is updated with the true location, so DB2 never has to do more than one hop to get from the pointer to the data. However, even that one hop means that the I/O (whether from bufferpool or from disk) is doubled, which can be detrimental to performance. A reorg will get rid of these pointers and ensure the data is in the location within the table where it is expected to be. This process involves updating the row’s rid, and thus indexes must be rebuilt or changed to match the new location.
Formula F1 looks to ensure that 5% or less of the total rows in the table are overflows. I’m going to share SQL I’ve used to calculate these values manually back in version 8.2 and 9.7. Use it at your own risk, and I have not verified it on 10.1 or 10.5.
For F1, this is a handy query to find tables that need reorgs:
select substr(tabschema,1,18) as tabschema, substr(tabname,1,30) as tabname, card, overflow, case when card > 0 then decimal(100*(float(overflow)/float(card)),10,2) else -1 end as F1 from syscat.tables where overflow >0 with ur
I’m not suggesting you make use of the SQL above, but just providing it for information. It gives output that looks like this:
TABSCHEMA TABNAME CARD OVERFLOW F1 ------------------ ------------------------------ -------------------- -------------------- --------------- SYSIBM SYSTABLES 11298 141 1.24 SYSIBM SYSCOLUMNS 36135 87 0.24 SYSIBM SYSINDEXES 6404 22 0.34 SYSIBM SYSPLANDEP 1666 1 0.06 WSCOMUSR CLEANCONF 163 1 0.61 SYSTOOLS HMON_ATM_INFO 1841 1138 61.81 SYSTOOLS ADMIN_MOVE_TABLE 18947 26 0.13
F2
F2 is described in the reorgchk header as:
100 * (Effective Space Utilization of Data Pages) > 70
While that’s a good human description of what reorgchk is looking for, it’s not very technical. This formula tells us how effectively DB2 is making use of space on pages. As a result, it is likely to be flagged for extremely small tables. I eliminate tables with a cardinality of 0 from reorgs, because they are sometimes flagged on this formula, and it wastes time.
I don’t have SQL that works for this formula. I played with it some, and don’t have it. Basically what DB2 does for this one is to calculate how many bytes would be used based on the cardinality and the average row size, and then calculates the size of the table based on the current number of pages, and looks for how close the value based on pages is to the value based on cardinality. Some table geometries will always cause this one to be flagged.
F3
F3 is described in the reogchk header as:
100 * (Required Pages / Total Pages) > 80
Basically DB2 is checking to make sure that the total pages in the table is not more than 20% higher than the required number of pages.
The sql calculation is much easier here, again use this SQL at your own risk:
select substr(tabschema,1,18) as tabschema, substr(tabname,1,30) as tabname, npages, fpages, case when fpages >0 then decimal(100 * (float(npages)/float(fpages)),5,2) else -1 end as F3 from syscat.tables where type='T' and npages >1 and fpages >1 with ur
The output looks like this:
TABSCHEMA TABNAME NPAGES FPAGES F3 ------------------ ------------------------------ -------------------- -------------------- --------------- SYSIBM SYSTABLES 1363 1363 100.00 SYSIBM SYSCOLUMNS 2112 2114 99.90 SYSIBM SYSINDEXES 658 660 99.69 SYSIBM SYSVIEWS 57 57 100.00 SYSIBM SYSVIEWDEP 53 53 100.00 SYSIBM SYSPLAN 68 68 100.00 SYSIBM SYSPLANDEP 51 51 100.00 SYSIBM SYSSECTION 85 87 97.70
Table Reorg Decisions
One approach for scripters of reorgs is to parse out the table name for any row with a *
. That actually works in this table reorg section, but does not in the index section I’ll talk about in a future post. There’s a boon in recent versions for people who want to script this. The REORGCHK_TB_STATS procedure can be used to return this information in a more friendly format for scripting. It is executed like this:
db2 "call REORGCHK_TB_STATS('T','SYSIBM.SYSCOLUMNS')" Result set 1 -------------- TABLE_SCHEMA TABLE_NAME DATAPARTITIONNAME CARD OVERFLOW NPAGES FPAGES ACTIVE_BLOCKS TSIZE F1 F2 F3 REORG -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- ----------- ----------- ----------- ----- SYSIBM SYSCOLUMNS 36135 87 2112 2114 -1 8021970 0 94 100 --- 1 record(s) selected.
But that’s not all. That alone is just a different format of data to parse through for the values. Running that populates a table called SESSION.TB_STATS that is session specific that you can now query to get particular values like this:
select substr(table_schema,1,18) as tabschema, substr(table_name,1,30) as tabname, f1, f2, f3, reorg from SESSION.TB_STATS TABSCHEMA TABNAME F1 F2 F3 REORG ------------------ ------------------------------ ----------- ----------- ----------- ----- SYSIBM SYSCOLUMNS 0 94 100 --- 1 record(s) selected.
I learned that nifty trick over at Phillip Carrington’s blog. I haven’t tried out the rest of his methodology, but thought that tip was good.
Calling REORGCHK_TB_STATS this way should collect data for all tables:
call REORGCHK_TB_STATS('T','ALL')
Selecting Table Reorg Syntax
Any syntax choices at this point are not determined by the reorgchk output but by other properties of the reorg. There are two basic options you have – classic or inplace. The former is also referred to as offline. Inplace can be referred to as online, but it is not fully online (see When is a Reorg Really Online?)
The Knowledge Center has a good page on reorg syntax.
Classic Table Reorgs
The most obvious disadvantage of classic reorgs is that the table is unavailable for significant portions of them. Because of this and the availability requirements of the e-commerce databases I work with, I don’t often do this kind of reorg. You can specify ALLOW READ ACCESS
to allow some access to the table while the reorg is occurring. One of the “advantages” of a classic reorg is that you can specify a temporary tablespace for the reorg to use. Be careful, though – the reorg may require a good three times the table size if you specify a temporary tablespace, and should only require around two times the table size if you do not specify one. Classic reorgs can also be used to reorganize LOB data – which you should not be doing on a regular basis, but may have to do to free up space from deleted LOBs or to inline LOBs.
Inplace Table Reorgs
I run inplace table reorgs on a regular basis. They are largely online. They also have the advantage of only moving small amounts of data at time so you don’t have to have two to three times the size of your table in available space. The big disadvantage here is in transaction log space. Inplace reorgs eat transaction log space like nothing else, so be prepared. Usually, the ALLOW WRITE ACCESS
keywords are specified for inplace reorgs. While it involves not releasing any empty pages at the end of the table at the end of the reorg, specifying NOTRUNCATE TABLE
does make for the most online reorg possible.
Keep in mind that an inplace reorg is an asynchronous operation – the command will return right away, but the reorg will continue to run in the background. This means you can easily tank your server if you improperly script these and reorg every table in your database at the same time. It is critical to control for how many online reorgs are running at once. There are options on the reorg command that will allow you to stop or to pause running inplace reorgs.
Running online reorgs write data to the history file. You can also use SNAPTAB_REORG to query reorg statuses for running and recently completed reorgs. db2pd also provides data. I think that monitoring and querying reorg statuses will have to be a separate blog entry.
THANK YOU, Ember! This is the kind of stuff I was hoping to find on REORGCHK that I just was not finding!
[…] How to Tell When a Table Reorg is Needed […]
Great information and SQL examples, as usual, thank you Ember. But, I disagree. REORGCHK should be deleted from sqllib/bin and never used. It can give REORG recommendations for tables that haven’t been read/accessed in many months. Instead, successful and smart DBAs should base their REORG decisions on table performance data – specifically, Overflows and Rows Read. When (Overflows * 100)/Rows Read > 3%, REORG a table to mitigate double I/Os. Learn more and find SQL here: http://www.dbisoftware.com/blog/db2_performance.php?id=116
In DB2 10.5, there’s a new REORG option that very quickly fixes the double I/O overhead of Overflows by correcting the pointers: INPLACE … CLEANUP OVERFLOWS.
The clever DBA will write a query against SYSIBMADM.SNAPTAB to generate REORG commands for tables where Overflows/Rows Read > 3%. Smarter DBAs will use DBI’s Brother-Hawk to fully automate the REORGs.
There are always different views on what requires a reorg, which is why I provide this information, so people can understand the IBM party line on it and what those formulas are really doing under the covers. Thanks for your additional details, Scott.
Thanks Ember for your article.
I quite don’t understand the meaning of wasting time in your sentence: “I eliminate tables with a cardinality of 0 from reorgs, because they are sometimes flagged on this formula, and it wastes time”.
If a table is wiped completely F2 will be flagged for the table but because it has cardinality 0 would you not reorg it?. I’m just referring a generic situation. In a real situation you would need further analyze the future use of that table.
Regards!
In vended databases, there are often a number of tables that are always empty – for features you are not using. Obviously a newly deleted from table would not qualify, and would need a reorg.
[…] My earlier post on table reorgs covered Reorg’s place in a database maintenance cycle and running reorgchk. If you haven’t already read it, check it out: How to Tell When a Table Reorg is Needed […]
[…] can be found on the IBM Knowledge Center, but I would certainly advice you to have a look at Ember Crooks DB2Commerce website for an excellent article on […]
Hi Ember,
Very useful article.But I have a doubt.Is it at all possible that after REORG performance may get degraded.Will rebind can help here?
Nothing is impossible. and runstats followed by rebind \all is always needed after reorgs.
I made a Korn shell script to check overflow access on tables over a period of time
#!/usr/bin/ksh
function Usage
{
echo “———————————————————————————————————”
echo “Usage : $(basename $0) DATABASE INTERVAL_IN SECONDS”
echo
}
# Load common functions
#. /db2scripts/common_script/ksh_functions
# Check unintialized variables
set -u
# Check input parameter
readonly NbInputParmReq=2
[[ $# != ${NbInputParmReq} ]] && Usage && FatalError “The script expects ${NbInputParmReq} input parameters and receives $#”
# Initialisation and declaration of variables
readonly BASEPATH=
readonly LOGFILE=$(basename $0)_${DB2INSTANCE}_$(hostname)_$(date +%Y-%m-%d-%H.%M.%S).log
integer RC_CMD=0
readonly DATABASE=$1
readonly INTERVAL=$2
# Action
{
#MsgStart
date
db2 connect to ${DATABASE}
print “create baseline tables”
db2 -v “declare global temporary table session.mon_table_baseline as (select current timestamp as snapshot_timestamp, a.* from table(mon_get_table(NULL,NULL,-2)) a) with no data on commit preserve rows” >/dev/null
print ” delete data from baseline table ( just in case )”
db2 -x “delete from session.mon_table_baseline” > /dev/null
print “insert baseline data into baseline table”
db2 -v “insert into session.mon_table_baseline select current timestamp as snapshot_timestamp, a.* from table(mon_get_table(NULL,NULL,-2)) a” > /dev/null
print ” wait the given interval ( ${INTERVAL} seconds )”
sleep ${INTERVAL}
print ” done sleeping”
#print ” collect the delta information and return the wanted information”
print ” Overflow Related Metrics ”
print ” ———————— ”
db2 -v ” select timestampdiff(2,char(timestamp(current timestamp)-b.snapshot_timestamp)) as snapshot_timestamp_diff_in_seconds,rtrim(substr(c.tabschema,1,25)) as TABSCHEMA,rtrim(substr(c.tabname,1,45)) as TABNAME,c.DATA_OBJECT_L_PAGES as Logical_pages_on_disk,c.OVERFLOW_ACCESSES-b.OVERFLOW_ACCESSES as OVERFLOW_ACCESSES, c.rows_read – b.rows_read as ROWS_READ, (c.OVERFLOW_ACCESSES-b.OVERFLOW_ACCESSES) *100 /( c.rows_read – b.rows_read) as PCT_OVERFLOW_ACCESSES_ROWS_READ from table(mon_get_table(NULL,NULL,-2)) c join session.mon_table_baseline b on c.tabschema=b.tabschema and c.tabname=b.tabname and c.MEMBER=b.MEMBER where c.rows_read-b.rows_read > 0 order by 5,6,7 desc fetch first 50 rows only”
print “End of the script – `date`”
#} > ${LOGFILE}
} | tee ${LOGFILE}
query is not running from the application side, it is not getting aborted also. and the last runstats for the table was ran on 2014. in this case as a db2dba what should i do ?
thanks
i appreciate your time in this.
There are a lot of possible issues. You’ll want to do runstats – unless the data is truely unchanging, they should be done daily or weekly. It could also be a locking issue – you may want to look for lock-waits in db2top, and review your setting for LOCKTIMEOUT (-1 means “wait forever”). Then there’s a whole art to query tuning if it isn’t either of those. Perhaps an index is needed.
Hello Ember,
Recently on of the user is facing performance issue, in accessing the database. I’ve done the reorgchk and everything seems fine and doesn’t require any reorgs for the table. And also in the database there is no deadlocks. Can I know what might be the possible cause for this. Is there some problem with the db side or with the application. Kindly suggest. Thanks Much
I could write a book on this topic – literally. I assume runstats are current? I would be looking at the access plan (using some method of explain) and if I could add indexes to help it (using db2advis and other methods).
Hi. Thanks for the very informative blog. Well, its 2020 now and I am on DB2 mainframe version 12. I am not able to run reorgchk, and I am wondering if it has been deprecated. I can’t find it in a manual more recent than 11.5. If it is deprecated, is there another command to perform a similar function? Thanks again for any information.
I got some more information and it looks like reorgchk has never been an option on the mainframe db2. I know now to look more closely at the product name in the documentation I find online.
Yep, that’s the answer. Db2 for z/OS and for LUW are very different products.
Should we do offline reorg for a >50gb tables in prod? Trying to do it as part of implementing adaptive compression to gain space after enabling compression. We don’t know much time it takes.
What are the risks?
You really have to do the reorg to get the compression fully implemented. Part of the catch-22 here is that reorg itself takes space on disk. A standard offline reorg can take up to 100% of the table space, and if you reorg on an index, it can be up to about 200%. Often the reason for implementing compression is disk space constraints. So make sure you have the space first.
If the outage caused by reorg is a problem, consider using admin_move_table instead. It can rebuild the table while keeping it mostly online. If you use the multi-phase syntax, you can control when the outage for the final swap takes place. This also takes up to 100% of the space for the table, so make sure you have the space.