跳至主要内容

使用 Snowflake 时光回溯(Time Travel):完整指南

在这篇深入指南中,了解如何利用 Snowflake 的时光回溯功能查询历史、克隆表以及恢复数据,助您完成数据库恢复。
· 9分钟 阅读

使用 AI 探索

Snowflake 中的 Time Travel 是什么?

就像软件工程师使用 Git 进行版本控制一样,数据工程师可以在 Snowflake 数据库中使用 Time Travel。通过 Time Travel,数据库管理员可以查询历史数据、克隆旧表,以及恢复过去被删除的对象。

不过,鉴于数据库可能会变得非常庞大,Time Travel 并不是代码版本控制的简单替代。每当表被修改(删除或更新)时,Snowflake 都会对更新前的数据状态进行快照。该快照只会保留指定的天数,这被称为数据保留期。

对于 Snowflake Standard 帐户,最大保留期仅为 1 天。对于 Enterprise 帐户,保留期可设置为 0 到 90 天之间。将保留期设为 0 会实际禁用 Time Travel;默认情况下,所有表均启用该功能。

Snowflake Time Travel 与 Fail-Safe 的区别

阅读Snowflake 文档时,您可能也会遇到“Fail-safe”这一术语。仅从名称看,Time Travel 和 Fail-safe 似乎执行相同任务,但事实并非如此。

当对象的保留期结束后,会被转入 Snowflake 的 Fail-safe。在 Fail-safe 中,您无法:

  • 查询历史数据
  • 克隆历史对象
  • 恢复过去被删除的对象

Fail-safe 仅在不可配置的 7 天期限内保留数据。在此期间,数据只能由 Snowflake 自行恢复。该功能作为数据恢复服务,仅在所有其他恢复方法均失败时作为最后手段使用,适用于因操作故障导致数据损坏或删除的情况。

因此,一旦对象自然度过了其设定的保留期,您就不能请求 Snowflake 恢复其过去版本。请在学习本教程时牢记这一点。

环境准备

Snowflake 提供两种与平台交互的界面:SnowSight(Web 界面)和 Snowflake CLI(终端客户端)。我们将使用更易上手的 SnowSight。如果您是 Snowflake 新手,可阅读这篇完整教程,其中也介绍了如何使用 Snowflake CLI。

首先,从Snowflake 主页注册一个免费帐户。您将获得 30 天的 Enterprise 功能试用期。

Snowflake 主页

帐户就绪后,您会被引导至仪表板的 Worksheets 页面。您可以将每个工作表视为运行 SQL 甚至 Python 的独立环境。

Snowflake 工作表

现在,使用右上角的“+”按钮创建一个新工作表:

在 Snowflake 中创建数据库和表

接下来,我们来创建一些数据库和表,并填充数据。

创建数据库和数据表

首先,我们将创建一个名为 ecommerce_db 的数据库。粘贴以下代码并按 "Ctrl + Enter"(或 Cmd + Enter)运行("Ctrl + Shift + Enter" 运行整个工作表中的语句)。

CREATE DATABASE IF NOT EXISTS ecommerce_db;

我们将使用这个假想数据库来销售与 AI 相关的周边。运行下面的命令将其设为默认数据库:

USE DATABASE ecommerce_db;

首先,我们将创建一个名为 inventory 的表,包含三列:

CREATE OR REPLACE TABLE inventory (
 product_id INT PRIMARY KEY,
 name VARCHAR(255),
 stock_level INT,
 last_updated TIMESTAMP_TZ DEFAULT CURRENT_TIMESTAMP
);

然后,我们添加一些初始商品:

INSERT INTO inventory (product_id, name, stock_level)
VALUES (1, Llama hoodie', 10), (2, Falcon cap', 20);

我们还将创建一个订单表:

CREATE OR REPLACE TABLE orders (
 order_id INT PRIMARY KEY,
 product_id INT REFERENCES inventory(product_id),
 quantity INT,
 order_date TIMESTAMP_TZ DEFAULT CURRENT_TIMESTAMP
);
-- Assume some time passes after this table was created

我们上线网站售卖周边后,收到了几笔订单。上午,我们收到两笔针对两个产品的订单:

INSERT INTO orders (order_id, product_id, quantity)
VALUES (1, 1, 5), (1, 2, 3);

下午,我们又收到一笔:

-- Simulate a system glitch causing an extra order for product 1
INSERT INTO orders (order_id, (product_id, quantity)
VALUES  (3, 1, 100);  -- This might cause negative stock

但由于系统故障,这笔订单记录的数量超出了我们的库存。假设我们在两周后才发现这个问题。

请注意,我在幕后对表还做了一些其他更新。

控制保留期

第一项任务是设置保留期。我的免费试用已结束,因此我只能将其设为 1 天:

ALTER TABLE inventory SET DATA_RETENTION_TIME_IN_DAYS=1;
ALTER TABLE orders SET DATA_RETENTION_TIME_IN_DAYS=1;

如果您的试用未结束,请尝试将其设为四周,因为您的试用期在此之后也会结束。

使用 AT 和 BEFORE 子句

Snowflake 通过以下 SQL 扩展实现 Time Travel:

  • 在 SELECT 语句中使用 AT 和 BEFORE 子句,以精确定位要查询的时间点(或时间段)。它们支持以下参数来完成该任务:
  • TIMESTAMP
  • OFFSET —— 相对于当前时间的秒数差
  • STATEMENT —— 唯一查询 ID
  • UNDROP 命令用于恢复表、Schema 和数据库

我们来看如何在示例数据库上使用这些扩展。

查询历史数据

首先,查看我们在 inventory 中有哪些记录:

-- Check current stock level (might show negative value)
SELECT * FROM inventory;

在 Snowflake 中查询历史数据

现在,我们把订单和库存结合起来看:

SELECT i.name, i.stock_level, o.quantity as "order_amount"
 FROM inventory as i
 JOIN orders as o
   ON i.product_id = o.product_id;

Snowflake 示例:合并订单和库存

糟糕!看起来出现了错误——Llama 连帽衫的订单数量超过了我们的库存。我们尝试回溯 17.5 小时,以定位这条错误语句的执行时间:

SELECT * FROM orders AT(OFFSET => -60*60*17.5); -- Go back 17.5

Snowflake 时光回溯

因此,不正确的订单是在 3 月 6 日下午 4:54 下的。这意味着我们需要该时间点之前的表状态。使用 BEFORE 子句很容易查询:

-- Change the timezone
ALTER SESSION  SET TIMEZONE = 'UTC';

-- Select the table state before the error
SELECT * FROM orders BEFORE(TIMESTAMP => '2024-03-06 04:54:00 -0800'::timestamp_tz);

别忘了将 timestamp_tz 作为时间戳的数据类型;tz 代表时区。

将 timestamp_tz 作为数据类型添加

这些示例展示了如何结合时间戳和偏移量使用 AT 与 BEFORE 子句。如果您不想计算查询的具体时间点,也可以使用语句 ID。

例如,下面的查询与上一个查询执行相同任务——在错误订单插入之前查询表状态:

SELECT * FROM orders BEFORE(STATEMENT => '01b2ce86-0000-95e2-0000-000669127035');

以下是查找任意语句的查询 ID 的方法:

Snowflake 查找查询 ID

在 SnowSight 中,通过筛选查询类型,您可以更快地找到目标查询。

克隆历史对象

现在,我们的表里存在一条不正确的订单——该如何去除它?

一种做法是克隆一个不包含错误行的表:

CREATE OR REPLACE TABLE orders_clone AS
SELECT * FROM orders WHERE quantity != 100;

SELECT * FROM orders_clone;

克隆历史对象

这奏效了,而且我们并未依赖 Time Travel 来修复问题。但当您需要克隆表的过去状态时,可以使用如下语法:

-- Clone an object as it existed 2 days ago
CREATE TABLE old_table_clone CLONE olt_table
   AT(OFFSET => -2 * 24 * 60 * 60);  -- Offset for 2 days

克隆数据库也类似:

CREATE DATABASE cloned_db CLONE my_db
 BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');

删除与恢复对象

假设我们刚雇了一位实习生,并把修复错误订单的问题交给了 TA。

在尝试删除那条记录时,这位实习生不小心在生产环境中删掉了 orders 表:

-- Simulate accidentally dropping the orders table
DROP TABLE orders

SELECT * FROM orders;;

删除与恢复对象

实习生惊慌失措地来找我们,说明了情况。于是我们冷静地执行 UNDROP 命令:

-- Recover the dropped table using UNDROP
UNDROP TABLE orders

SELECT * FROM orders;;

表成功恢复。我们也原谅了这位实习生,当然不会因为这次失误而解雇 TA。

结语

在本教程中,我们学习了 Snowflake 的一项关键功能——Time Travel。借助 Time Travel,您可以查询和恢复过去的信息,这是数据库管理工具中非常受欢迎的能力。

在生产环境中,任何事情都有可能发生;而在每次更新前拥有数据库的备份,能让人更加安心。

我认为 Snowflake 是目前最好的数据库管理工具之一。它非常强大,掌握它是数据岗位的加分技能。如果您想进一步学习,欢迎查看 DataCamp 的Introduction to Snowflake 课程。

如果您已较为熟悉并想检验自己的水平,不妨看看 2024 年可选的最佳 Snowflake 认证。

Bexruz (Bex) Tuychiev

作者

Bexruz (Bex) Tuychiev

我是一名数据科学内容创作者,拥有超过 2 年的经验,并在 Medium 上拥有较大的读者群。我喜欢用略带讽刺的笔调撰写有关 AI 和机器学习的深度文章——毕竟总得想点办法让这些内容不那么枯燥。我已发表 130 多篇文章,并制作了一门 DataCamp 课程,另有一门正在筹备中。我的内容已被超过 500 万人次阅读,其中有 2 万人在 Medium 和 LinkedIn 上成为关注者。 

主题