In each PeopleSoft product, certain tables usually grow to become the largest in the implementations at most customers. The challenges they present and the options for dealing with them also are common to most systems. Most PeopleSoft Financials systems use General Ledger. In General Ledger, the ledger, summary ledger and journal line tables are usually the largest tables, and present the biggest challenges.
This is the first of five articles where I look at the challenges typically presented by queries on the journal line table (PS_JRNL_LN).
- Problem Statement
- Exadata System Statistics
- Partitioning
- Compression
- Conclusion
Problem Statement
In General Ledger, we typically see many queries on the ledger (or summary ledger) tables and also queries in the application, drill-down queries in nVision reporting, and ad-hoc PS/Queries that query details of journals posted to the ledger. Below is part of a typical query. The statement and execution plans below were taken from a PeopleSoft Financials system. It is running on Oracle 19c on Exadata. Making use of Exadata features will also be a topic.SELECT A.FISCAL_YEAR, A.ACCOUNTING_PERIOD, B.BUSINESS_UNIT, B.JOURNAL_ID, TO_CHAR(B.JOURNAL_DATE,'YYYY-MM-DD'), B.LEDGER, B.ACCOUNT
, B.PRODUCT, B.PROJECT_ID, B.CHARTFIELD1, B.CHARTFIELD2, B.CURRENCY_CD, B.AFFILIATE, SUM( B.MONETARY_AMOUNT), B.FOREIGN_CURRENCY
, SUM( B.FOREIGN_AMOUNT), A.REVERSAL_CD, A.REVERSAL_ADJ_PER, A.JRNL_HDR_STATUS, TO_CHAR(A.POSTED_DATE,'YYYY-MM-DD'), A.OPRID, A.DESCR254
, B.DEPTID, A.SOURCE, B.ALTACCT, TO_CHAR(CAST((A.DTTM_STAMP_SEC) AS TIMESTAMP),'YYYY-MM-DD-HH24.MI.SS.FF'), B.LINE_DESCR
FROM PS_JRNL_HEADER A, PS_JRNL_LN B
WHERE (A.BUSINESS_UNIT = B.BUSINESS_UNIT
AND A.JOURNAL_ID = B.JOURNAL_ID
AND A.JOURNAL_DATE = B.JOURNAL_DATE
AND A.UNPOST_SEQ = B.UNPOST_SEQ
AND A.JRNL_HDR_STATUS IN('P','V','U')
AND A.FISCAL_YEAR IN (2024)
AND A.ACCOUNTING_PERIOD BETWEEN 1 AND 12
AND B.CHARTFIELD1 IN ('1234567','1234568','1234569')
AND B.LEDGER IN ('LEDGER'))
GROUP BY A.FISCAL_YEAR, A.ACCOUNTING_PERIOD, B.BUSINESS_UNIT, B.JOURNAL_ID, B.JOURNAL_DATE, B.LEDGER, B.ACCOUNT, B.PRODUCT
, B.PROJECT_ID, B.CHARTFIELD1, B.CHARTFIELD2, B.CURRENCY_CD, B.AFFILIATE, B.FOREIGN_CURRENCY, A.REVERSAL_CD, A.REVERSAL_ADJ_PER
, A.JRNL_HDR_STATUS, A.POSTED_DATE, A.OPRID, A.DESCR254, B.DEPTID, A.SOURCE, B.ALTACCT, A.DTTM_STAMP_SEC, B.LINE_DESCR
- The journal line table (PS_JRNL_LN) is joined to its parent, the journal header table (PS_JRNL_HEADER), by the 4 key columns on the journal header (BUSINESS_UNIT, JOURNAL_ID, JOURNAL_DATE, UNPOST_SEQ).
- There are criteria on both the journal header and line tables.
- The number of journal line rows per header is usually highly variable, and it also varies from customer to customer depending on the shape of their data. It is not unusual to see thousands of journal line rows per header row. Filtering it by FISCAL_YEAR and perhaps also ACCOUNTING_PERIOD could be very effective. However, these columns are on PS_JRNL_HEADER, and not on PS_JRNL_LN.
- Queries often include criteria on other attribute columns on PS_JRNL_LN. However, these columns are not indexed by default, though many customers add such indexes.
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 428K| 93M| | 1730K (1)| 00:01:08 | | |
| 1 | HASH GROUP BY | | 428K| 93M| 111M| 1730K (1)| 00:01:08 | | |
| 2 | NESTED LOOPS | | 428K| 93M| | 1715K (1)| 00:01:07 | | |
| 3 | NESTED LOOPS | | 428K| 93M| | 1715K (1)| 00:01:07 | | |
|* 4 | TABLE ACCESS STORAGE FULL | PS_JRNL_HEADER | 428K| 41M| | 1476 (7)| 00:00:01 | | |
| 5 | PARTITION RANGE ITERATOR | | 1 | | | 3 (0)| 00:00:01 | KEY | KEY |
|* 6 | INDEX RANGE SCAN | PS_JRNL_LN | 1 | | | 3 (0)| 00:00:01 | KEY | KEY |
|* 7 | TABLE ACCESS BY LOCAL INDEX ROWID| PS_JRNL_LN | 1 | 128 | | 4 (0)| 00:00:01 | 1 | 1 |
------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 428K| 93M| | 66M (1)| 00:43:30 | | |
| 1 | HASH GROUP BY | | 428K| 93M| 111M| 66M (1)| 00:43:30 | | |
|* 2 | HASH JOIN | | 428K| 93M| 46M| 66M (1)| 00:43:30 | | |
| 3 | JOIN FILTER CREATE | :BF0001 | 428K| 41M| | 32501 (1)| 00:00:02 | | |
| 4 | PART JOIN FILTER CREATE | :BF0000 | 428K| 41M| | 32501 (1)| 00:00:02 | | |
|* 5 | TABLE ACCESS STORAGE FULL | PS_JRNL_HEADER | 428K| 41M| | 32501 (1)| 00:00:02 | | |
| 6 | JOIN FILTER USE | :BF0001 | 1132K| 137M| | 66M (1)| 00:43:28 | | |
| 7 | PARTITION RANGE JOIN-FILTER| | 1132K| 137M| | 66M (1)| 00:43:28 |:BF0000|:BF0000|
|* 8 | TABLE ACCESS STORAGE FULL | PS_JRNL_LN | 1132K| 137M| | 66M (1)| 00:43:28 |:BF0000|:BF0000|
-------------------------------------------------------------------------------------------------------------------------
- Why is the full scan so expensive?
- How can I make it cheaper?
No comments :
Post a Comment