将分区 p2 设置为仅存储最近的 3 个月数据如何?

huangapple go评论60阅读模式
英文:

How can i set partition p2 to store only letest 3 months data in it?

问题

In this create partition part of the code block, 如何设置分区2仅存储最近3个月的数据在分区p2中?

英文:

In this create partition part of code block, how can i set partition 2 to store 3 months latest data within the partition p2 only?

CREATE TABLE server1.test_temp
                PARTITION BY RANGE (receiveddate)
                (
                  PARTITION P2_test_temp VALUES LESS THAN (TO_DATE('08-05-23', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
                )
                AS
                SELECT * FROM server1.test;
              

答案1

得分: 1

请使用INTERVAL分区,这会让您的生活变得更容易,例如像这样:

CREATE TABLE server1.test_temp
    PARTITION BY INTERVAL (INTERVAL '3' MONTH)
    (
    PARTITION P_INITIAL VALUES LESS THAN (TIMESTAMP '2008-01-01 00:00:00')
    )
英文:

Better use INTERVAL partition, it makes your life much easier, for example like this:

CREATE TABLE server1.test_temp
    PARTITION BY INTERVAL (INTERVAL '3' MONTH)
    (
    PARTITION P_INITIAL VALUES LESS THAN (TIMESTAMP '2008-01-01 00:00:00')
    )

答案2

得分: 1

以下是您提供的内容的中文翻译:

最简单的解决方案是指定分区间隔,动态分配新日期指定大小的新分区。分区修剪where条件、子查询甚至允许基于条件动态选择分区。

但是,如果由于某种原因,您仍然需要为过去三个月保留单个分区,并具有动态上边界,您需要安排每日作业,以相应地调整现有分区。它应该执行以下操作:

  1. 为新日期添加新分区,以使用其上边界作为新的上边界。
  2. 将此新分区合并到“旧”的最后一个分区中。
  3. 将最后一个分区在日期前的3个月拆分,以从最新分区中删除旧数据。
  4. 将此旧数据与以前的分区合并。否则,它将保留此一天的数据在其自己的分区中,最好考虑每日自动间隔分区。

以下是执行此特定表的步骤的过程。如果要将表作为参数传递,您需要进行调整并添加名称验证。

表和初始数据:

create table test_temp (
  somedata varchar2(100),
  receiveddate date
)
partition by range(receiveddate) (
  partition p_2022 values less than(date '2023-01-01'),
  partition p_2023 values less than(date '2023-02-08'),
  partition p_last_3_month values less than (date '2023-05-08')
);

select *
from test_temp
partition (p_last_3_month)
SOMEDATA RECEIVEDDATE
qwe 2023-05-01
asd 2023-02-09
create procedure p_keep_3_month_part(
 p_date in date default trunc(sysdate)
)
as
  tmp_partition_name constant varchar2(30) := 'TEMP_PARTITION';
  last_partition_expr long;
  last_partition_name varchar2(30);
  prev_partition_name varchar2(30);

  last_partition_date date;

  /*Dynamic statement logging*/
  procedure execute_immediate(l_stmt in varchar2)
    as
    begin
      dbms_output.put_line(l_stmt);
      execute immediate l_stmt;
    end;

  /*Merge partitions into the lower boundary partition name*/
  procedure merge_partitions_to_lower(p_from in varchar2, p_to in varchar2)
    as
    begin
      execute_immediate('alter table test_temp merge partitions ' ||
        p_from || ' to ' || p_to ||
        ' into partition ' || p_to);
      execute_immediate('alter table test_temp rename partition ' ||
        p_to || ' to ' || p_from);
    end;
begin
  /*获取最后一个分区和上一个分区的信息以进行合并*/
  select
    partition_name,
    lag(partition_name) over(partition by table_name order by partition_position asc)
  
    into
      last_partition_name,
      prev_partition_name
  from user_tab_partitions
  where table_name = 'TEST_TEMP'
  order by partition_position desc
  fetch first row only;

  /*为新日期添加新分区*/
  execute_immediate('alter table test_temp add partition ' || tmp_partition_name ||
    ' values less than (date ''' || to_char(p_date, 'yyyy-mm-dd') || ''')');

  /*将最后一个分区扩展到此新日期*/
  merge_partitions_to_lower(last_partition_name, tmp_partition_name);

  /*从最后一个分区中拆分旧数据*/
  execute_immediate('alter table test_temp split partition ' || last_partition_name ||
    ' at (date ''' || to_char(add_months(p_date, -3), 'yyyy-mm-dd') ||
    ''') into (partition ' || tmp_partition_name || ', partition ' || last_partition_name || ')');

  /*将旧数据与上一个分区合并*/
  merge_partitions_to_lower(prev_partition_name, tmp_partition_name);
  
end;/ 

2023-05-14(截至今天的日期)拆分:

begin
  dbms_output.put_line('');
  p_keep_3_month_part(sysdate + 4);
end;/ 
1 行受影响

dbms_output:

alter table test_temp add partition TEMP_PARTITION values less than (date '2023-05-14')
alter table test_temp merge partitions P_LAST_3_MONTH to TEMP_PARTITION into partition TEMP_PARTITION
alter table test_temp rename partition TEMP_PARTITION to P_LAST_3_MONTH
alter table test_temp split partition P_LAST_3_MONTH at (date '2023-02-14') into (partition TEMP_PARTITION, partition P_LAST_3_MONTH)
alter table test_temp merge partitions P_2023 to TEMP_PARTITION into partition TEMP_PARTITION
alter table test_temp rename partition TEMP_PARTITION to P_2023

检查结果:

select table_name, partition_name, high_value, partition_position
from user_tab_partitions
TABLE_NAME PARTITION_NAME HIGH_VALUE PARTITION_POSITION
TEST_TEMP P_2022 TO_DATE(' 2023-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 1
TEST_TEMP P_2023 TO_DATE(' 2023-02-14 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 2
TEST_TEMP P_LAST_3_MONTH TO_DATE(' 2023-05-14 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 3
select *
from test_temp
partition (p_last_3_month)
SOMEDATA RECEIVEDDATE
qwe 2023-05-01

fiddle

英文:

The easiest solution would be to specify interval partitioning that will dynamically allocate new partitions of specified size for new dates. Partition pruning works very well with where conditions and even subqueries and alows dynamic partition selection based on conditions.

However if, for some reason, you still need to have single partition for the last three month with dynamic upper boundary, you need to schedule daily job that will adjust existing partitions accordingly. It should:

  1. Add new partition for a new date to use its upper boundary as new upper boundary.
  2. Merge this new partition with the "old" last partition.
  3. Split the last partition at the 3 month before the date to remove old data from the latest partition.
  4. Merge this old data with the previous partition. Otherwise it will leave this one-day data in its own partition and it would be better to consider automatic interval partitioning on daily basis instead.

Below is the procedure that does these steps for this particular table. You need to adjust it and add name validations if you want to pass a table as a parameter.

Table and initial data:

create table test_temp (
  somedata varchar2(100),
  receiveddate date
)
partition by range(receiveddate) (
  partition p_2022 values less than(date '2023-01-01'),
  partition p_2023 values less than(date '2023-02-08'),
  partition p_last_3_month values less than (date '2023-05-08')
);

select *
from test_temp
partition (p_last_3_month)
SOMEDATA RECEIVEDDATE
qwe 2023-05-01
asd 2023-02-09
create procedure p_keep_3_month_part(
 p_date in date default trunc(sysdate)
)
as
  tmp_partition_name constant varchar2(30) := 'TEMP_PARTITION';
  last_partition_expr long;
  last_partition_name varchar2(30);
  prev_partition_name varchar2(30);

  last_partition_date date;

  /*Dynamic statement logging*/
  procedure execute_immediate(l_stmt in varchar2)
    as
    begin
      dbms_output.put_line(l_stmt);
      execute immediate l_stmt;
    end;

  /*Merge partitions into the lower boundary partition name*/
  procedure merge_partitions_to_lower(p_from in varchar2, p_to in varchar2)
    as
    begin
      execute_immediate('alter table test_temp merge partitions ' ||
        p_from || ' to ' || p_to ||
        ' into partition ' || p_to);
      execute_immediate('alter table test_temp rename partition ' ||
        p_to || ' to ' || p_from);
    end;
begin
  /*get last and previous partition info for merge*/
  select
    partition_name,
    lag(partition_name) over(partition by table_name order by partition_position asc)
  
    into
      last_partition_name,
      prev_partition_name
  from user_tab_partitions
  where table_name = 'TEST_TEMP'
  order by partition_position desc
  fetch first row only;

  /*Add new partition for new date*/
  execute_immediate('alter table test_temp add partition ' || tmp_partition_name ||
    ' values less than (date ''' || to_char(p_date, 'yyyy-mm-dd') || ''')');

  /*Extend last partition to this new date*/
  merge_partitions_to_lower(last_partition_name, tmp_partition_name);

  /*Split old data from the last partition*/
  execute_immediate('alter table test_temp split partition ' || last_partition_name ||
    ' at (date ''' || to_char(add_months(p_date, -3), 'yyyy-mm-dd') ||
    ''') into (partition ' || tmp_partition_name || ', partition ' || last_partition_name || ')');

  /*Merge old data with the previous partition*/
  merge_partitions_to_lower(prev_partition_name, tmp_partition_name);
  
end;/

Split at 2023-05-14 (as of today's date):

begin
  dbms_output.put_line('');
  p_keep_3_month_part(sysdate + 4);
end;/
1 rows affected

dbms_output:

alter table test_temp add partition TEMP_PARTITION values less than (date '2023-05-14')
alter table test_temp merge partitions P_LAST_3_MONTH to TEMP_PARTITION into partition TEMP_PARTITION
alter table test_temp rename partition TEMP_PARTITION to P_LAST_3_MONTH
alter table test_temp split partition P_LAST_3_MONTH at (date '2023-02-14') into (partition TEMP_PARTITION, partition P_LAST_3_MONTH)
alter table test_temp merge partitions P_2023 to TEMP_PARTITION into partition TEMP_PARTITION
alter table test_temp rename partition TEMP_PARTITION to P_2023

Check the result:

select table_name, partition_name, high_value, partition_position
from user_tab_partitions
TABLE_NAME PARTITION_NAME HIGH_VALUE PARTITION_POSITION
TEST_TEMP P_2022 TO_DATE(' 2023-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 1
TEST_TEMP P_2023 TO_DATE(' 2023-02-14 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 2
TEST_TEMP P_LAST_3_MONTH TO_DATE(' 2023-05-14 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 3
select *
from test_temp
partition (p_last_3_month)
SOMEDATA RECEIVEDDATE
qwe 2023-05-01

fiddle

huangapple
  • 本文由 发表于 2023年5月10日 15:30:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76215935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定