使用 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 数据定义语言”中的 DEFAULT (expression)

PostgreSQL

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

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

生成的列上的 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;