根据小表的结果修剪大表
Posted
技术标签:
【中文标题】根据小表的结果修剪大表【英文标题】:Pruning a large table based on the results from a smaller table 【发布时间】:2021-03-26 15:49:17 【问题描述】:我正在尝试了解是否可以减少在以下场景中扫描的分区数量。
我有两张桌子:
Table A (100M rows)
JOIN_KEY DATA_1 DATA_2 etc.
Table B (40K rows)
JOIN_KEY FILTER_COL_A FILTER_COL_B
当用户想要从表 A 中查询数据时,他们需要通过过滤 FILTER_COL_A
& FILTER_COL_B
从表 B 中获取对应的 JOIN_KEY
值。
当对FILTER_COL_A
和FILTER_COL_B
进行过滤时,它将为JOIN_KEY
生成数量非常少的值 - 通常只有 3 个,但可能更多。
表 A 由 JOIN_KEY
聚类。
当我在 JOIN_KEY 上编写连接两个表的查询,然后在 FILTER_COL_A
和 FILTER_COL_B
上进行过滤时,会扫描表 A 上的所有分区,而不是 800 个分区中的大约 5 个分区。
我不能在运行时直接过滤 JOIN_KEY,在从表 B 返回数据之前,我不知道这应该是什么值。
有没有一种方法可以构造查询,以便 Snowflake 在连接过滤器中使用表 B 的结果并修剪表 A 的大部分分区?
【问题讨论】:
如果可以的话,Snowflake 分区会在连接时进行修剪。不能这样做的一个原因是,如果数据不是由表上的连接键聚集在一起,尤其是较大的连接键。您是否在连接键上运行了 SYSTEM$CLUSTERING_INFORMATION?如果您在直方图底部看到结果,则可能需要运行自动集群服务才能从此连接的修剪中受益。 自动集群在较大的表上启用,并通过连接键进行集群。 SYSTEM$CLUSTERING_INFORMATION 不超过 00007,平均深度为 3.0878。较小的表没有定义集群键。 【参考方案1】:假设 INNER JOIN 并根据您执行过滤的位置,选项包括 a) 将过滤器放在 WHERE 子句中 或者 b)将它们放在 JOIN 子句中(不清楚这是否是您所说的您不能做的)。 或者 c)A.JOIN_KEY IN (SELECT JOIN_KEY FROM B WHERE ...)
我可以根据当前信息给出的最佳建议。
【讨论】:
在运行时,我们不知道表 A 中JOIN_KEY
的值应该是什么,因此它们不能在 JOIN 或 WHERE 子句中提供。表 B 本质上是一个查找表,它根据用户的请求返回所需的键【参考方案2】:
根据查看分区的元数据,在 SQL 编译时完成修剪。
鉴于您要连接两个表,只有表 B 的分区可以被修剪并且过滤子句是已知的。
因此,您需要将表 B 查询的结果写入临时表,然后加入临时表和表 A。
或
你的表A应该有FILTER_COL_A
,FILTER_COL_B
作为列,并且表被(FILTER_COL_A,FILTER_COL_B)
聚类,那么你可以直接查询这个表。
我建议您自己对此进行测试,方法是使用这些列创建一个新的表 A' 并对它进行测试以查看修剪效果。
【讨论】:
将FILTER_COL_A
和FILTER_COL_B
添加到表A 会显着增加行数,因为它是1:M 关系。该表将从 100M 变为 ~7B 并且维护它将是一个问题。如果可以的话,我想避免这样做。临时表是一种选择,但让它与 BI 工具 (Tableau) 一起工作可能是个问题。
@suchafunkymonkey 在一个层面上,返回约 3 行的过滤器可能对基表产生 70 倍的影响似乎很奇怪。再次,我建议尝试一下,看看它是否仍然表现更好。如果它的积极影响为零,那么您就知道了。一旦您知道我们可以让您阅读“更快”或“更便宜”,您就可以通过增加维护它的“成本”来锻炼。并选择最能接受的性价比。我们有许多具有 12+B 行的表,它们是基表的副本,但是为了获得修剪的优势而减少了列。因为我们进行了测试,并且成功了【参考方案3】:
发布此答案以防其他人对此提出异议。
在撰写本文时,它似乎仅在表 A 和表 B 上的 JOIN_KEY
列的数据类型为 number(38,0)
时才有效。
使用number (38,0)
时,Snowflake会根据FILTER_COL_A
和FILTER_COL_B
过滤后的表B结果对表A上的分区进行剪枝。
【讨论】:
以上是关于根据小表的结果修剪大表的主要内容,如果未能解决你的问题,请参考以下文章