Redshift 不使用交错排序键执行合并连接

Posted

技术标签:

【中文标题】Redshift 不使用交错排序键执行合并连接【英文标题】:Redshift not performing merge joins with interleaved sort keys 【发布时间】:2017-02-15 16:58:48 【问题描述】:

我正在查看我在 Redshift 中执行的一些查询的性能,并注意到我在文档中找不到的一些内容。

我创建了两个表,它们之间有一个连接键(子表中大约有 10K 行)。

对于父表,我们称它为 A,我有一个主键,我已声明它是表的 distkey 和排序键。我们称它为 id。

对于子表 B,我创建了一个外键字段 parent_id,它引用了 A.id。 parent_id 已被声明为表 B 的 distkey。表 B 也有一个主键,即我定义的 id。我在表 B 上为 (parent_id,id) 创建了一个交错排序键。

当我尝试解释连接两个表时,我总是会得到一个哈希连接。如果我用普通的复合排序键重新创建表 B,我总是会得到一个合并连接。

当我查看表格的统计数据时,我没有看到任何不符合规定的偏差。

我的问题是,Redshift 是否总是使用带有交错排序键的哈希连接,还是我做错了什么?

EDIT - 表 B 中交错排序键的顺序实际上是 (parent_id, id)。我上面写错了。我已经更新了上面的内容。

【问题讨论】:

我怀疑您的交错密钥的顺序导致了问题。试着把parent_id放在第一位。 感谢您的回复。实际上,我首先使用 parent_id 声明了表 B——我只是没有在上面写。由于合并连接仍然没有发生,因此我进行了编辑以澄清。 嗯,那肯定是INTERLEAVED 的问题。我过去每次尝试时都会遇到问题(查看 Redshift 论坛),所以我一直远离它,除非我真的需要它。 我之前尝试过使用交错排序,它确实应该有所帮助,但性能比标准复合排序慢一个数量级。这个理论很好,但我认为目前还没有准备好迎接黄金时段。 【参考方案1】:

据我了解:

合并连接可以在两个表都在连接列上排序时使用,这非常有效 - 有点像拉上拉链,两边“适合”彼此。 散列连接效率较低,因为它需要通过散列查找匹配值。

正如您所指出的,如果使用普通复合键对表进行排序,则两个表都按连接列排序。

然而,在交错连接中,值不保证在每一列中排序

Interleaved Keys 的文档说:

交错排序对排序键中的每一列或列的子集赋予相同的权重。如果多个查询使用不同的列作为过滤器,那么您通常可以通过使用交错排序样式来提高这些查询的性能。当查询对二级排序列使用限制性谓词时,与复合排序相比,交错排序显着提高了查询性能。

但是,它意味着所有列都已排序(就像它们使用复合排序一样)。相反,它提供了一般良好的排序组合,因此任何列上的排序通常都能正常工作。因此,每一列不一定是完全排序的,因此需要散列连接

博文Quickly Filter Data in Amazon Redshift Using Interleaved Sorting 试图解释使用交错排序时如何存储数据。

【讨论】:

这似乎暗示着使用交错排序意味着你放弃了合并连接,或者你减少了查询规划器可以使用这种类型的连接的发生率。 是的,但是您可以通过跨多个列的总体良好的区域映射(允许 Redshift 避免从如此多的磁盘块读取数据)来获得收益。如果您经常在多个不同的列上单独使用 WHERE 子句,请仅使用 Interleaved。

以上是关于Redshift 不使用交错排序键执行合并连接的主要内容,如果未能解决你的问题,请参考以下文章

对定义为排序键的列进行 Redshift 顺序扫描

连接的 Redshift 排序键

即使使用 where 子句中使用的排序键,Redshift 也会执行全表扫描

Redshift Dist 键、IDentity 列或连接列?列的基数,用于排序键的联接考虑

在 Redshift 中使用连接的最佳方式

Kotlin:合并多个列表然后排序交错合并列表