暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

oushudb-表分区

原创 宗恩 2023-02-03
173

在数据库日渐庞大的今天,为了方便对数据库数据的管理,比如按时间、地区去统计一些数据时,基数 过于庞大带来了诸多不便。很多商业数据库都提供分区的概念,按不同的维度去存放数据,便于后期的 管理,OushuDB也不例外。

表分区是把逻辑上的一个大表拆分成多个子表,这样不仅能带来访问速度的提升,更能带来管理和维护
上的方便,

这样的话,有两个好处:

    查询优化器可以针对分区表进行优化,如果查询只涉及到某些分区,则查询计划只需要扫描
    这些分区,从而加速查询
    如果我们按照日期进行分区的话,我们可以简单的加入分区和删除过期的分区。

分区表的目的是为了提高查询性能,但并非所有的表都适合做分区。只有大型事实表、经常使用特定>条 件[日期、地区等]查询数据、维护历史数据、数据分布均匀的情况,可通过分区策略大大提升使用性 能。且分区数不宜过多,否则会影响维护和管理工作速度。

OushuDB支持基于Range和List的两种分区方式:

Range分区:表被一个或者多个关键列分区成”范围”,这些范围在不同的分区里没有重叠。 比如依 据日期、价格数值范围进行分区。 List分区:依据一个值的列表进行分区,比如依据地区列表进行分区。

创建新的分区表使用CREATE TABLE ... PATITION BY语法实现,创建分区表步骤如下:

1. 确定分区类型:范围分区RANGE或列表分区List。
2. 选定分区字段:范围分区多为日期、数值类型字段;列表分区多为枚举类型的特定列表; 3. 确定分区级别:OushuDB支持子分区SUBPARTITION,可以按照不同维度实现多级分区。

定义Range分区

比如,假设我们为一个巨大的冰激凌公司构造数据库。该公司每天都测量最高温度,以及每个地区的冰
激凌销售。且大多数查询都只会访问最后一周,最后一个月或者最后一个季度的数据,因为这个表的主
要用途是为管理准备在线报告。为了减少需要存储的旧数据,我们决定只保留最近三年的有用数据。在
每个月的开头,我们都会删除最旧的一个月的数据。因此,我们会选定日期字段作按月的范围分区:

CREATE TABLE measurement (
  city_id int not null,
  logdate date not null,
  peaktemp int,
  unitsales int
)
DISTRIBUTED BY (city_id)
PARTITION BY RANGE (logdate)
(START (date '2020-01-01') INCLUSIVE END (date '2020-02-01') EXCLUSIVE EVERY
(INTERVAL '1 month'));

又例如,我们来创建一个sales表,按照date列Range分区,从2008年到2009年每月创建一个分区:

要查看创建的表信息,可以通过\d+给出该表的所有信息

postgres=# \d+ sales
              Append-Only Table "public.sales"
 Column |     Type      | Modifiers | Storage | Description
--------+---------------+-----------+---------+-------------

id |integer | date | date | amt | numeric(10,2) |

Compression Type: None
Compression Level: 0
Block Size: 32768
Checksum: f
Child tables: sales_1_prt_1,
              sales_1_prt_10,
              sales_1_prt_11,
              sales_1_prt_12,
              sales_1_prt_2,
              sales_1_prt_3,
              sales_1_prt_4,
              sales_1_prt_5,
              sales_1_prt_6,
              sales_1_prt_7,
              sales_1_prt_8,
              sales_1_prt_9
Has OIDs: no
Options: appendonly=true
Distributed randomly
Partition by: (date)

|plain | | plain | | main |

你也可以显式得声明子分区并指定子表名字。

CREATE TABLE sales_exp (id int, date date, amt decimal(10,2))
PARTITION BY RANGE (date)
( PARTITION Jan08 START (date '2008-01-01') INCLUSIVE ,
  PARTITION Feb08 START (date '2008-02-01') INCLUSIVE ,
  PARTITION Mar08 START (date '2008-03-01') INCLUSIVE ,
  PARTITION Apr08 START (date '2008-04-01') INCLUSIVE ,
  PARTITION May08 START (date '2008-05-01') INCLUSIVE ,
  PARTITION Jun08 START (date '2008-06-01') INCLUSIVE ,
  PARTITION Jul08 START (date '2008-07-01') INCLUSIVE ,
  PARTITION Aug08 START (date '2008-08-01') INCLUSIVE ,
  PARTITION Sep08 START (date '2008-09-01') INCLUSIVE ,
  PARTITION Oct08 START (date '2008-10-01') INCLUSIVE ,
  PARTITION Nov08 START (date '2008-11-01') INCLUSIVE ,
  PARTITION Dec08 START (date '2008-12-01') INCLUSIVE

END (date '2009-01-01') EXCLUSIVE );

查看创建的表信息

postgres=# CREATE TABLE sales (id int, date date, amt decimal(10,2)) PARTITION BY RANGE (date)
( START (date '2008-01-01') INCLUSIVE

   END (date '2009-01-01') EXCLUSIVE
   EVERY (INTERVAL '1 month') );

下面是另外一个根据Range分区的例子,这次使用的是整型列进行分区。这里面我们添加了一个 DEFAULT PARTITION, 在不满足其他分区的条件下,数据会被插入DEFAULT PARTITION。

定义List分区

列表分区的分区字段可以是任意可进行等于比较的数据类型,且允许多列组合进行分区,而范围分区只
允许选定一列作分区字段。列表分区时必须显式为每个分区申明分区值,比如还是上述提到的冰淇淋数
据表,我们可以按照地区列表对数据进行分区操作:

CREATE TABLE rank (id int, rank int, year int, gender char(1), count int)
PARTITION BY RANGE (year)
( START (2001) END (2008) EVERY (1),
  DEFAULT PARTITION extra );
最后修改时间:2023-02-06 15:06:38
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论