多个加入查询中的Redshift Disk Full

时间:2017-10-24 02:02:15

标签: sql query-optimization amazon-redshift

我有两张桌子。第一个我们称之为“main”,它包括六列(a-f),它们在另一个名为“lookup”的表中一对一映射。我的查询如下:

with
a_options as (*a options*),
...,
f_options as (*f options*),
other as (*query on base1*),
main as (select ... from a_options,..., f_options, other),
lookup as (*query on base2*)
select *,
  a_lookup.value,
  b_lookup.value,
  c_lookup.value,
  d_lookup.value,
  e_lookup.value,
  f_lookup.value
from main
inner join lookup as a_lookup on a = a_lookup.key
inner join lookup as b_lookup on b = b_lookup.key
inner join lookup as c_lookup on c = c_lookup.key
inner join lookup as d_lookup on d = d_lookup.key
inner join lookup as e_lookup on e = e_lookup.key
inner join lookup as f_lookup on f = f_lookup.key

我在16个dc1.large节点的Redshift集群上运行它。在整个集群中,我的磁盘空间利用率约为60%,这意味着我应该拥有不超过240 GB的内存和1.02 TB可用磁盘空间(这是一个很高的估计值,因为其中一些是为Redshift内部使用而保留的)

正如我所提到的,这些连接中的每一个都是一对一的,因此查询的结果应该不大于main的大小。当main为4,496行时,查询在~15秒内执行,并且使用很少甚至没有磁盘空间。但是,在7,304行(主要以离散增量增长)时,查询在磁盘完全错误大约5分钟后失败。

CloudWatch显示该错误是由其中一个节点达到存储容量引起的。在整个查询过程中,存储在节点之间不会均匀增长,并且当第一个节点达到100%时查询会失败,因此查询不会消耗群集中的所有可用磁盘空间。不过,它不应该接近容量。有没有人见过这种行为?为什么我的查询会像这样爆炸?

数据库几乎全部由新表组成,因此没有任何碎片。我也没有对数据库设计进行全面控制,因此我无法重构我的表以优化性能(我发现查询中有六个连接可能表示设计不佳)。我只是想了解为什么Redshift会吸收如此多的存储空间。

编辑: main和lookup都是派生表,每个都在CTE中定义。 a-f有几种不同的选择。 Main是通过首先计算a-f(交叉连接)的每个不同组合然后将其与另一组数据连接而生成的。另一组数据(92行)也是CTE,它是另一个表的过滤和聚合版本(196,154,352行,称为base1)。对于a-f的每个组合,main中将有大约30个不同的行(这就是为什么主要增加大小的离散,这取决于你对a-f有多少选项)。同样,当main处于大约7,000行(a-f的平均2.5选项)时,查询开始吸收磁盘空间。查找只是另一个表的过滤和聚合版本,我将其称为base2(从172,867行减少到1,241行)。

因此base1和base2是此查询中唯一真正的表。 Main来自a-f与从base1派生的另一个CTE连接的交叉连接,而lookup直接从base2派生。查看上面查询的更新。

1 个答案:

答案 0 :(得分:0)

一旦我遇到类似的问题并且像这样分裂修复它,请你试试。

with part1 as 
(
select *,
a_lookup.value,
b_lookup.value,
c_lookup.value
from main
inner join lookup as a_lookup on main.a = a_lookup.key
inner join lookup as b_lookup on main.b = b_lookup.key
inner join lookup as c_lookup on main.c = c_lookup.key
)
select p1.*,
  d_lookup.value,
  e_lookup.value,
  f_lookup.value
from part1 as p1
inner join lookup as d_lookup on p1.d = d_lookup.key
inner join lookup as e_lookup on p1.e = e_lookup.key
inner join lookup as f_lookup on p1.f = f_lookup.key
;