使用持久化查询结果

当执行查询时,结果会保留(即缓存)一段时间。在时间段结束时,将从系统中清除结果。

Snowflake 使用持久化查询结果,避免在没有任何更改时重新生成结果(即“检索优化”)。此外,还可以使用持久化查询结果对结果进行后处理(例如,在已计算的结果之上分层新查询)。

对于所有大小的持久化查询结果,缓存将在 24 小时后过期。

请注意,用于访问 大型 持久化查询结果(即大小超过 100 KB )的安全令牌将在 6 小时后过期。可以检索新令牌,以便在结果仍在缓存中时访问结果。较小的持久化查询结果不使用访问令牌。

备注

提供给 Snowflake Connector for Spark(“Spark Connector”)的令牌将在 24 小时后过期,而不管持久化查询结果的大小如何。Spark Connector 利用较长的缓存过期时间来避免某些用例中的超时。

另请参阅 优化仓库缓存,其中讨论了活跃状态的仓库如何缓存和重复使用表数据。

本主题内容:

检索优化

如果用户重复已运行的查询,并且自上次运行查询以来表中的数据未发生更改,则查询结果相同。Snowflake 不会再次运行查询,而是简单地返回之前返回的相同结果。这可以大大减少查询时间,因为 Snowflake 绕过查询执行,而直接从缓存中检索结果。

通常,如果满足以下 所有 条件,则会重用查询结果:

  • 新查询与以前执行的查询完全匹配。语法上的任何差异(包括小写与大写)或表别名的使用都将禁止 100% 的缓存重用。例如,考虑以下连续运行的查询:

    SELECT DISTINCT(severity) FROM weather_events;
    SELECT DISTINCT(severity) FROM weather_events;
    SELECT DISTINCT(severity) FROM weather_events we;
    select distinct(severity) from weather_events;
    
    Copy

    第一个查询将填充缓存,相同的第二个查询将受益于 100% 的缓存重用。但是,第三个和第四个查询不会触发缓存重用,这仅仅是因为第三个查询引入了表别名,而第四个查询使用小写关键字。

  • 查询不包括不可重用的函数,这些函数会为同一查询的连续运行返回不同的结果。UUID_STRINGRANDOMRANDSTR 是不可重用函数的良好示例。

  • 查询不包括 外部函数

  • 该查询不会从 混合表 中进行选择。

  • 参与查询结果的表数据未更改。

  • 上一个查询的持久化结果仍然可用。

  • 访问缓存结果的角色具有所需的权限。

    • 如果查询是 SELECT 查询,则执行查询的角色必须对缓存查询中使用的所有表具有必要的访问权限。

    • 如果查询是 SHOW 查询,则执行查询的角色必须与生成缓存结果的角色匹配。

  • 任何影响结果生成方式的配置选项均未更改。

  • 由于表中其他数据的更改,表的微分区未发生更改(例如,已重聚类或合并)。

备注

满足所有这些条件并不能 保证 Snowflake 重用查询结果。

默认情况下,结果重用处于启用状态,但可以使用 USE_CACHED_RESULT 会话参数在账户、用户和会话级别覆盖结果。

备注

每次重复使用查询的持久化结果时,Snowflake 都会重置结果的 24 小时保留期,最多为从首次执行查询的日期和时间起的 31 天。31 天后,将清除结果,下次提交查询时,将生成并保留新结果。

后处理查询结果

在某些情况下,您可能希望对已运行的查询结果执行进一步处理。例如:

  • 您正在逐步开发一个复杂的查询,并且希望在上一个查询的基础上添加一个新层并运行新查询,而无需从头开始重新计算部分结果。

  • 上一个查询是 SHOW <objects>DESCRIBE <object>CALL 语句,它以不易重用的形式返回结果。

    例如,不能像在 SQL 语句中调用函数那样在更复杂的 SQL 语句中调用存储过程,因此处理存储过程输出的唯一方法是对存储的查询结果进行后处理。

可以使用 RESULT_SCAN 表函数执行后处理。该函数以“表”的形式返回上一个查询的结果,然后可以对表格数据运行新查询。

示例

处理 SHOW TABLES 命令的结果,并从结果中提取以下列和行:

  • schema_nametable_namerows 列。

  • 空表的行。

SHOW TABLES;

+-----+-------------------------------+-------------+-------+-------+------+
| Row |           created_on          | name        | ...   | ...   | rows |
+-----+-------------------------------+-------------+-------+-------+------+
|  1  | 2018-07-02 09:43:49.971 -0700 | employees   | ...   | ...   | 2405 |
+-----+-------------------------------+-------------+-------+-------+------+
|  2  | 2018-07-02 09:43:52.483 -0700 | dependents  | ...   | ...   | 5280 |
+-----+-------------------------------+-------------+-------+-------+------+
|  3  | 2018-07-03 11:43:52.483 -0700 | injuries    | ...   | ...   |    0 |
+-----+-------------------------------+-------------+-------+-------+------+
|  4  | 2018-07-03 11:43:52.483 -0700 | claims      | ...   | ...   |    0 |
+-----+-------------------------------+-------------+-------+-------+------+
| ...                                                                      |
| ...                                                                      |
+-----+-------------------------------+-------------+-------+-------+------+

-- Show the tables that are empty.
SELECT  "schema_name", "name" as "table_name", "rows"
    FROM table(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "rows" = 0;

+-----+-------------+-------------+------+
| Row | schema_name | name        | rows |
+-----+-------------+-------------+------+
|  1  |  PUBLIC     | injuries    |    0 |
+-----+-------------+-------------+------+
|  2  |  PUBLIC     | claims      |    0 |
+-----+-------------+-------------+------+
| ...                                    |
| ...                                    |
+-----+-------------+-------------+------+
Copy

RESULT_SCAN 中提供了其他示例。

语言: 中文