使用 TTL 管理数据保留

本页面介绍了如何在 Spanner 表上使用存留时间 (TTL)。如需了解详情,请参阅关于 TTL

准备工作

开始之前,请遵循以下最佳实践。

启用备份和时间点恢复

在将 TTL 添加到您的表之前,我们建议您启用 Spanner 备份和恢复。这样,您就可以在您不小心使用 TTL 政策删除数据时完全恢复数据库。

如果您已启用时间点恢复,并且已删除的数据在已配置的版本保留期限内,则可以查看和恢复这些数据,而不必从备份进行完全恢复。如需了解如何读取过去的数据,请参阅执行过时读取

清理旧数据

如果这是您第一次使用 TTL,并且您希望第一次运行会删除很多行,请考虑先使用分区 DML 手动清理旧数据。这样一来,您就可以更好地控制资源使用情况,而不是留给 TTL 后台进程使用。TTL 以较低的优先级运行,非常适合增量清理。但是,这样做可能会延长删除繁忙数据库中的初始行集所需的时间,因为 Spanner 的内部工作调度程序将优先考虑其他工作,例如用户查询。

验证您的条件

对于 GoogleSQL 表,如果要在启用 TTL 之前验证行删除政策将影响的数据,可以使用相同的条件查询该表。例如:

GoogleSQL

  SELECT COUNT(*)
  FROM CalculatedRoutes
  WHERE TIMESTAMP_ADD(CreatedAt, INTERVAL 30 DAY) < CURRENT_TIMESTAMP();

所需权限

如需更改数据库的架构,您必须拥有 spanner.databases.updateDdl 权限。如需了解详情,请参阅 Spanner 的访问权限控制

创建行删除政策

GoogleSQL

如需使用 GoogleSQL 创建行删除政策,您可以在创建新表时定义 ROW DELETION POLICY 子句,或向现有表添加政策。此子句包含一个列和间隔的表达式。

如需在创建表时添加政策,请执行以下操作:

CREATE TABLE MyTable(
Key INT64,
CreatedAt TIMESTAMP,
) PRIMARY KEY (Key),
ROW DELETION POLICY (OLDER_THAN(timestamp_column, INTERVAL num_days DAY));

其中:

  • timestamp_column 必须是类型为 TIMESTAMP 的现有列。具有提交时间戳的列和生成的列都是有效的。但是,您无法指定引用了提交时间戳列的生成列。

  • num_daystimestamp_column 中时间戳的过去天数(在该日期内,相应行已被标记为要删除的行)。该值必须是非负整数,且 DAY 是唯一支持的单位。

如需向现有表添加政策,请使用 ALTER TABLE 语句。一个表最多只能有一项行删除政策。向具有现有政策的表添加行删除政策会失败并显示错误。请参阅生成的列上的 TTL 以指定更复杂的行删除逻辑。

ALTER TABLE Albums
ADD ROW DELETION POLICY (OLDER_THAN(timestamp_column, INTERVAL num_days DAY));

PostgreSQL

如需使用 PostgreSQL 创建行删除政策,您可以在创建新表时定义 TTL INTERVAL 子句,或向现有表添加政策。

如需在创建表时添加政策,请执行以下操作:

CREATE TABLE mytable (
  key bigint NOT NULL,
  timestamp_column_name TIMESTAMPTZ,
  PRIMARY KEY(key)
) TTL INTERVAL interval_spec ON timestamp_column_name;

其中:

  • timestamp_column_name 必须是数据类型为 TIMESTAMPTZ 的列。您需要在 CREATE TABLE 语句中创建此列。具有提交时间戳的列和生成的列都是有效的。但是,您无法指定引用了提交时间戳列的生成列。

  • interval_spectimestamp_column_name 中时间戳的过去天数(在该日期内,已将行标记为删除)。该值必须是非负整数,且计算结果必须为整数天数。例如,允许使用 '3 days',但 '3 days - 2 minutes' 会返回错误。

如需向现有表添加政策,请使用 ALTER TABLE 语句。一个表最多只能有一项 TTL 政策。将 TTL 政策添加到具有现有政策的表会失败并显示错误。请参阅对生成的列执行 TTL 指定更复杂的 TTL 逻辑。

如需向现有表添加政策,请执行以下操作:

ALTER TABLE albums
ADD COLUMN timestampcolumn TIMESTAMPTZ;

ALTER TABLE albums
ADD TTL INTERVAL '5 days' ON timestampcolumn;

限制

行删除政策具有以下限制。

外键引用的表的 TTL

您无法在以下对象上创建行删除政策:

  • 由不包含 ON DELETE CASCADE 限制条件的外键引用的表。
  • 针对由不包含 ON DELETE CASCADE 引用操作的外键引用的表的父键。

在以下示例中,您不能向 Customers 表添加行删除政策,因为它由 Orders 表中的外键引用,该表没有 ON DELETE CASCADE 限制条件。删除客户可能会违反此外键限制条件。也不能向 Districts 表添加行删除政策。从 Districts 中删除行可能会导致删除操作在子 Customers 表中级联,这可能会违反 Orders 表的外键限制条件。

GoogleSQL

CREATE TABLE Districts (
  DistrictID INT64
) PRIMARY KEY (DistrictID);

CREATE TABLE Customers (
  DistrictID INT64,
  CustomerID INT64,
  CreatedAt TIMESTAMP
) PRIMARY KEY (DistrictID, CustomerID),
INTERLEAVE IN PARENT Districts ON DELETE CASCADE;

CREATE TABLE Orders (
  OrderID INT64,
  DistrictID INT64,
  CustomerID INT64,
  CONSTRAINT FK_CustomerOrder FOREIGN KEY (DistrictID, CustomerID) REFERENCES Customers (DistrictID, CustomerID)
) PRIMARY KEY (OrderID);

PostgreSQL

CREATE TABLE districts (
  districtid   bigint NOT NULL,
  PRIMARY KEY(districtid)
);

CREATE TABLE customers (
  districtid   bigint NOT NULL,
  customerid   bigint NOT NULL,
  createdat  timestamptz,
  PRIMARY KEY(districtid, customerid)
) INTERLEAVE IN PARENT districts ON DELETE CASCADE;

CREATE TABLE orders (
  orderid bigint NOT NULL,
  districtid   bigint,
  customerid bigint,
  PRIMARY KEY(orderid),
  CONSTRAINT fk_customerorder FOREIGN KEY (districtid, customerid) REFERENCES customers (districtid, customerid)
);

您可以针对由使用 ON DELETE CASCADE 的外键限制条件引用的表创建行删除政策。在以下示例中,您可以对 Customers 表创建行删除政策,该政策由 Orders 表中定义的外键限制条件 CustomerOrder 引用。当 TTL 删除 Customers 中的行时,删除操作会级联到 Orders 表中的匹配行。

GoogleSQL

 CREATE TABLE Districts (
  DistrictID INT64,
  CreatedAt TIMESTAMP
) PRIMARY KEY (DistrictID),
ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 1 DAY));

CREATE TABLE Customers (
  DistrictID INT64,
  CustomerID INT64,
  CreatedAt TIMESTAMP
) PRIMARY KEY (DistrictID, CustomerID),
INTERLEAVE IN PARENT Districts ON DELETE CASCADE,
ROW DELETION POLICY (OLDER_THAN(CreatedAt, INTERVAL 1 DAY));

CREATE TABLE Orders (
  OrderID INT64,
  DistrictID INT64,
  CustomerID INT64,
  CONSTRAINT FK_CustomerOrder FOREIGN KEY (DistrictID, CustomerID) REFERENCES Customers (DistrictID, CustomerID) ON DELETE CASCADE
) PRIMARY KEY (OrderID);

PostgreSQL

CREATE TABLE districts (
  districtid   bigint NOT NULL,
  createdat  timestamptz,
  PRIMARY KEY(districtid)
) TTL INTERVAL '1 day' ON createdat;

CREATE TABLE customers (
  districtid   bigint NOT NULL,
  customerid   bigint NOT NULL,
  createdat  timestamptz,
  PRIMARY KEY(districtid, customerid)
) INTERLEAVE IN PARENT districts ON DELETE CASCADE
TTL INTERVAL '1 day' ON createdat;

CREATE TABLE orders (
  orderid bigint NOT NULL,
  districtid bigint,
  customerid bigint,
  PRIMARY KEY(orderid),
  CONSTRAINT fk_customerorder FOREIGN KEY (districtid, customerid) REFERENCES customers (districtid, customerid) ON DELETE CASCADE
);

同样,您可以对由 ON DELETE CASCADE 外键限制条件引用的表的父表创建行删除政策。

采用默认值的列的 TTL

行删除政策可以使用具有默认值的时间戳列。典型的默认值为 CURRENT_TIMESTAMP。如果未明确为该列分配任何值,或者 INSERTUPDATE 语句将列设置为默认值,则在规则计算中使用默认值。

在以下示例中,表 CustomersCreatedAt 列的默认值是创建该行时的时间戳。

GoogleSQL

CREATE TABLE Customers (
  CustomerID INT64,
  CreatedAt TIMESTAMP DEFAULT (CURRENT_TIMESTAMP())
) PRIMARY KEY (CustomerID);

如需了解详情,请参阅“GoogleSQL 数据定义语言”中的默认(表达式)

PostgreSQL

CREATE TABLE customers (
  customerid bigint NOT NULL,
  createdat timestamptz DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY(customerid)
  );

如需了解详情,请参阅“PostgreSQL 数据定义语言”中的创建表

生成的列上的 TTL

行删除政策可以使用生成的列来表示更复杂的规则。例如,您可以针对多列的 greatest 时间戳(GoogleSQLPostgreSQL)定义行删除政策,或者将其他值映射到时间戳。

GoogleSQL

下表(名为 Orders)用于跟踪销售订单。表所有者想要设置一个行删除政策,以便在 30 天后删除已取消的订单,并在 180 天后删除未取消的订单。

Spanner TTL 仅允许每个表有一项行删除政策。若要在单个列中表示这两个条件,可以使用生成的列并搭配 IF 语句:

CREATE TABLE Orders (
  OrderId INT64 NOT NULL,
  OrderStatus STRING(30) NOT NULL,
  LastModifiedDate TIMESTAMP NOT NULL,
  ExpiredDate TIMESTAMP AS (IF(OrderStatus = 'Cancelled',
    TIMESTAMP_ADD(LastModifiedDate, INTERVAL 30 DAY),
    TIMESTAMP_ADD(LastModifiedDate, INTERVAL 180 DAY))) STORED,
) PRIMARY KEY(OrderId),
ROW DELETION POLICY (OLDER_THAN(ExpiredDate, INTERVAL 0 DAY));

该语句会创建一个名为 ExpiredDate 的列,该列会根据订单状态向 LastModifiedDate 添加 30 天或 180 天。然后,它通过指定 INTERVAL 0 day 定义行删除政策,以在 ExpiredDate 列中存储的行之日过期。

PostgreSQL

下表(名为 Orders)用于跟踪销售订单。表所有者希望设置行删除政策,以在处于非活动状态 30 天后删除行。

Spanner TTL 仅允许每个表有一项行删除政策。如需在单个列中表示这两个条件,您可以创建一个生成的列:

CREATE TABLE orders (
    orderid bigint NOT NULL,
    orderstatus varchar(30) NOT NULL,
    createdate timestamptz NOT NULL,
    lastmodifieddate timestamptz,
    expireddate timestamptz GENERATED ALWAYS AS (GREATEST(createdate, lastmodifieddate)) STORED,
    PRIMARY KEY(orderid)
) TTL INTERVAL '30 days' ON expireddate;

该语句会创建一个名为 ExpiredDate 的生成列,用于计算两个日期(LastModifiedDateCreateDate)中最近的日期。然后,它会定义行删除政策,以在订单创建 30 天后过期,或者如果订单在这 30 天内发生了修改,则会将删除再延长 30 天。

TTL 和交错表

交错表是将一对多子表中的相关行与父表中的行相关联的性能优化。如需在父表上添加行删除政策,所有交错子表都必须指定 ON DELETE CASCADE,这意味着子行将与父行一起以原子方式删除。这样可以确保参照完整性,以便父表上的删除也会删除同一事务中的相关子行。Spanner TTL 不支持 ON DELETE NO ACTION

事务大小上限

Spanner 设有事务大小限制。如果对包含索引列的大型父子层次结构执行级联删除操作,可能会超出这些限制,导致一项或多项 TTL 操作失败。对于失败的操作,TTL 将使用较小的批量进行重试,最小的批量为单个父行。但是,即使是单个父行的大型子层次结构仍有可能超出变更限制。

TTL 指标中将会报告失败的操作。

如果单个行及其交错的子表因过大而无法删除,那么除了父表上的行删除政策之外,您还可以直接在子表上附加行删除政策。应配置子表的政策,使子行先于父行删除。

当以下两个语句适用时,请考虑将行删除政策附加到子表:

  • 子表具有任何与之关联的全局索引;且
  • 每个父行预计包含大量 (>100) 子行。

删除行删除政策

您可以从表中删除现有行删除政策。如果表上没有行删除政策,则返回错误。

GoogleSQL

ALTER TABLE MyTable
DROP ROW DELETION POLICY;

PostgreSQL

ALTER TABLE mytable
DROP TTL;

删除行删除政策会立即中止在后台运行的任何 TTL 进程。正在进行的进程已删除的所有行都将被删除。

删除行删除政策引用的列

Spanner 不允许删除行删除政策引用的列。您必须先删除行删除政策,然后才能删除该列。

查看表的行删除政策

您可以查看 Spanner 表的行删除政策。

GoogleSQL

SELECT TABLE_NAME, ROW_DELETION_POLICY_EXPRESSION
FROM INFORMATION_SCHEMA.TABLES
WHERE ROW_DELETION_POLICY_EXPRESSION IS NOT NULL;

如需了解详情,请参阅 GoogleSQL 方言数据库的信息架构

PostgreSQL

SELECT table_name, row_deletion_policy_expression
FROM information_schema.tables
WHERE row_deletion_policy_expression is not null;

如需了解详情,请参阅 PostgreSQL 方言数据库的信息架构

修改行删除政策

您可以更改现有行删除政策的列或间隔表达式。以下示例将列从 CreatedAt 切换到 ModifiedAt,并将间隔从 1 DAY 延长到 7 DAY。如果表上没有现有的行删除政策,则会返回错误。

GoogleSQL

ALTER TABLE MyTable
REPLACE ROW DELETION POLICY (OLDER_THAN(ModifiedAt, INTERVAL 7 DAY));

PostgreSQL

ALTER TABLE mytable
ALTER TTL INTERVAL '7 days' ON timestampcolumn;