Snowflake 中的性能运行

31 2025 年 7 月 | 阅读 8 分钟

为什么 Snowflake 查询运行缓慢?

了解 Snowflake 查询性能缓慢的根本原因对于优化它们至关重要。网络延迟对查询的总体性能影响很小或没有影响。Snowflake 采用分布式设计,跨多个节点并行执行查询片段。

虽然网络问题可能导致一些查询延迟,但它们并不是持续执行缓慢的主要原因。现在我们已经澄清了这些误解,让我们来看看 Snowflake 中查询运行缓慢的其他根本原因以及如何改进 Snowflake 性能优化。

Performance Running in Snowflake

Snowflake 性能调优技术

检查并减少排队

最有效的 Snowflake 性能调优策略之一是检查并消除排队。当仓库忙于运行其他查询时,就会发生排队,Snowflake 无法在有足够资源可用之前开始处理传入的查询。这可能发生在仓库过载、队列中的查询消耗计算资源,或者查询占用了仓库的所有核心时。

如何减少排队?

为了指定查询可以在队列中等待多长时间才会被 Snowflake 取消,级别提供了灵活性,但如果设置次数过多可能会导致混淆。调整此参数应经过战略性仔细考虑。

Performance Running in Snowflake

Snowflake 仓库可以是单集群或多集群。单集群仓库中的查询会推迟,直到正在运行的查询释放资源或配置了额外的资源。当一个多集群仓库达到最大并发量时,会为每个新查询生成一个新的集群。

MAX_CONCURRENCY_LEVEL 选项并不限制查询数量。相反,它会防止仓库因过多的运行请求而负担过重。

以下是改进分区修剪的示例

只投影必需的列:限制查询中投影的列可以帮助减少总体数据大小,可能防止或最小化磁盘溢出。在 SELECT 语句中,提及必需的列而不是所有列。

Snowflake 查询优化:Snowflake 查询优化器使用了许多高级查询调优算法。但是,默认表不支持 Snowflake 索引。

为什么 Snowflake 性能调优很重要?

需要系统调优专业人员来帮助最大限度地提高性能并降低成本。与需要预先购买硬件和许可证的本地数据库不同,Snowflake 是按秒计费的,计算资源(虚拟仓库)在使用期间才会计费。要在 Snowflake 中实现良好的性能调优,您必须首先确定优先级。

减少查询执行时间:这是最终用户查询的共同优先级,但对于快速数据采集和转换以便及时发送数据进行分析也至关重要。这是本文的主要重点。

Snowflake 架构详解

在深入研究具体的 Snowflake SQL 调优策略之前,值得考虑图中所示的架构。Snowflake 由三个相互连接的计算机系统组成,每个系统都有自己的自动伸缩硬件和软件。

Performance Running in Snowflake

上图显示了这些层,包括:

云服务层接受连接,Snowflake 查询优化器对其进行调优,可能会重写代码以提高 SQL 查询性能。术语“本地存储”指的是比磁盘存储快得多的虚拟仓库存储。云存储层在 blob 存储中实际存储数据。通常存储在硬盘上的云存储在 Snowflake 中被称为远程存储。

缓存 Snowflake。

Snowflake 通过在虚拟仓库和云服务层中缓存结果来提高查询性能。

下图显示了 Snowflake 如何存储数据。Snowflake 在以下层中缓存数据:

云服务:它包含元数据和结果缓存。元数据缓存存储行数以及不同值和空值,而结果缓存存储过去 24 小时内进行的所有查询的结果。

虚拟仓库:使用最近最少使用 (LRU) 技术将原始数据缓存到快速 SSD 上。Snowflake 可以使用 Snowflake 数据缓存运行本地存储的数据搜索,绕过较慢的远程存储访问。

通常,通过元数据或结果缓存执行的 SQL 查询会在几毫秒内返回,并且不需要虚拟仓库(它们基本上是免费的)。当查询针对数据缓存执行时,查询性能最多可提高十六倍。但是,每个仓库都有一个 AUTO_SUSPEND 时间,通常约为 60 秒。

Performance Running in Snowflake

在预定的时间量之后,仓库会挂起,清除数据缓存。这会导致查询时间略有增加,因为后续查询必须从较慢的磁盘而不是本地 SSD 读取数据。

将 AUTO_SUSPEND 时间限制为 60 秒而不是通常的 10 分钟是很好的做法,因为这样做可以防止您为未执行查询的时间付费。但是,通过增加用于最终用户查询的商店的 AUTO_SUSPEND 时间,可以提高整体查询性能。

优化结果缓存的使用。

如前所述,每次查询的结果都会在结果缓存中存储 24 小时,并快速(通常在几毫秒内)返回,这通常是最大化查询性能的一种易于访问且直接的选项。

但是,结果缓存只能返回不包含非确定性函数的查询的结果。这意味着如果查询被重新执行,结果必须是相同的,并且它不能包含 CURRENT_TIMESTAMP() 等函数。如果底层数据保持不变,连续的仪表板查询会在几毫秒内返回(查询是针对 Snowflake Clone 运行的)。

Performance Running in Snowflake

RESULT_SCAN 表函数允许您直接从结果缓存查询结果。例如,以下查询存储 QUERY_ID,用于在 RESULT_SCAN 查询之前列出仓库。

了解 Snowflake 如何存储数据以及如何在每个节点上运行对于 Snowflake 查询调优至关重要。Snowflake 将数据存储在称为微分区的大(16MB)单元中。加载数据时,元数据缓存会存储每个微分区的物理位置,然后该位置会保存在远程磁盘存储中。

Performance Running in Snowflake

下图说明了 Snowflake 查询优化器如何使用元数据来跟踪每个微分区的。当执行 SQL 查询时,Snowflake 查询优化器会分析元数据以确定需要加载哪些微分区来满足查询。

这意味着 Snowflake 可以自动删除微分区,从而在不需要任何数据工程工作的情况下提高查询性能。

这是一个细微但重要的区别;换句话说,增加虚拟仓库的大小会添加硬件节点,而不是升级硬件。这意味着增加仓库大小仅对处理和生成大量数据的长时间运行的复杂查询有帮助。

Performance Running in Snowflake

使用 Snowflake LIMIT 或 TOP 子句。

提高 SELECT 查询效率最简单但最有效的方法是使用 TOP 或 LIMIT 子句。为了理解表的内容,您通常需要查看前几行,这促使您使用 SELECT * FROM TABLE 语句。

下图区分了行存储(左),最适合 OLTP 系统,以及列存储(右),它提供了显著的压缩优势和更快的 I/O。

根据 Mike Stonebraker 教授的说法,列式数据库在分析查询方面比行式数据库快 100 倍,因为它们只读取所需的列值。

例如,如果以下查询在一个包含 100 列的表上运行,它将仅从磁盘存储中返回 2% 的列。然而,这导致了 Snowflake 的另一项性能最佳实践:避免 SELECT * from tables,只提取您需要的列。

虽然这对于在线查询来说不是问题,但我们需要避免在生产系统中这样做,因为它具有两个关键优势:

  • 它减少了从远程存储传输到内存的数据量。
  • 最大限度地利用虚拟仓库缓存。
  • 这两种好处都有助于提高整体查询性能。

这表明,仅使用一个 SQL 语句,逐行处理的吞吐量可以提高约一百万倍。

简而言之,要避免 Snowflake 的逐行处理。这将降低查询性能。

简化转换查询。

在从 Teradata 迁移到 Snowflake 时注意到的一种常见设计模式是使用单个 SQL 语句生成完整的 ELT 管道,这使得优化 Snowflake 查询优化器变得困难。

Performance Running in Snowflake

这种方法变得麻烦,因为最重要的 Snowflake 优化策略之一依赖于 Snowflake 估计每个 JOIN 事务的基数的能力。对于低级 JOIN 来说,这不是一个问题,因为 Snowflake 可以直接访问表统计信息。但是,当数据在多个级别上进行汇总和聚合时,这会变得越来越困难。

在这种情况下,识别大型表变得越来越困难,这可能导致次优的查询计划,其中 Snowflake 将 千兆字节 的数据读入内存,同时扫描只有几 兆字节 磁盘空间的数据库。与其将语句作为单个查询运行,不如将问题分解为多个查询,将结果发送到临时表。最后,批处理转换活动可以对性能产生重大影响,因为整个任务的各个部分可以并发完成。

Performance Running in Snowflake

避免 Snowflake 溢出到存储。

下图描绘了一个 X-Small 虚拟仓库的内部结构,包括 CPU、RAM 和本地存储(SSD)。Snowflake 始终尝试在内存中执行排序操作,以提高查询效率。但是,如果排序过大,中间结果将需要移至较慢的本地存储,甚至可能移至更慢的远程存储。

由于内存比 SSD 快,而 SSD 比远程磁盘快得多,因此存储溢出会影响查询性能。这会阻止虚拟仓库挂起并影响查询性能,从而因查询运行时间更长而增加成本。

Performance Running in Snowflake

防止溢出的最有效方法是将任务转移到巨大的虚拟仓库。缩减规模是减少泄漏的最佳方法,因为每个 T 恤尺寸都会将负载分配给多个节点,每个节点都有内存和 SSD。在极端情况下,增加仓库大小可能会降低总体成本。

最大化 Snowflake 分区修剪。

它会自动收集每个项目的元数据统计信息,包括每列的最小值和最大值。假设数据是在每个月底导入的,下图描绘了一种可能的数据架构。

Snowflake 使用元数据自动修剪分区。例如,如果执行以下查询,优化器会将搜索限制在微分区 2 和 3,而忽略所有其他微分区。这种 Snowflake 数据聚类技术可以大大提高在具有数百万个微分区的超大表上的查询性能,特别是如果聚类与聚类键保持最新。

最好在交付区域实现聚类键,因为频繁的更改倾向于干扰聚类,导致在表由自动聚类服务重新排序时消耗更多信用。

优化 WHERE 子句。

分区修剪依赖 WHERE 子句来过滤数据,但一些小的错误可能会意外地减少分区修剪,导致执行时间延长。

Performance Running in Snowflake

同样,WHERE 子句中的列包装会大大降低分区消除,这会减慢查询速度。出于相同的原因,数据应始终以其本机数据类型存储。

为了最大化分区移除,例如,如果数据是基于文本但包含数字或日期值,您必须选择 NUMBER 或 DATE 等列。这还极大地提高了数据压缩,从而减少了磁盘 I/O 并提高了查询性能。

结论

总之,我们可以得出结论,实施建议的实践并注意工作负载模式将使您能够在 Snowflake 中保持良好的性能。这不仅可以加快查询执行速度并提高用户满意度,还可以优化资源利用率,使您的数据运营在未来更具成本效益和可扩展性。


下一主题