具有高基数的雪花性能调优列

Posted

技术标签:

【中文标题】具有高基数的雪花性能调优列【英文标题】:Snowflake performance tuning columns with high cardinality 【发布时间】:2021-09-19 18:25:31 【问题描述】:

我们如何在雪花中更快地进行如下查询。

SELECT ColumnA, ColumnB, ColumnC 
FROM TableA 
WHERE ColumnA = 'ABC123'

SELECT ColumnA, ColumnB, ColumnC 
FROM TableA 
WHERE ColumnA IN ('ABC123', 'ABC456', 'ABCnnn')

表 A 有 5 亿行、200 列、30GB 压缩大小,A 列有 3 亿个唯一值。

ColumnA 不能用作集群键,因为该表已被其他必要的列集群。此外,表格的搜索优化已经开启。

在 IN 子句中具有 15K 值的典型查询使用 XL 仓库在 30 秒内返回结果,而在这些列上编制索引的旧数据存储在 1 秒内返回结果。

【问题讨论】:

IN 子句中的 15k 值实际上可能会为您创建较长的编译时间,而不是执行时间。编译与执行需要多少时间? 【参考方案1】:

哇,作为字符串的连接键不利于性能。 但是具有 15K 值的 IN 子句更糟。 200 列并不是理想的以太。

我怀疑情况并非如此,但如果需要加速的查询只有三列,我会用这三列创建第二个表,然后在更新插入时执行多表更新/插入让它们保持同步。

在 IN 子句中使用 15K 值,您正在执行全表扫描,因此您的时间将完全受 IO 限制,并且您应该会发现每个实例获得大约 40MBps 的数据,从而更快地读取它(这是数字我记得我们曾经注意到我们的大型 IO 绑定任务),需要更大的实例。但这会让您的成本保持不变。

为了避免全表扫描,您需要让 Snowflake 帮助您避免一些数据(如果您选择 3/200 列,那就是一些减少)。因此,这是通过对您的键进行聚类或通过其他一些标准(如插入时间)来限制数据来完成的。或其他一些可以删除行的过滤器。

如果您没有可以预先过滤该数据的任何内容,那么您就处于全表扫描的快乐之地。

【讨论】:

您也可以为此创建一个 MV,而不是创建一个单独的表。这将使其保持同步而无需任何工作,并且您可以继续引用基表并允许自动查询重写功能为您完成工作(选择 MV)。 同意,物化视图可以达到同样的效果。以两个级别的成本,一个是物化如何发生“自动魔术”,因此就像所有魔术一样,可能无法与您的数据和读/写模式的现实保持一致。但它肯定是更简单的起点。我想我倾向于更深入地了解您的完整数据流,从而以允许您需要的使用方式编写数据。 MV 是一个帮助解决这个问题的工具。 @MikeWalton 嗯,自动 SQL 重写是我不知道的新优势。听起来确实不错。 这是相当新的,而且 IMO 有点埋没在文档中。它并不总是像您期望的那样工作,但在这种情况下(200 列中的 3 列),即使在查询基表时它也肯定会工作。 另外,请注意,您还可以将 MV 聚集在 ColumnA 上(或者最好是它的子字符串),这也可以改进 MV 的修剪。这可能会在基表和 MV 之间的集群服务中造成一些混乱,但可能是值得的。【参考方案2】:

Snowflake 使用微分区作为其混合分区技术;您在此处描述的可能更多是数据架构/建模限制。

当然,正如其他人所评论的那样,IN 子句中的 15k 搜索键是一个坏主意 --- 如果您在内部认为它需要将 15,000 个搜索值解析到静态修剪步骤,这将导致编译时间过长.我们经常建议不要这样做,也许更好的解决方案是将这 15,000 个值包含在单独的表中,并将其包含在 INNER JOIN 中。这是动态修剪,需要找到这么多匹配项。

Snowflake 是 Deep Right Join Tree 优化的,这意味着如果上述内容是 Star-Join 查询的一部分,那么性能甚至可能会更快!

【讨论】:

【参考方案3】:

假设您使用的是企业版或更高版本,您可以尝试 Search Optimization

【讨论】:

看起来 OP 已经声明他们开启了搜索优化。

以上是关于具有高基数的雪花性能调优列的主要内容,如果未能解决你的问题,请参考以下文章

Spark&Spark性能调优实战

apache高负载性能调优

性能测试-性能调优之一

高并发编程系列:JVM性能调优的6大步骤,及关键调优参数详解

MySQL管理之道:性能调优高可用与监控 PDF扫描版[61MB] 完整版下载

浅谈高并发系统性能调优