I have written previously about partitioning the PS_LEDGER table in Financials for the benefit of General Ledger (GL) reporting. I have always recommended top-level range partitioning on the combination of FISCAL_YEAR and ACCOUNTING_PERIOD with separate partitions for each accounting period. It also leaves sub-partitioning available to use another column, usually LEDGER.
- PeopleSoft DBA blog: nVision Performance Tuning: 4. Partitioning of Ledger, Ledger Budget, and Summary Ledger Tables
- Go-Faster blog: Retrofitting Partitioning into Existing Applications: Example 1. General Ledger
However, recent research into partition change tracking (PCT) and materialized views has made me question that advice. The decision is not as clear cut.
Summary Ledgers or Materialized Views
You can create summary ledger tables in PeopleSoft Financials that are incrementally maintained by batch processes, and then nVision reports can reference the summary ledgers instead. If the summary ledgers are not up to date, then the reports will produce out of date results.
Similarly, materialized views can be used in an Oracle database to create pre-generated reporting tables. An application can reference a materialized view directly, or the database can dynamically rewrite submitted SQL queries to use the materialized view if they are sufficiently similar to the query that created the materialized view and if the optimizer judges that it is cheaper to query the materialized view. By default, the database will check that the materialized view is up to date, that is no change has been made to the underlying tables since the last refresh commenced, before it can rewrite the SQL query. So the query will always return the same data, but if the materialized view is out of date you don't get the performance improvement.
You can optionally choose to configure the database to write SQL queries to use stale materialized views by setting QUERY_REWRITE_INTEGRITY=stale_tolerated at either database or session-level.
Materialized views can be created for the nVision queries that you wish to optimise, and no further code change is required because the database will rewrite the SQL. You can see a typical example of this in my blog about PCT.
Partition Change Tracking is a mechanism the Oracle database uses to 'track freshness to a finer grain than the entire materialized view'. It can identify which partitions and subpartitions are fresh and can be used for query rewrite, and to refresh just the partitions that are stale or that contain stale sub-partitions.
Alternatives for Partitioning PS_LEDGER
If you wish to create materialized views on the main ledger table, and rely upon query rewrite, and keep the materialized views up to date with respect to the ledger table, and only use them when they are up to date, then you probably want PCT to help with both rewrite and refresh.
1. Multi-column composite partitioning
I usually like to range partition PS_LEDGER on the combination of FISCAL_YEAR and ACCOUNTING_PERIOD to produce a separate range partition for each accounting period. Partition pruning works very effectively with the SQL generated by nVision. It also allows sub-partitioning on another column, usually LEDGER. This is desirable when a system has multiple actuals ledgers, and especially since 9.2 where the budget data is also stored in PS_LEDGER rather than PS_LEDGER_BUDG.
However, amongst the documented restrictions of PCT is that partitioned tables must use either range, or list partitioning, or composite partitioning with range or list as the top-level partitioning strategy. Also, the top-level partition key must consist of only a single column (see Database Data Warehousing Guide -> Advanced Materialized Views -> About Partition Change Tracking)
If I want to use query rewrite to materialized views for queries on LEDGER table then I have a few choices.
- If I stick with multi-column range partitioning, then I cannot use PCT. I must either keep the materialized views fresh, or the queries remain on the ledger table. Any update to any partition in the ledger table will render the entire materialized view stale and prevent query rewrite. Many customers run a suite of nVision reportbooks overnight. I could set QUERY_REWRITE_INTEGRITY=stale_tolerated at session-level for the report books processes using a trigger on the process scheduler request table (PSPRCSRQST) - see Setting Oracle Session Parameters for Specific Process Scheduler Processes. In this case, I would have to take responsibility for refreshing the materialized views prior to running, say, a suite of report processes. This is effectively the same situation as using summary ledgers, but without code change to the reports.
- I have created materialized views on summary ledger tables in order to provide compressed copies of the summary ledger. Again, in this case, the materialized views had to be refreshed after the summary ledger maintenance process.
- Or, I have to produce a simpler partitioning strategy for the ledger table that is still compatible with PCT.
2. Composite Range-Range Partitioning on FISCAL_YEAR and ACCOUNTING_PERIOD
I could composite partition both the LEDGER table and the materialized views by FISCAL_YEAR and ACCOUNTING_PERIOD, but then I cannot further subpartition by other columns. This would degrade queries on smaller ledgers that could not be rewritten to dedicated materialized views.
CREATE TABLE ps_ledger
(business_unit VARCHAR2(5) NOT NULL
…
) PCTFREE 10 PCTUSED 80
PARTITION BY RANGE (FISCAL_YEAR)
SUBPARTITION BY RANGE (ACCOUNTING_PERIOD)
SUBPARTITION TEMPLATE
(SUBPARTITION ap_bf VALUES LESS THAN (1)
,SUBPARTITION ap_01 VALUES LESS THAN (2)
,SUBPARTITION ap_02 VALUES LESS THAN (3)
,SUBPARTITION ap_03 VALUES LESS THAN (4)
,SUBPARTITION ap_04 VALUES LESS THAN (5)
,SUBPARTITION ap_05 VALUES LESS THAN (6)
,SUBPARTITION ap_06 VALUES LESS THAN (7)
,SUBPARTITION ap_07 VALUES LESS THAN (8)
,SUBPARTITION ap_08 VALUES LESS THAN (9)
,SUBPARTITION ap_09 VALUES LESS THAN (10)
,SUBPARTITION ap_10 VALUES LESS THAN (11)
,SUBPARTITION ap_11 VALUES LESS THAN (12)
,SUBPARTITION ap_12 VALUES LESS THAN (13)
,SUBPARTITION ap_cf VALUES LESS THAN (MAXVALUE))
(PARTITION ledger_2018 VALUES LESS THAN (2019) PCTFREE 0 COMPRESS
,PARTITION ledger_2019 VALUES LESS THAN (2020) PCTFREE 0 COMPRESS
,PARTITION ledger_2020 VALUES LESS THAN (2021)
,PARTITION ledger_2021 VALUES LESS THAN (2022)
)
ENABLE ROW MOVEMENT NOLOGGING
/
CREATE MATERIALIZED VIEW mv_ledger_2020
PARTITION BY RANGE (FISCAL_YEAR)
SUBPARTITION BY RANGE (ACCOUNTING_PERIOD)
SUBPARTITION TEMPLATE
(SUBPARTITION ap_bf VALUES LESS THAN (1)
,SUBPARTITION ap_01 VALUES LESS THAN (2)
,SUBPARTITION ap_02 VALUES LESS THAN (3)
,SUBPARTITION ap_03 VALUES LESS THAN (4)
,SUBPARTITION ap_04 VALUES LESS THAN (5)
,SUBPARTITION ap_05 VALUES LESS THAN (6)
,SUBPARTITION ap_06 VALUES LESS THAN (7)
,SUBPARTITION ap_07 VALUES LESS THAN (8)
,SUBPARTITION ap_08 VALUES LESS THAN (9)
,SUBPARTITION ap_09 VALUES LESS THAN (10)
,SUBPARTITION ap_10 VALUES LESS THAN (11)
,SUBPARTITION ap_11 VALUES LESS THAN (12)
,SUBPARTITION ap_12 VALUES LESS THAN (13)
,SUBPARTITION ap_cf VALUES LESS THAN (MAXVALUE))
(PARTITION ledger_2019 VALUES LESS THAN (2020)
,PARTITION ledger_2020 VALUES LESS THAN (2021)
) PCTFREE 0 COMPRESS PARALLEL
REFRESH COMPLETE ON DEMAND
ENABLE QUERY REWRITE AS
SELECT business_unit, account, chartfield1, fiscal_year, accounting_period,
sum(posted_total_amt) posted_total_amt
FROM ps_ledger
WHERE fiscal_year >= 2019
AND ledger = 'ACTUALS'
AND currency_cd = 'GBP'
GROUP BY business_unit, account, chartfield1, fiscal_year, accounting_period
/
Note that I have equality criteria on LEDGER and CURRENCY_CD in the materialized view, but I have not included those columns in the select clause, and so they are not in the view. Oracle can still rewrite queries to use this materialized view and that specify the same criteria on PS_LEDGER
PCT will determine whether any unpruned partitions or subpartitions are stale and if so prevent query rewrite. It is documented behaviour that the materialized view refresh will truncate and rebuild the whole top-level partitions, in this case each fiscal year, where the partition or any constituent sub-partitions are stale. So even if just one subpartition, for one accounting period is stale, the whole fiscal year is refreshed.
3. Composite Range-Range Partitioning on ACCOUNTING_PERIOD and FISCAL_YEAR
I investigated making ACCOUNTING_PERIOD the top-level partitioning key, and sub-partitioning on FISCAL_YEAR.
- Partitioning pruning works correctly, so the query performance will be unaffected,
- PCT refresh processed all years for the single accounting period, rather than all accounting periods for the single year. That is less work if you have fewer fiscal years than accounting periods. Generally, this is the case. I usually see systems that contain 3 to 6 fiscal years of data.
However, it has a number of problems.
- I can't specify storage options or compression attributes on sub-partitions in the create table DDL command, so I have to come along afterwards with PL/SQL to alter the sub-partitions.
- It is not possible to interval range sub-partition an object, so I can't automatically add partitions for future fiscal years on demand. Instead, I am going to have to add new fiscal year subpartitions to each of the 14 range partitions.
On balance, I don't think I would choose to implement this.
Conclusion
There is no single clear recommendation for partitioning and PCT. It will depend on the circumstances.
- If I don't need to introduce materialized views on PS_LEDGER then I would usually stick with the multi-column composite partitioning with the top-level range partition on FISCAL_YEAR and ACCOUNTING_PERIOD.
- PeopleSoft provides summary ledgers to improve the performance of the ledger queries and compressed materialized views can be built on these.
- If you only have a single actuals ledger then composite range-range partition on FISCAL_YEAR and ACCOUNTING_PERIOD is attractive.
- I do not recommend interval partitioning on FISCAL_YEAR because this affects the scope of the refresh process. It processes a second top-level range partition.
- If the budget data is stored in the PS_LEDGER table rather than LEDGER_BUDG then consider building separate materialized views for each value of LEDGER.
- If you can manage to build materialized views to support rewrite of most the queries on the smaller ledgers, then the lack of sub-partitioning by LEDGER is not going to be a problem unless the query doesn't get rewritten because the materialized views are stale. Keeping the materialized views up to date is going to be a bigger challenge.