Friday, December 28, 2018

Db2 for z/OS Partitioned Table Spaces: How the Number of Partitions can Impact Performance

This past summer, I delivered a couple of presentations at a meeting of a regional Db2 users group in the USA. During the lunch break, I shared a table with a member of the Db2 for z/OS support team at a large financial institution. He told me an interesting story. At his site, the Db2 for z/OS team had decided that universal partition-by-range (PBR) would be a better table space type for a large table currently housed in a partition-by-growth table space (PBG). To prove out this assessment, the team created a copy of the table of interest in a PBR table space, and ran some batch jobs that targeted the two variants of the table - the same jobs (some that changed data, others that only read data), accessing data that was identical in a logical sense (i.e., same data records in the tables in the two different table spaces). The performance characteristics of the PBG-accessing and the PBR-accessing jobs were compared.

The findings? The PBG-accessing jobs showed consistently better elapsed and CPU times versus the PBR-accessing jobs. That was not a result I would have expected. I've blogged before about reasons for favoring PBR over PBG for large Db2 tables, and some of those reasons are performance-related. Would I have been surprised by comparative results showing roughly equivalent performance for PBG-accessing and PBR-accessing jobs? Maybe not. But better performance for the PBG-accessing jobs? That had me scratching my head.

I asked the Db2 person at the user group meeting to send me Db2 performance monitor accounting "long" reports capturing activity for the PBR-accessing and PBG-accessing jobs, and he did that not long after getting back to his workplace. Analysis was focused on the package-level accounting data for a particular package that accessed only the table with the PBR and PBG variants (other packages associated with the batch jobs used for comparison accessed the PBR-and-PBG-variant table and several other related tables as well). Sure enough, for the "this table only" package the CPU time was about 6% higher for the PBR-housed table versus the PBG-housed table. Not a huge difference, but statistically significant and, as previously mentioned, unexpectedly favoring the PBG table space.

I started asking questions, looking for a possible explanation for the better performance result seen for the PBG-accessing package:

  • Was the SEGSIZE specification the same for both table spaces (a larger SEGSIZE value can result in better CPU-efficiency for large-scale page scans)? Yes, same SEGSIZE for both table spaces.
  • Was the PBR table space in fact universal, as opposed to being a non-universal table-controlled partitioned table space (I wanted to make sure that we were comparing universal to universal)? Yes, the PBR table space was indeed of the universal variety.
  • Were the PBG-housed and PBR-housed tables clustered by the same key (clustering affects locality of reference for set-level query and update and delete operations)? Yes, both variants of the table had the same clustering key.
  • Were there indexes defined on the same keys of both tables (obviously, indexes have a lot to do with query access paths, and they affect the CPU cost of insert and delete and some update operations)? For both the PBG-housed and the PBR-housed table, there was only one index, and it was defined on the same key.
  • Were the PCTFREE and FREEPAGE specifications the same for the one index on the two table variants (a significant difference here could affect index GETPAGE counts)? Yes, for the one index defined on the same key of both table variants, the PCTFREE and FREEPAGE values were identical.
  • Was the one index on the PBR-housed table a partitioned index or a non-partitioned index (NPI)? It was a partitioned index, and by the way the PBR table space had 318 partitions (me, on getting that piece of information: "Hmmmm").

OK, so what prompted my "Hmmmm" on learning the number of the PBR table space's partitions? That number got me thinking, "318 is a pretty substantial number of data sets. Depending on the number of data sets associated with the PBG table space, that could be an important differentiating factor between the two." Indeed, it turned out that the PBG table space had far fewer data sets versus its PBR cousin. How could that influence CPU time for an application process? In this case, a clue came from a number in the aforementioned Db2 monitor accounting reports: the commit count for the batch process that accessed the table of interest: 204,004 over the 4-hour, 50-minute reporting interval (a little over 700 per minute). What does that have to do with the job's CPU time? Well, when the RELEASE specification for a package is COMMIT (the default), any and all "parent" locks acquired in executing the package will be released every time the application process driving the package's execution issues a commit (the package itself is also released from the application process's thread at each commit). We tend to think of "parent" locks as being table space-level locks, but in fact when a table space is partitioned the parent locks are at the partition level. If the application process's SQL statements are such that a large number of partitions are accessed in each unit of work, that means a lot of partition-level locks are acquired within each unit of work and released at commit time. That parent lock acquisition and release cost can be yet a bit higher in a data sharing environment (and such was the case in the situation I'm describing), because a significant percentage of global locks tend to be of the parent type.

I relayed to the Db2 support person my thinking about the impact that the number of PBR versus PBG partitions might have on the application process's CPU time. He got together with the larger Db2 team at his site, and they decided to repartition the PBR table space in a way that dropped the number of partitions from 318 to 58, and voila - the application process's CPU time dropped to a level that was several percentage points below that seen for the PBG table space. Success!

Now, it's important to note that in this particular situation, a re-partitioning of the PBR table space was not a problematic change. Suppose you have a situation like the one I've described here, and re-partitioning your PBR table space is not a viable option? In that case, the in-Db2 CPU cost of an application process (likely a batch job) that accesses a large number of a table space's partitions within each unit of work could be reduced (especially if the job issues a large number of commits, resulting in a large number of units of work) via a rebinding of the associated Db2 package(s) with RELEASE(DEALLOCATE). That package bind option would cause the partition-level locks acquired as the batch job progresses to be retained until thread deallocation time (i.e., until end-of-job). That, in turn, would eliminate the overhead of releasing many partition-level locks at each commit (which locks would likely be re-acquired within the next unit of work), thereby reducing CPU time (I posted an entry on RELEASE(DEALLOCATE) considerations to this blog a few years ago - the part under the heading "Batch" is most relevant to the blog entry you're reading now). [Note: table space- and partition-level locks are almost always of the "intent" variety. Such locks are non-exclusive in nature, so retaining them across commits should not be a concern from a concurrency perspective.]

The bottom-line message here is NOT that you should always go for fewer rather than more partitions for a partitioned table space; rather, it is that the number of a table space's partitions can be a factor that affects CPU efficiency for some applications. A type of application for which this can matter is one that a) uses RELEASE(COMMIT) packages, b) is characterized by many units of work in the life of a thread, and c) accesses a large percentage of a table space's partitions in a typical unit of work. For such an application, CPU efficiency could potentially be improved by going with a smaller rather than a larger number of partitions for the target table space. When significant partition reduction is not an option for a table space, CPU time for an application process such as the one described in this blog entry could potentially be reduced by rebinding the application's Db2 packages with the RELEASE(DEALLOCATE) option.

7 comments:

  1. Hi Rob,
    I have pbr table-with part 1 to 19.The logical part & physical part was in same sequence(1...19)when I issued below alter
    ALTER TABLE xxxxxx
    ROTATE PARTITION FIRST TO LAST
    ENDING AT ('xxxx-11-30') RESET ;
    COMMIT;

    the logical part looked like this:
    LOGPART
    19
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    But in IBM site,-https://www.ibm.com/docs/en/db2-for-zos/13?topic=partitions-rotating
    it shows as new limitkey value with old part would get listed in bottom.

    P010 12/31/2005 catname.DSNDBx.dbname.psname.I0001.A010
    P011 12/31/2006 catname.DSNDBx.dbname.psname.I0001.A011
    P001 12/31/2007 catname.DSNDBx.dbname.psname.I0001.A001

    Can you clarify on this?

    ReplyDelete
  2. Rob,below is the screenshot from CA tool vs IBM site
    ca tool:
    PART LIMITKEYVAL LOGPART
    1 '2023-11-3> 19
    2 '2022-05-3> 1
    3 '2022-06-3> 2
    4 '2022-07-3> 3
    5 '2022-08-3> 4
    6 '2022-09-3> 5
    7 '2022-10-3> 6
    8 '2022-11-3> 7
    9 '2022-12-3> 8
    10 '2023-01-3> 9
    11 '2023-02-2> 10
    12 '2023-03-3> 11
    13 '2023-04-3> 12
    14 '2023-05-3> 13
    15 '2023-06-3> 14
    16 '2023-07-3> 15
    17 '2023-08-3> 16
    18 '2023-09-3> 17
    19 '2023-10-3> 18
    ibm site:
    PART LIMITKEYVAL LOGPART
    2 '2022-05-3> 1
    3 '2022-06-3> 2
    4 '2022-07-3> 3
    5 '2022-08-3> 4
    6 '2022-09-3> 5
    7 '2022-10-3> 6
    8 '2022-11-3> 7
    9 '2022-12-3> 8
    10 '2023-01-3> 9
    11 '2023-02-2> 10
    12 '2023-03-3> 11
    13 '2023-04-3> 12
    14 '2023-05-3> 13
    15 '2023-06-3> 14
    16 '2023-07-3> 15
    17 '2023-08-3> 16
    18 '2023-09-3> 17
    19 '2023-10-3> 18
    1 '2023-11-3> 19
    My question is:why ca tool shows a different order(first line & last line ) vs what we see from ibm site.which is right? I'm wondering ,may be any other ddl/any statements would have the order displayed in this way in ca tool?

    ReplyDelete
    Replies
    1. Pretty simple: the CA tool is listing partitions in physical order (left-hand side), with the corresponding logical partition to the right. The "IBM site" display is in logical partition order (right-hand side), with the corresponding physical partition to the left. It's just two different ways of looking at the same information.

      Robert

      Delete
    2. I faced the same situation like above user in my shop.The "PL" option showed below before rotate partition:
      ------------------------
      DEV1:
      ----------
      part limitkey logicalpart
      1 31-05-2023 1
      2 30-06-2023 2
      3 31-07-2023 3
      4 31-08-2023 4
      5 30-09-2023 5
      On Executing:
      Alter table tablename rotate partition first to last ending at ('xxx') reset;
      It looked like below :
      part limitkey logicalpart
      1 31-10-2023 5-->new limitkey replaced old key & moved to top
      2 30-06-2023 1
      3 31-07-2023 2
      4 31-08-2023 3
      5 30-09-2023 4
      But same rotate partition command issued in other environment on same table looks like below .how is that possible? Table defintion/structure is all same across environment.
      part limitkey logicalpart
      1 30-06-2023 1
      2 31-07-2023 2
      3 31-08-2023 3
      4 30-09-2023 4
      5 31-10-2023 5----------->stays at bottom with new limitkey,but oldest limitkey is removed.

      Delete
    3. I don't know what you mean by "other environment." If you are talking about two different Db2 for z/OS systems, and if the same tool or same query is used in both cases to return table partition information, you should get consistent results. I do not know why you appear to be getting inconsistent results, if the circumstances are in fact equivalent.

      Robert

      Delete
  3. Hello Rob ,
    IBM website states that after we rotate partition,
    the partition is not placed in REORG-pending (REORP) status, "if the table is large, or if the last partition before the rotation is empty."
    1)What does it mean by "large"? Is it large tablespace type or size of table?
    2)Even if the last partition of table is not empty, the table was not placed in reorg pending after partition rotation.I have never seen the object in REORP after rotate.Any idea
    https://www.ibm.com/docs/en/db2-for-zos/12?topic=partitions-rotating

    ReplyDelete
    Replies
    1. I suspect that the reference to a "large" table is a mistake on that particular page of the documentation, as there is no reference to "large" tables in the information about rotating partitions that is found in the documentation on the ALTER TABLE statement (https://www.ibm.com/docs/en/db2-for-zos/13?topic=statements-alter-table). As far as I know, "large" was never a technical specification for a table. A LONG time ago, a table space could be defined as LARGE, which meant that its data sets could be up to 4 GB in size (this was before the DSSIZE specification came along).

      Regarding REORG-pending status, there's no reason to place a whole table space in REORP status just because you're rotated a partition from first to last. In some circumstances, the last two partitions of a range-partitioned table space could be placed in REORP status as a result if a ROTATE PARTITION FIRST TO LAST action. These circumstances are described on the aforementioned documentation page on the ALTER TABLE statement (https://www.ibm.com/docs/en/db2-for-zos/13?topic=statements-alter-table), under the heading, "Rotating a partition from first to last."

      Robert

      Delete