sql—oracle—日常分区方法适合于具有数百万行的表吗

fdx2calv  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(452)

我正在处理一个现有的表,该表有数百万行的零售交易历史数据。架构如下所示:

create table History(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtodsinterval(1,'day'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

上面的表是基于每日间隔分区的,因此一年中将有365个分区,由数百万行组成。我们计划创建一个清除作业,但是在那之前,在一个表中有这么多分区是可以的,并且与没有分区的表相比,它会导致性能下降吗?
任何帮助都将不胜感激。谢谢。:)

sulc1iza

sulc1iza1#

根据您对“百万”的定义,日常分区可能过于精细,在读取数据时可能会导致性能问题。
每个分区在物理上像一个表一样存储,并且有不同的开销——最重要的是段空间分配的开销。甲骨文几乎从来没有分配到底需要多少空间,总是有一点额外的。如果您创建了大量的小分区,那么这个“小额外”可能会比实际数据大。
在我下面的测试用例中,假设每年有500万行,并且每列中的值相对较小,每日分区使用的段空间是每月分区的十倍。这意味着每日分区对于选择一天的数据是最佳的,但是对于选择多天的数据则是糟糕的。而且,由于全表/分区扫描使用多块读取,而且一次读取兆字节的数据,因此读取一整月的数据可能不会比读取一天的数据慢多少。

示例架构

为每日、每月和无分区创建三个表。将500万行平均加载到365天中的每个行中,然后检查段大小。
每日分区使用2920兆字节用于365个段。
每月分区使用288兆字节用于13个段。
没有分区对一个段使用280兆字节。
代码:

----------------------------------------
--DAY
----------------------------------------

create table History_day(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtodsinterval(1,'day'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

create sequence history_day_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history_day values(history_day_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY_DAY';

----------------------------------------
--MONTH: 288 megabytes for 13 partitions.
----------------------------------------

create table History_month(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtoyminterval(1,'month'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

create sequence history_month_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history_month values(history_month_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY_MONTH';

----------------------------------------
--NO PARTITIONS
----------------------------------------

create table History(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid));

create sequence history_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history values(history_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY';

这些结果适用于你吗?

很有可能您的结果在您的系统上会有所不同,这取决于您的数据和系统如何分配段。重要的是你应该自己做这样的测试。请记住,分区是为“大”数据量而设计的,但是“大”这个词显然是主观的。
对于许多大型表来说,每日分区是完美的,但是我有一种感觉,您的表使用每月分区会更好。

相关问题