مروری کوتاه بر چند نکته در مورد Interval Partitioning

با ارائه قابلیت Interval partitioning در اوراکل نسخه 11g، نیاز به اضافه کردن دستی پارتیشن، در هنگام درج اطلاعات خارج از محدوده از بین رفته است. در این متن به صورت خلاصه نکاتی را در مورد Interval Partitioning مرور خواهیم کرد.

نکته شماره 1:همانطور که می دانید برای پارتیشن بندی جدول به روش Range-Interval، باید حداقل یک Range Partition برای جدول تعریف کرد:

SQL> create table tbl (

     id number,

     name varchar2(10),

     date_        DATE

)

PARTITION BY RANGE (date_)

 INTERVAL(NUMTOYMINTERVAL(1, ‘YEAR’))

(

   PARTITION p1 VALUES LESS THAN (TO_DATE(‘4-6-2001’, ‘DD-MM-YYYY’))

);

ممکن است با اضافه شدن پارتیشنهای جدید به این جدول، تصمیم به حذف پارتیشن p1(که تنها پارتیشن از نوع Range جدول tbl است) را داشته باشیم:

SQL> insert into tbl values(1,’test’,TO_DATE(‘4-6-2002‘, ‘DD-MM-YYYY’));

1 row inserted

SQL> insert into tbl values(1,’test’,TO_DATE(‘4-6-2003‘, ‘DD-MM-YYYY’));

1 row inserted

SQL> select PARTITION_NAME,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME   INTERVAL

—————- ——–

P1               NO

SYS_P701 YES

SYS_P702         YES

SQL> alter table TBL drop partition p1;

ORA-14758: Last partition in the range section cannot be dropped

همانطور که می بینید، در اوراکل 11g، حذف پارتیشن اول از جدول TBL امکان پذیر نمی باشد و برای حذف آن باید حداقل یک پارتیشن دیگر از نوع RANGE در جدول موجود باشد(علاوه بر پارتیشن p1) که با اجرای دستور زیر، همه پارتیشنهای  INTERVAL به NON-INTERVAL تغییر خواهد کرد:

SQL> alter table tbl set interval( numtoyminterval(1,’YEAR’));

Table altered

SQL> select PARTITION_NAME,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME   INTERVAL

—————- ——–

P1               NO

SYS_P701         NO

SYS_P702         NO

در این شرایط، قابلیت حذف پارتیشن P1 به وجود خواهد آمد:

SQL> alter table TBL drop partition p1;

Table altered

در اوراکل 12cR2، مسئله کمی تغییر کرده است و برای حذف اولین پارتیشن جدول، نیاز به اجرای دستور اضافه ای نخواهد بود و این مسئله توسط اوراکل مدیریت می شود:

SQL> select PARTITION_NAME,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       INTERVAL

——————– ——–

P1                   NO

SYS_P17415           YES

SYS_P17416           YES

SQL> alter table TBL drop partition p1;

Table altered

SQL> select PARTITION_NAME,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       INTERVAL

——————– ——–

SYS_P17415           NO

SYS_P17416           YES

 

نکته شماره 2: جدولی را به صورت زیر و با استراتژی range interval پارتیشن بندی کرده ایم:

SQL> create table tbl (

     id number,

     name varchar2(10),

     date_        DATE

)

PARTITION BY RANGE (date_)

INTERVAL(NUMTOYMINTERVAL(1, ‘YEAR‘))

(

   PARTITION p1 VALUES LESS THAN (TO_DATE(‘4-6-2001’, ‘DD-MM-YYYY’)),

   PARTITION p2 VALUES LESS THAN (TO_DATE(‘5-5-2003’, ‘DD-MM-YYYY’)),

   PARTITION p3 VALUES LESS THAN (TO_DATE(‘6-4-2005’, ‘DD-MM-YYYY’))

); 

Table created.

با درج رکوردی که تاریخ آن خارج از محدوده تعریف شده است(بزرگتر از تاریخ 6-4-2005)، خواهیم دید که عدد در نظر گرفته شده برای روز و ماه پارتیشن جدید(توسط دیتابیس)، برابر با عدد تنظیم شده برای Range partition آخر جدول tbl می باشد.

SQL> insert into tbl values(7,’test’,TO_DATE(‘9-8-2041’, ‘DD-MM-YYYY’));

1 row inserted

SQL> insert into tbl values(7,’test’,TO_DATE(’10-11-2091′, ‘DD-MM-YYYY’));

1 row inserted

SQL> select PARTITION_NAME,HIGH_VALUE from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       HIGH_VALUE

——————– ———–

P1                    2001-06-04

P2                    2003-05-05

P3                    2005-04-06

SYS_P501              2042-04-06

SYS_P521              2092-04-06

همانطور که می بینید، هر پارتیشنی که برای سال جدید ایجاد می شود، در تاریخ ****-04-06 ایجاد خواهد شد(04=month,06=day) تکرار می شود که این اعداد بر اساس اعداد در نظرگرفته شده برای اخرین Range partition تعریف شده جدول انتخاب شده است.

در صورتی که این بخواهیم این اعداد را برای INTERVAL PARTITIONهای جدید تغییر دهیم، می توانیم دستورات زیر را  اجرا کنیم.

–غیرفعال کردن interval partitioning:

SQL>  alter table tbl set interval();

Table altered

–تعریف پارتیشن جدید بر اساس تاریخ دلخواه:

SQL> alter table tbl add partition p100 values less than (TO_DATE(‘3030-01-01‘,’YYYY-MM-DD’));

Table altered

–فعال کردن interval partitioning:

SQL> alter table tbl set interval(NUMTOYMINTERVAL(1,’YEAR‘));

Table altered

با درج رکورد جدید، خواهیم دید که پارتیشن در روز و ماه تعریف شده ایجاد خواهد شد:

SQL> insert into tbl values(855,’test’,TO_DATE(’12-12-4040′, ‘DD-MM-YYYY’));

1 row inserted

SQL> select PARTITION_NAME,HIGH_VALUE from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       HIGH_VALUE

——————– ———–

P1                   2001-06-04

P2                   2003-05-05

P3                   2005-04-06

SYS_P501             2042-04-06

SYS_P521             2092-04-06

P100                 3030-01-01

SYS_P541             4041-01-01

7 rows selected

 

نکته شماره 3: همانطور که می دانید در زمان اضافه کردن یک RANGE PARTITION می توان نامی را برای آن پارتیشن در نظر گرفت:

SQL>   alter table tbl add partition p2040 values less than (TO_DATE(‘4-6-2040’, ‘DD-MM-YYYY’));

Table altered

البته در صورت عدم نامگذاری پارتیشن، این کار بر عهده دیتابیس خواهد بود:

SQL>   alter table tbl add partition  values less than (TO_DATE(‘4-6-2040’, ‘DD-MM-YYYY’));

Table altered

SQL> select PARTITION_NAME,HIGH_VALUE from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       HIGH_VALUE

——————–                   ——————–

P1                                           2001-06-04

SYS_P581                             2040-06-04

اما با فعال بودن Interval Partitioning، نمی توان با روش فوق پارتیشنی را به جدول اضافه کرد:

SQL> alter table tbl add partition p4020 values less than (4);

ORA-14760: ADD PARTITION is not permitted on Interval partitioned objects

البته از اوراکل 12cR2 می توان نام پارتیشنهای که به صورت خودکار ایجاد شده اند را برای interval partitionها تغییر داد:

SQL> select PARTITION_NAME,HIGH_VALUE,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       HIGH_VALUE INTERVAL

——————– ———- ——–

P1                   1          NO

SYS_P601             3          YES

SQL> alter table tbl rename partition for (2) to p3;

Table altered

SQL> select PARTITION_NAME,HIGH_VALUE,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME       HIGH_VALUE INTERVAL

——————– ———- ——–

P1                   1          NO

P3                   3          YES

 

نکته شماره 4: اضافه کردن دستی پارتیشن به یک جدول Range-Interval

 به روش متداول امکان اضافه کردن پارتیشن به جدولی که به صورت Range-Interval پارتیشن بندی شده است، وجود ندارد(بصورت دستی و بدون انجام عملیات DMLای منظور است) و برای انجام آن نیاز به فراهم شدن مقدماتی دارد که در ادامه با دو روش زیر نحوه انجام آن را ملاحضه خواهید کرد:

روش اول:

SQL> select PARTITION_NAME,HIGH_VALUE,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME  HIGH_VALUE            INTERVAL

————— ———–          ——–

P1               2001-06-04         NO

SQL> LOCK TABLE tbl PARTITION FOR(TO_DATE(’11-12-2021′, ‘DD-MM-YYYY’)) IN SHARE MODE;

Table(s) locked

SQL> commit;

Commit complete

SQL> select PARTITION_NAME,HIGH_VALUE,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME  HIGH_VALUE  INTERVAL

————— ———– ——–

P1              2001-06-04   NO

SYS_P664 2022-06-04   YES

یکی از کاربردهای اضافه کردن پارتیشن به روش فوق، به انجام عملیات exchange برمیگردد:

SQL> create table tbl_non_partition as select * from tbl where 1=2;

Table created

SQL> insert into tbl_non_partition values(855,’test’,TO_DATE(’09-09-2021′, ‘DD-MM-YYYY’));

1 row inserted

SQL> insert into tbl_non_partition values(855,’test’,TO_DATE(’07-07-2021′, ‘DD-MM-YYYY’));

1 row inserted

SQL> insert into tbl_non_partition values(855,’test’,TO_DATE(’08-08-2021′, ‘DD-MM-YYYY’));

1 row inserted

SQL> insert into tbl_non_partition values(855,’test’,TO_DATE(’10-10-2021′, ‘DD-MM-YYYY’));

1 row inserted

SQL> commit;

Commit complete

SQL> ALTER TABLE tbl

    EXCHANGE PARTITION FOR (TO_DATE(’11-12-2021′, ‘DD-MM-YYYY’))

      WITH TABLE tbl_non_partition;

Table altered

SQL> select count(*) from tbl_non_partition;

  COUNT(*)

———-

         0

SQL> select count(*) from tbl PARTITION FOR (TO_DATE(’11-12-2021′, ‘DD-MM-YYYY’));

  COUNT(*)

———-

         4

روش دوم: غیر فعال کردن موقت interval partitioning و اضافه کردن دستی پارتیشن:

 SQL> ALTER TABLE tbl SET INTERVAL ();

Table altered

SQL> alter table tbl add partition p4020 values less than (TO_DATE(’11-12-2021′, ‘DD-MM-YYYY’)) ;

Table altered

SQL> select PARTITION_NAME,HIGH_VALUE,INTERVAL from user_tab_partitions where table_name=’TBL’;

PARTITION_NAME  HIGH_VALUE  INTERVAL

————— ———-  ——–

P1              2001-06-04  NO

P4020           2021-12-11  NO

 

نکته شماره 5: تبدیل Range Partititoning به Interval Partititoning:

ساختار جدول tbl1 را در نظر بگیرید:

create table tbl1 (

     id number,

     name varchar2(10),

     date_        DATE

)

PARTITION BY RANGE (date_)

(

   PARTITION p1 VALUES LESS THAN (TO_DATE(‘4-1-2001’, ‘DD-MM-YYYY’))

); 

با دستور زیر قصد داریم اطلاعات مربوط به سال 2030 را در جدول tbl1 درج کنیم اما با توجه به آنکه پارتیشن p1 اطلاعاتی که تاریخ آنها مربوط به قبل از تاریخ 4-1-2001 است، را پشتیبانی می کند، دستورزیر با خطا مواجه خواهد شد:

SQL> insert into tbl1 values(6,’test’,TO_DATE(‘4-1-2030’, ‘DD-MM-YYYY’));

ORA-14400: inserted partition key does not map to any partition

با تبدیل نوع پارتیشن بندی جدول از range به interval، خواهیم دید که اوراکل در زمان درج اطلاعات خارج از محدوده، پارتیشن جدیدی را ایجاد خواهد کرد. دستور زیر، Range Partititoning را به Interval Partititoning تبدیل خواهد شد:

SQL> ALTER TABLE tbl1 SET INTERVAL(NUMTOYMINTERVAL(2,’YEAR’));

Table altered.

SQL> select partition_name, interval from   user_tab_partitions where  table_name = ‘TBL1’;

PARTITION_ INT

———- —

P1         NO

SQL> insert into tbl1 values(6,’test’,TO_DATE(‘4-1-2030’, ‘DD-MM-YYYY’));

1 row created.

SQL> select partition_name, interval from   user_tab_partitions where  table_name = ‘TBL1’;

PARTITION_ INT

———- —

P1         NO

SYS_P421   YES

نکته شماره 6: تبدیل interval  به range

همانطور که مشاهده شد، با تبدیل نوع پارتیشن بندی از range به interval، پارتیشن SYS_P421 به صورت خودکار ایجاد خواهد شد. در صورتی که قصد تغییر نوع پارتیشن بندی جدولی را از interval به range داشته باشیم، می توانیم از روش زیر استفاده کنیم:

SQL> ALTER TABLE tbl1 SET INTERVAL ();

Table altered.

SQL> select partition_name, interval from user_tab_partitions where  table_name = ‘TBL1’;

PARTITION_ INT

———- —

P1         NO

SYS_P421   NO

SQL>  insert into tbl1 values(7,’test’,TO_DATE(‘4-1-2040’, ‘DD-MM-YYYY’));

ORA-14400: inserted partition key does not map to any partition

 

نکته شماره 7: زمانی که از interval partitioning استفاده می کنیم، می توانیم پارتیشنها را به صورت round robin بین tablespaceهای مختلف توزیع کنیم. این کار با کمک عبارت store in قابل انجام است:

SQL> alter table tbl1 set STORE IN(tbs1,tbs2,tbs3,tbs4);

Table altered.

 

 

ارتباط با نویسنده مطلب:vahidusefzadeh@ کانال تخصصی اوراکل و لینوکس: OracleDB@

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد.