问题描述
我有一个数据库,其中一个表包含历史BLOB数据,所以这个表目前相当大(1.2TB)。我根据ID分区了一个范围,我的主键(此表没有日期列) ,为了便于管理,我将除当前分区以外的所有分区设置为只读。我的目标是使每个分区为10G ,所以我在最初使用dbms_re定义的时候循环访问并确定了用于每个分区的适当ID。由于BLOB的大小变化很大,所以范围到处都是。我的想法是,在DB增长以创建额外的10G只读分区时,我将简单地拆分活动分区,只要确定创建新的10G分区所需的ID即可。我在拆分活动分区时遇到的问题是,拆分所需的时间,以及用户在拆分期间无法继续添加新数据的事实。我不能在这个数据库上有任何停机时间进行分区维护,所以我需要找到一种方法来分割并让应用程序继续运行。根据我的研究,答案是在需要的时候提前向表中添加新的分区,而不是拆分当前的分区,但对我来说,我不想这样做,因为我正试图使它们在大小上有些一致。如有任何建议将不胜感激。
专家解答
这里有一个古老的股票市场说法: "过去的行为不是未来行为的可靠指标"这一点可能适用于这里,因为它只需要几个非常大的斑点,就可以在几行中轻松地将您带到10g ,而明天,可能需要数百万行(每个都有小斑点)才能将您带到10g。所以你可能会有某种妥协。
这种折衷可能依赖于“快速分割”优化,即在分割点的“右侧”一侧选择一个没有数据的点。
这里有一些让你开始的东西-逻辑是这样的:
-按顺序沿着隔板走
-如果“此”分区为空,请检查前一个分区的大小
-如果大于x ,则
-在逻辑点将它拆分为2个分区,以便一个分区拥有所有数据,一个空分区(ptmp)
-将“maxvalue”最高分区拆分为两个( pn和pmax ) ,为分区建立新的合理边界点
-合并ptmp和pn
所以,在数字上,我们说
我们认为p2现在“太大了”。我们这样做
步骤1 -拆分p2
因此,我们现在将p2限制在1600 (即,在插入过程中保留了一些回旋余地)
步骤2 -拆分pmax
我们这样做是因为ptmp对我们没有好处,因为它的上限是2000 ,我们希望它的上限是一个合理的逻辑值
步骤3 -合并p3和ptmp
我们就完了。所有这些操作,因为它们在空分区上工作,实际上都是瞬时的。
这里是一个演示,其中30兆是一个片段的大小限制
现在,在另一个会话中,我正在批量运行插入以模拟在线活动
这是我的例行程序,它可以随时监视并自动进行分区维护
好好享受吧!
这种折衷可能依赖于“快速分割”优化,即在分割点的“右侧”一侧选择一个没有数据的点。
这里有一些让你开始的东西-逻辑是这样的:
-按顺序沿着隔板走
-如果“此”分区为空,请检查前一个分区的大小
-如果大于x ,则
-在逻辑点将它拆分为2个分区,以便一个分区拥有所有数据,一个空分区(ptmp)
-将“maxvalue”最高分区拆分为两个( pn和pmax ) ,为分区建立新的合理边界点
-合并ptmp和pn
所以,在数字上,我们说
values less than current hwm p1 1000 1000 p2 2000 1500 pmax maxvalue -
我们认为p2现在“太大了”。我们这样做
步骤1 -拆分p2
values less than current hwm p1 1000 1000 p2 1600 1500 ptmp 2000 - pmax maxvalue -
因此,我们现在将p2限制在1600 (即,在插入过程中保留了一些回旋余地)
步骤2 -拆分pmax
values less than current hwm p1 1000 1000 p2 1600 1500 ptmp 2000 - p3 3000 - pmax maxvalue -
我们这样做是因为ptmp对我们没有好处,因为它的上限是2000 ,我们希望它的上限是一个合理的逻辑值
步骤3 -合并p3和ptmp
values less than current hwm p1 1000 1000 p2 1600 1500 p3 3000 - pmax maxvalue -
我们就完了。所有这些操作,因为它们在空分区上工作,实际上都是瞬时的。
这里是一个演示,其中30兆是一个片段的大小限制
SQL> create table T ( x int, y char(200))
2 partition by range (x)
3 (
4 partition p1 values less than (300000),
5 partition p2 values less than (600000),
6 partition p3 values less than (900000),
7 partition p4 values less than (1200000),
8 partition pmax values less than (maxvalue)
9 );
Table created.
SQL>
SQL> insert /*+ APPEND */ into T
2 select rownum, rownum
3 from dual
4 connect by level <= 1000000;
1000000 rows created.
SQL>
SQL> create index IX on T ( x ) local;
Index created.
SQL>
SQL> alter table T add constraint T_PK primary key ( x ) using index local
2 /
Table altered.
SQL>
SQL> select bytes
2 from user_segments
3 where segment_name = 'T';
BYTES
----------
75497472
75497472
75497472
25165824
现在,在另一个会话中,我正在批量运行插入以模拟在线活动
SQL> declare 2 l_start int; 3 l_cnt int := 1; 4 begin 5 select max(x) into l_start from t; 6 7 for i in 1 .. 1000 loop 8 for j in 1 .. 10000 loop 9 insert into t values (l_start+l_cnt,i); 10 l_cnt := l_cnt + 1; 11 end loop; 12 commit; 13 dbms_lock.sleep(4); 14 end loop; 15 end; 16 /
这是我的例行程序,它可以随时监视并自动进行分区维护
SQL> set serverout on
SQL> declare
2 l_has_Rows int;
3 l_hi_par varchar2(30);
4 l_hi_bytes int;
5 l_hwm int;
6
7 procedure ddl(m varchar2) is
8 begin
9 dbms_output.put_line(m);
10 execute immediate m;
11 end;
12 begin
13 for i in ( select p.partition_name, s.bytes, p.partition_position
14 from user_segments s,
15 user_tab_partitions p
16 where p.table_name= 'T'
17 and p.table_name = s.segment_name(+)
18 and p.partition_name = s.partition_name(+)
19 order by p.partition_position asc
20 )
21 loop
22 execute immediate 'select count(*) from t partition ( '||i.partition_name||') where rownum = 1' into l_has_rows;
23 dbms_output.put_line(i.partition_name||':'||i.bytes||':'||l_has_rows);
24 if l_has_rows > 0 then
25 --
26 -- we've hit a partition with rows
27 --
28 if i.partition_name = 'PMAX' then
29 raise_application_error(-20000,'We got rows in PMAX...thats a problem');
30 end if;
31
32 l_hi_par := i.partition_name;
33 l_hi_bytes := i.bytes;
34 else
35 --
36 -- see if we've hit PMAX, check size of prev one
37 --
38 if l_hi_bytes > 30*1024*1024 then
39 execute immediate 'select max(x) from t partition ( '||l_hi_par||')' into l_hwm;
40
41 ddl('alter table T split partition '||l_hi_par||' at ('||(l_hwm+10000)||') into (partition '||l_hi_par||', partition ptmp)');
42 ddl('alter table T split partition pmax at ('||(l_hwm+10000+300000)||') into (partition p'||i.partition_position||', partition pmax)');
43 ddl('alter table T merge partitions ptmp,p'||i.partition_position||' into partition p'||i.partition_position);
44
45 end if;
46 exit;
47 end if;
48 end loop;
49 end;
50 /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:25165824:1
PMAX::0
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL> /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:33554432:1
PMAX::0
alter table T split partition P4 at (1020000) into (partition P4, partition ptmp)
alter table T split partition pmax at (1320000) into (partition p5, partition pmax)
alter table T merge partitions ptmp,p5 into partition p5
PL/SQL procedure successfully completed.
SQL> /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:33554432:1
P5:8388608:1
PMAX::0
PL/SQL procedure successfully completed.
SQL> /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:33554432:1
P5:16777216:1
PMAX::0
PL/SQL procedure successfully completed.
SQL> /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:33554432:1
P5:33554432:1
PMAX::0
alter table T split partition P5 at (1140000) into (partition P5, partition ptmp)
alter table T split partition pmax at (1440000) into (partition p6, partition pmax)
alter table T merge partitions ptmp,p6 into partition p6
PL/SQL procedure successfully completed.
SQL> /
P1:75497472:1
P2:75497472:1
P3:75497472:1
P4:33554432:1
P5:33554432:1
P6:8388608:1
PMAX::0
PL/SQL procedure successfully completed.
SQL>
好好享受吧!
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




