Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Nikhil.

Asked: January 11, 2017 - 7:24 am UTC

Last updated: January 14, 2017 - 7:54 am UTC

Version: 11.2.0

Viewed 1000+ times

You Asked

Hi Team,

Please have a look at table structure shared via LiveSQL Link - https://livesql.oracle.com/apex/livesql/s/ee1slk0wo53esxy30e4l0ac2x

table is used in application using stmt_end_date -
1. Since stmt_end_date is a part of primary key, is it recommended to as a PARTITION key?
2. Could you please share your views which partition methos combination can be used for this table.
3. Since there is not direct way to partition table in 11g, If we go for upgrading Oracle to 12c will ALTER COMMAND MODIFY will help to parition exiting non-partition table?

Copying table structure if incase Live links is not accessible -
CREATE TABLE TB_DEMOGRAPHIC
(CARD_NO VARCHAR2(25 CHAR),
CONSTRAINT PK_TB_DEMOGRAPHIC PRIMARY KEY (CARD_NO));

CREATE TABLE TB_STATEMENT
(CARD_NO VARCHAR2(25 CHAR),
STMT_BEGIN_DATE DATE,
ACC_NO VARCHAR2(25 CHAR),
PRIMARY_CARD_NO VARCHAR2(25 CHAR),
STATEMENT_TYPE CHAR(1 CHAR),
ACC_STATUS VARCHAR2(4 CHAR),
BLOCK_CD CHAR(1 CHAR),
BLOCK_REASON VARCHAR2(2 CHAR),
STMT_END_DATE DATE,
STMT_BEGIN_BAL NUMBER(13,2),
STMT_BEGIN_BAL_SIGN VARCHAR2(2 CHAR),
STMT_END_BAL NUMBER(13,2),
STMT_END_BAL_SIGN VARCHAR2(2 CHAR),
CREDIT_LIMIT NUMBER(18,2),
CASH_LIMIT NUMBER(18,2),
AVAIL_CREDIT_LIMIT NUMBER(18,2),
AVAIL_CREDIT_LIMIT_SIGN VARCHAR2(2 CHAR),
AVAIL_CASH_LIMIT NUMBER(18,2),
AVAIL_CASH_LIMIT_SIGN VARCHAR2(2 CHAR),
AMT_DUE_CYCLE1 NUMBER(18,2),
AMT_DUE_CYCLE2 NUMBER(18,2),
AMT_DUE_CYCLE3 NUMBER(18,2),
AMT_DUE_CYCLE4 NUMBER(18,2),
AMT_DUE_CYCLE5 NUMBER(18,2),
AMT_DUE_CYCLE6 NUMBER(18,2),
AMT_DUE_CYCLE7 NUMBER(18,2),
DUE_AMT NUMBER(18,2),
DUE_AMT_SIGN CHAR(1 CHAR),
NO_OF_DUE_DAYS NUMBER(3,0),
PAYMENT_DUE NUMBER(18,2),
PAYMENT_DUE_SIGN VARCHAR2(2 CHAR),
PAYMENT_DUE_DATE DATE,
PRINT_FLG CHAR(1 CHAR),
ONLINE_STMT_DISP_FLG CHAR(1 CHAR),
STMT_MSG_IND VARCHAR2(2 CHAR),
STMT_PAYMENT_RECD NUMBER(13,2),
STMT_PAYMENT_RECD_SIGN CHAR(1 CHAR),
NEW_TXN NUMBER(18,2),
NEW_TXN_SIGN VARCHAR2(2 CHAR),
STMT_GEN_FLG CHAR(1 CHAR),
UPLOAD_ID NUMBER(10,0),
REC_STATUS VARCHAR2(2 CHAR) DEFAULT 'AC',
CREATED_BY VARCHAR2(30 CHAR),
CREATED_ON DATE,
MODIFIED_BY VARCHAR2(30 CHAR),
MODIFIED_ON DATE,
FILEDATE DATE,
CYCLE_DAY VARCHAR2(2 CHAR),
SWISSGIRO VARCHAR2(75 CHAR),
SWEDEN_GIRO VARCHAR2(100 CHAR),
PAYEE_ACC_NO VARCHAR2(15 CHAR),
FINNISH_GIRO_REF_NO VARCHAR2(20 CHAR),
FINNISH_CHECK_DIGIT1 VARCHAR2(5 CHAR),
FINNISH_CHECK_DIGIT2 VARCHAR2(5 CHAR),
REWARD_FLAG CHAR(1 CHAR),
OPENING_BALANCE NUMBER(13,2),
POINTS_EARNED NUMBER(13,2),
POINTS_REDEEMED NUMBER(13,2),
POINTS_EXPIRED NUMBER(13,2),
TOT_AVAIL_POINTS NUMBER(13,2),
EXPIRY_DATE DATE,
ACH_PAYMENT_FLG VARCHAR2(5 CHAR),
DESPATCH_TYPE_FLAG VARCHAR2(2 CHAR),
NEXT_DUE_DATE DATE,
NEXT_STMT_DATE DATE,
CASH_ADVANCE_FEE NUMBER(18,2),
CASH_ADVANCE_PERCENTAGE NUMBER(4,2),
CASH_ADVANCE_ACTION VARCHAR2(1 CHAR),
LATE_CHARGE_FEE NUMBER(18,2),
LATE_CHARGE_PERCENTAGE NUMBER(4,2),
LATE_CHARGE_ACTION VARCHAR2(1 CHAR),
RETURN_CHEQUE_FEE NUMBER(18,2),
RETURN_CHEQUE_PERCENTAGE NUMBER(4,2),
RETURN_CHEQUE_ACTION VARCHAR2(1 CHAR),
FOREIGN_TXN_FEE NUMBER(18,2),
FOREIGN_TXN_PERCENTAGE NUMBER(4,2),
FOREIGN_TXN_ACTION VARCHAR2(1 CHAR),
ANNUAL_MEMBERSHIP_FEE NUMBER(18,2),
CONSTRAINT CHECK_C0023288 CHECK (CARD_NO IS NOT NULL) ENABLE,
CONSTRAINT CHECK_C0023289 CHECK (STMT_BEGIN_DATE IS NOT NULL) ENABLE,
CONSTRAINT CHECK_C0023290 CHECK (ACC_NO IS NOT NULL) ENABLE,
CONSTRAINT CHECK_C0023291 CHECK (PRIMARY_CARD_NO IS NOT NULL) ENABLE,
CONSTRAINT PK_TB_STATEMENT PRIMARY KEY (CARD_NO, STMT_BEGIN_DATE),
CONSTRAINT FK_TB_STATEMENT1 FOREIGN KEY (CARD_NO)
REFERENCES TB_DEMOGRAPHIC (CARD_NO) ENABLE
);

CREATE INDEX IDX_AP_CS_CD_NO ON TB_STATEMENT (CARD_NO, STMT_END_DATE);

CREATE INDEX IDX_AP_PRINT_FLG ON TB_STATEMENT (PRINT_FLG);


with LiveSQL Test Case:

and Chris said...

To recommend a partitioning strategy, we need to know more about your requirements. Why do you want to partition? What do you expect to achieve by doing this? How do you access your data?

Without answers to these kinds of questions any recommendation we make could make a mess of your application! Say you do partition on stmt_end_date. If you have lots of queries against stmt_end_date, such as:

stmt_end_date = :x

or

stmt_end_date between :st and :en

Partition pruning will kick in and you could see good performance benefits. But if few of your queries have predicates on stmt_end_date you could end up making performance much worse.

Before you jump in with partitioning, take the time to understand it. Check out Connor's slides from his excellent Partition 101 presentation at UKOUG. You can get these from Resources tab here on AskTom. Scroll to the bottom and look for ukoug_partitioning.pdf. Note you need to be logged into download these.

I'd also read Martin Widlakes slides on "The Forgotten PerformanceTuning Trick - Clustering Your Data". In it he discusses some of the pros and cons of partitioning. And if your goal is "fast data access" he covers the alternatives (IOTs, clusters) too:

https://www.doag.org/formes/servlet/DocNavi?action=getFile&did=8488207&key=

To your question on partitioning existing tables. Starting in 12.2 you can partition a table online in a single statement:

create table t as 
  select rownum x, 'stuff' y from dual
  connect by level <= 1000;
  
alter table t modify partition by range (x) interval (100) (
  partition p1 values less than (101)
);

exec dbms_stats.gather_table_stats(user, 't');

select partition_name, high_value, num_rows 
from   user_tab_partitions
where  table_name = 'T';

PARTITION_NAME  HIGH_VALUE  NUM_ROWS  
P1              101         100       
SYS_P1463       201         100       
SYS_P1464       301         100       
SYS_P1465       401         100       
SYS_P1466       501         100       
SYS_P1467       601         100       
SYS_P1468       701         100       
SYS_P1469       801         100       
SYS_P1470       901         100       
SYS_P1471       1001        100  


https://blogs.oracle.com/sql/entry/12_things_developers_will_love#partition-online

In the meantime you can partition an existing table with minimal downtime using dbms_redefinition:

https://oracle-base.com/articles/misc/partitioning-an-existing-table

Thanks for providing your code in LiveSQL!

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Archival

Nikhil Patil, January 11, 2017 - 11:33 am UTC

Hi Chris,
Thanks for you reply.

This table is currently holding billions of statement data fro past 15 years.
We are now moving these tables into another DB for Archival purpose.
In this Archival process we will be moving data from primary to Archival DB and making this table Partition in both the DB.

Currently Table is used based on composite primary key i.e. CARD_NO & STATEMENT_END_DATE, Hence I thought of making this table as Parition using STATEMENT_END_DATE column.

From your experience, It would you be helpful if you share your views on - can partition key be one of the column in Composite primary Ket i.e. STMT_END_DATE ..?
Connor McDonald
January 14, 2017 - 7:54 am UTC

"can partition key be one of the column in Composite primary Ket i.e. STMT_END_DATE .."

Yes it can be, and in fact, if you want to have a *local* index for the primary key, the partition key must be part of the index.

More to Explore

VLDB

If you are new to partitioning, check out Connor McDonald's introduction series here.

VLDB

Documentation set on VLDB and Partitioning.