1 - 删除分区

使用 DROP_PARTITIONS 函数删除给定表的一个或多个分区键。可以指定单个分区键或分区键范围。

例如,对新表进行分区中显示的表按列 order_date 进行分区:

=> CREATE TABLE public.store_orders
(
    order_no int,
    order_date timestamp NOT NULL,
    shipper varchar(20),
    ship_date date
)
PARTITION BY YEAR(order_date);

鉴于此表定义,Vertica 会为每个唯一的 order_date 年份(在本例中为 2017、2016、2015 和 2014 年)创建一个分区键,并相应地将数据划分到不同的 ROS 容器中。

以下 DROP_PARTITIONS 语句从表 store_orders 中删除与分区键 2014 关联的所有订单记录:

=> SELECT DROP_PARTITIONS ('store_orders', 2014, 2014);
Partition dropped

拆分分区组

如果表 partition 子句包括 GROUP BY 子句,则分区将按其分区组键在 ROS 中合并。 DROP_PARTITIONS 随后可以指定给定分区组内或跨多个分区组的分区键范围。无论哪种情况,删除操作都要求 Vertica 拆分存储这些分区的 ROS 容器。为此,该函数的 force_split 参数必须设置为 true。

例如,上面显示的 store_orders 表可以使用 GROUP BY 子句重新分区,如下所示:

=> ALTER TABLE store_orders
     PARTITION BY order_date::DATE GROUP BY DATE_TRUNC('year', (order_date)::DATE) REORGANIZE;

由于之前删除了 2014 年的所有订单记录,order_date 值现在跨越三个年份(2017 年、2016 年和 2015 年)。因此,Tuple Mover 为每年创建三个分区组键,并为每个组指定一个或多个 ROS 容器。然后,它将 store_orders 分区合并到相应的组中。

以下 DROP_PARTITIONS 语句指定删除跨越两个年份(2014 年和 2015 年)的订单日期:

=> SELECT DROP_PARTITIONS('store_orders', '2015-05-30', '2016-01-16', 'true');
Partition dropped

删除操作要求 Vertica 从两个分区组(2015 和 2016)删除分区。这些组至少跨越两个 ROS 容器,必须拆分这些容器才能移除目标分区。因此,将函数的 force_split 参数设置为 true。

调度分区删除

如果硬件具有固定的磁盘空间,则可能需要配置一个定期执行的进程,以便通过删除分区来迁出旧数据。

例如,如果空间只够将数据存储固定的天数,请将 Vertica 配置为删除最旧的分区键。为此,请创建一个基于时间的作业调度程序(例如 cron),以计划在低负载期间删除分区键。

如果数据输入速率具有峰值和谷值,则可以使用以下两种技术来管理分区键删除方式:

  • 设置一个定期(每天)检查磁盘空间的进程。如果已用磁盘空间百分比超出特定阈值(例如 80%),则删除最旧的分区键。

  • 在分区中添加一个可根据行计数等指标递增的假列。例如,每次行计数增加 100 行时,该列可能会递增。设置一个定期(每天)查询此列的进程。如果新列中的值超出特定阈值(例如 100),请删除最旧的分区键,并将该列的值设置回 0。

表锁定

DROP_PARTITIONS 会在目标表上获取一个独占的 O 锁,以阻止可能会影响表数据的任何 DML 操作(DELETEUPDATEINSERTCOPY)。该锁还会阻止在 SERIALIZABLE 隔离级别发出的 SELECT 语句。

如果操作无法在目标表上获取 O lock,Vertica 将尝试关闭该表上运行的任何内部 tuple mover 会话。如果成功,则可以继续操作。在用户会话中运行的显式 Tuple Mover 操作不会关闭。如果显式 Tuple Mover 操作在表上运行,则该操作仅在 Tuple Mover 操作完成后继续。

2 - 存档分区

可以使用 Vertica 函数 MOVE_PARTITIONS_TO_TABLE 在表之间移动分区。此函数对于在下列过程中存档旧分区非常有用:

  1. 标识要存档的分区,并使用 MOVE_PARTITIONS_TO_TABLE 将其移动到临时暂存表

  2. 备份临时表

  3. 删除临时表

可以随时还原已存档的分区

将分区移动到临时表

存档历史数据的方法是标识要从表中移除的分区。然后,将每个分区(或分区组)移动到临时表。

在调用 MOVE_PARTITIONS_TO_TABLE 之前:

  • 刷新所有过时投影。

以下建议适用于临时表:

  • 为了方便备份过程,为每个存档操作的临时表创建唯一架构。

  • 为临时表指定新名称。这可确保它们不包含先前移动操作中的分区。


    如果该表不存在,Vertica 将根据源表的定义,通过调用 CREATE TABLE 包含 LIKEINCLUDING PROJECTIONS 子句来创建一个表。该新表会从源表中继承所有权。有关详细信息,请参阅复制表

  • 使用能够让其他用户轻松标识分区内容的临时名称。例如,如果表按日期分区,则使用指定日期或日期范围的名称。

在以下示例中,MOVE_PARTITIONS_TO_TABLE 指定将单个分区移动到临时表 partn_backup.tradfes_200801

=> SELECT MOVE_PARTITIONS_TO_TABLE (
          'prod_trades',
          '200801',
          '200801',
          'partn_backup.trades_200801');
MOVE_PARTITIONS_TO_TABLE
-------------------------------------------------
 1 distinct partition values moved at epoch 15.
(1 row)

备份临时表。

在创建临时表后,可以使用 vbr 配置文件通过对象级备份来存档它。有关详细信息,请参阅备份和还原数据库

删除临时表

在备份完成后,可以按删除表中所述删除临时表。

还原已存档分区

您可以还原之前移至中间表、存档为对象级别备份后删除的分区。

还原已存档分区的步骤如下:

  1. 还原在移动一个或多个待存档分区时所保存的中间表的备份(请参阅存档分区)。

  2. 将还原后的分区从中间表移至原始表。

  3. 删除中间表。

3 - 交换分区

SWAP_PARTITIONS_BETWEEN_TABLESDROP_PARTITIONSMOVE_PARTITIONS_TO_TABLE 的操作合并为单个事务。如果定期将已分区数据从一个表加载到另一个表,并且需要刷新第二个表中的分区,则 SWAP_PARTITIONS_BETWEEN_TABLES 很有用。

例如,您可能具有一个按日期分区的收入表,而且经常将数据从临时表移动到该表中。临时表有时包含目标表中已有日期的数据。在这种情况下,首先必须从目标表中删除这些日期的分区,然后将其替换为临时表中的相应分区。可以通过调用一次 SWAP_PARTITIONS_BETWEEN_TABLES 来完成这两个任务。

通过将删除和移动操作包装在单个事务中,SWAP_PARTITIONS_BETWEEN_TABLES 可保持交换数据的完整性。如果交换操作中的任何任务失败,整个操作则会失败并回退。

示例

以下示例创建两个已分区表,然后在两者之间交换某些分区。

这两个表的定义相同,且具有不同 year 值的分区。交换 year = 2008 和 year = 2009 的分区。这两个表都至少有两行要交换。

  1. 创建 customer_info 表:

    => CREATE TABLE customer_info (
          customer_id INT NOT NULL,
          first_name VARCHAR(25),
          last_name VARCHAR(35),
          city VARCHAR(25),
          year INT NOT NULL)
          ORDER BY last_name
          PARTITION BY year;
    
  2. customer_info 表中插入数据:

    INSERT INTO customer_info VALUES
     (1,'Joe','Smith','Denver',2008),
     (2,'Bob','Jones','Boston',2008),
     (3,'Silke','Muller','Frankfurt',2007),
     (4,'Simone','Bernard','Paris',2014),
     (5,'Vijay','Kumar','New Delhi',2010);
     OUTPUT
    --------
          5
    (1 row)
    
    => COMMIT;
    
  3. 查看表数据:

    => SELECT * FROM customer_info ORDER BY year DESC;
     customer_id | first_name | last_name |   city    | year
    -------------+------------+-----------+-----------+------
               4 | Simone     | Bernard   | Paris     | 2014
               5 | Vijay      | Kumar     | New Delhi | 2010
               2 | Bob        | Jones     | Boston    | 2008
               1 | Joe        | Smith     | Denver    | 2008
               3 | Silke      | Muller    | Frankfurt | 2007
    (5 rows)
    
  4. 创建第二个表 member_info,其具有与 customer_info 相同的定义:

    => CREATE TABLE member_info LIKE customer_info INCLUDING PROJECTIONS;
    CREATE TABLE
    
  5. member_info 表中插入数据:

    => INSERT INTO member_info VALUES
    (1,'Jane','Doe','Miami',2001),
    (2,'Mike','Brown','Chicago',2014),
    (3,'Patrick','OMalley','Dublin',2008),
    (4,'Ana','Lopez','Madrid',2009),
    (5,'Mike','Green','New York',2008);
     OUTPUT
    --------
          5
    (1 row)
    => COMMIT;
    COMMIT
    
  6. 查看 member_info 表中的数据:

    => SELECT * FROM member_info ORDER BY year DESC;
     customer_id | first_name | last_name |   city   | year
    -------------+------------+-----------+----------+------
               2 | Mike       | Brown     | Chicago  | 2014
               4 | Ana        | Lopez     | Madrid   | 2009
               5 | Mike       | Green     | New York | 2008
               3 | Patrick    | OMalley   | Dublin   | 2008
               1 | Jane       | Doe       | Miami    | 2001
    (5 rows)
    
  7. 要交换分区,请运行 SWAP_PARTITIONS_BETWEEN_TABLES 函数:

    => SELECT SWAP_PARTITIONS_BETWEEN_TABLES('customer_info', 2008, 2009, 'member_info');
                                        SWAP_PARTITIONS_BETWEEN_TABLES
    ----------------------------------------------------------------------------------------------
     1 partition values from table customer_info and 2 partition values from table member_info are swapped at epoch 1045.
    
    (1 row)
    
  8. 查询这两个表以确认它们交换了各自的 2008 年和 2009 年记录:

    => SELECT * FROM customer_info ORDER BY year DESC;
     customer_id | first_name | last_name |   city    | year
    -------------+------------+-----------+-----------+------
               4 | Simone     | Bernard   | Paris     | 2014
               5 | Vijay      | Kumar     | New Delhi | 2010
               4 | Ana        | Lopez     | Madrid    | 2009
               3 | Patrick    | OMalley   | Dublin    | 2008
               5 | Mike       | Green     | New York  | 2008
               3 | Silke      | Muller    | Frankfurt | 2007
    (6 rows)
    
    => SELECT * FROM member_info ORDER BY year DESC;
     customer_id | first_name | last_name |  city   | year
    -------------+------------+-----------+---------+------
               2 | Mike       | Brown     | Chicago | 2014
               2 | Bob        | Jones     | Boston  | 2008
               1 | Joe        | Smith     | Denver  | 2008
               1 | Jane       | Doe       | Miami   | 2001
    (4 rows)
    

4 - 最小化分区

默认情况下,Vertica 最多支持 1024 个 ROS 容器来存储给定投影的分区(请参阅投影参数)。ROS 容器包含共享相同分区键或相同分区组键的数据。根据每个分区的数据量,一个分区或分区组可以跨多个 ROS 容器。

鉴于此限制,不建议按高度精细的数据(例如,按 TIMESTAMP 列)对表进行分区。这样做会生成非常多的分区。如果分区数量需要超过 1024 个 ROS 容器,Vertica 会发出 ROS 推回警告并拒绝加载更多表数据。大量 ROS 容器也会对 DML 操作(例如 DELETE)产生负面影响,这需要 Vertica 打开所有 ROS 容器。

在实践中,您不太可能接近此最大值。为了获得最佳性能,Vertica 建议未分组分区的数量介于 10 到 20 之间,并且不超过 50。此范围通常适用于大多数业务需求。

还可以通过对分区进行分组来减少 ROS 容器的数量。有关详细信息,请参阅分区分组分层分区

5 - 查看分区存储数据

Vertica 提供了多种方式来查看表分区的组织和存储方式:

  • 查询 PARTITIONS 系统表。

  • 转储分区键。

查询 PARTITIONS 表

下面的表和投影定义按订单日期对 store_order 数据进行分区,并将同一年份的分区分组在一起:

=> CREATE TABLE public.store_orders
  (order_no int, order_date timestamp NOT NULL, shipper varchar(20), ship_date date)
  PARTITION BY ((order_date)::date) GROUP BY (date_trunc('year', (order_date)::date));

=> CREATE PROJECTION public.store_orders_super
   AS SELECT order_no, order_date, shipper, ship_date FROM store_orders
   ORDER BY order_no, order_date, shipper, ship_date UNSEGMENTED ALL NODES;

=> COPY store_orders FROM '/home/dbadmin/export_store_orders_data.txt';

在将数据加载到此表后,可以查询 PARTITIONS 表,以确定所有节点上有多少个 ROS 容器存储投影 store_orders_unseg 的已分组分区。每个节点有八个 ROS 容器,每个容器存储一个分区组的分区:

=> SELECT COUNT (partition_key) NumPartitions, ros_id, node_name FROM PARTITIONS
       WHERE projection_name ilike 'store_orders%' GROUP BY ros_id, node_name ORDER BY node_name, NumPartitions;
 NumPartitions |      ros_id       |    node_name
---------------+-------------------+------------------
           173 | 45035996274562779 | v_vmart_node0001
           211 | 45035996274562791 | v_vmart_node0001
           212 | 45035996274562783 | v_vmart_node0001
           213 | 45035996274562787 | v_vmart_node0001
           173 | 49539595901916471 | v_vmart_node0002
           211 | 49539595901916483 | v_vmart_node0002
           212 | 49539595901916475 | v_vmart_node0002
           213 | 49539595901916479 | v_vmart_node0002
           173 | 54043195529286985 | v_vmart_node0003
           211 | 54043195529286997 | v_vmart_node0003
           212 | 54043195529286989 | v_vmart_node0003
           213 | 54043195529286993 | v_vmart_node0003
(12 rows)

转储分区键

Vertica 提供了多个函数,允许您在多个级别检查各个分区在群集上的存储方式:

给定前面的表和投影,DUMP_PROJECTION_PARTITION_KEYS 显示每个节点上四个 ROS 容器的内容:


=> SELECT DUMP_PROJECTION_PARTITION_KEYS('store_orders_super');
 ...
 Partition keys on node v_vmart_node0001
  Projection 'store_orders_super'
   Storage [ROS container]
     No of partition keys: 173
     Partition keys: 2017-01-02 2017-01-03 2017-01-04 2017-01-05 2017-01-06 2017-01-09 2017-01-10
2017-01-11 2017-01-12 2017-01-13 2017-01-16 2017-01-17 2017-01-18 2017-01-19 2017-01-20 2017-01-23
2017-01-24 2017-01-25 2017-01-26 2017-01-27 2017-02-01 2017-02-02 2017-02-03 2017-02-06 2017-02-07
2017-02-08 2017-02-09 2017-02-10 2017-02-13 2017-02-14 2017-02-15 2017-02-16 2017-02-17 2017-02-20
...
2017-09-01 2017-09-04 2017-09-05 2017-09-06 2017-09-07 2017-09-08 2017-09-11 2017-09-12 2017-09-13
2017-09-14 2017-09-15 2017-09-18 2017-09-19 2017-09-20 2017-09-21 2017-09-22 2017-09-25 2017-09-26 2017-09-27
   Storage [ROS container]
     No of partition keys: 212
     Partition keys: 2016-01-01 2016-01-04 2016-01-05 2016-01-06 2016-01-07 2016-01-08 2016-01-11
2016-01-12 2016-01-13 2016-01-14 2016-01-15 2016-01-18 2016-01-19 2016-01-20 2016-01-21 2016-01-22
2016-01-25 2016-01-26 2016-01-27 2016-02-01 2016-02-02 2016-02-03 2016-02-04 2016-02-05 2016-02-08
2016-02-09 2016-02-10 2016-02-11 2016-02-12 2016-02-15 2016-02-16 2016-02-17 2016-02-18 2016-02-19
...
2016-11-01 2016-11-02 2016-11-03 2016-11-04 2016-11-07 2016-11-08 2016-11-09 2016-11-10 2016-11-11
2016-11-14 2016-11-15 2016-11-16 2016-11-17 2016-11-18 2016-11-21 2016-11-22 2016-11-23 2016-11-24 2016-11-25
   Storage [ROS container]
     No of partition keys: 213
     Partition keys: 2015-01-01 2015-01-02 2015-01-05 2015-01-06 2015-01-07 2015-01-08 2015-01-09
2015-01-12 2015-01-13 2015-01-14 2015-01-15 2015-01-16 2015-01-19 2015-01-20 2015-01-21 2015-01-22
2015-01-23 2015-01-26 2015-01-27 2015-02-02 2015-02-03 2015-02-04 2015-02-05 2015-02-06 2015-02-09
2015-02-10 2015-02-11 2015-02-12 2015-02-13 2015-02-16 2015-02-17 2015-02-18 2015-02-19 2015-02-20
...
2015-11-02 2015-11-03 2015-11-04 2015-11-05 2015-11-06 2015-11-09 2015-11-10 2015-11-11 2015-11-12
2015-11-13 2015-11-16 2015-11-17 2015-11-18 2015-11-19 2015-11-20 2015-11-23 2015-11-24 2015-11-25
2015-11-26 2015-11-27
   Storage [ROS container]
     No of partition keys: 211
     Partition keys: 2014-01-01 2014-01-02 2014-01-03 2014-01-06 2014-01-07 2014-01-08 2014-01-09
2014-01-10 2014-01-13 2014-01-14 2014-01-15 2014-01-16 2014-01-17 2014-01-20 2014-01-21 2014-01-22
2014-01-23 2014-01-24 2014-01-27 2014-02-03 2014-02-04 2014-02-05 2014-02-06 2014-02-07 2014-02-10
2014-02-11 2014-02-12 2014-02-13 2014-02-14 2014-02-17 2014-02-18 2014-02-19 2014-02-20 2014-02-21
...
2014-11-04 2014-11-05 2014-11-06 2014-11-07 2014-11-10 2014-11-11 2014-11-12 2014-11-13 2014-11-14
2014-11-17 2014-11-18 2014-11-19 2014-11-20 2014-11-21 2014-11-24 2014-11-25 2014-11-26 2014-11-27
   Storage [ROS container]
     No of partition keys: 173
...