Sql 多连接查询时红移磁盘已满

Sql 多连接查询时红移磁盘已满,sql,query-optimization,amazon-redshift,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*) se

我有两张桌子。第一个我们称之为“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.1大型节点组成的红移集群上运行这个。在整个集群中,我的磁盘空间利用率约为60%,这意味着我的可用内存不应超过240 GB,可用磁盘空间不应超过1.02 TB(这是一个很高的估计值,因为其中一些空间是保留给红移内部使用的)

正如我提到的,每个连接都是一对一的,因此查询的结果不应该大于main的大小。当main为4496行时,查询将在约15秒内执行,并且几乎不使用磁盘空间。但是,在7304行(main以离散增量增长)时,查询在磁盘已满错误发生大约5分钟后失败

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

数据库几乎完全由新表组成,因此没有任何片段。我对数据库的设计也没有太多的控制权,因此无法重构表以优化性能(我意识到在一个查询中有六个连接可能表明设计不佳)。我只是想弄明白为什么红移会占用这么多存储空间

编辑: main和lookup都是派生表,每个表都在CTE中定义。a-f有几种不同的选择。Main是通过首先计算a-f(交叉连接)的每个不同组合,然后将其与另一组数据连接而生成的。另一组数据(92行)也是一个CTE,它是另一个表(196154352行,称为base1)的过滤和聚合版本。对于a-f的每个组合,main中将有大约30个不同的行(这就是main的大小离散增加的原因,这取决于a-f的选项数量)。同样,当main大约为7000行时,查询开始占用磁盘空间(a-f的平均选项为2.5)。Lookup只是另一个表的过滤和聚合版本,我将其称为base2(从172867行降至1241行)


因此,base1和base2是此查询中唯一的实际表。Main派生自a-f的交叉连接,该交叉连接与派生自base1的另一个CTE连接,而lookup直接派生自base2。请参阅上面的查询更新。

请您尝试一下,一旦我遇到类似问题,像这样进行拆分就可以解决它

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
;

请你尝试一下,一旦我有一个类似的问题,像这样分裂修复它

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
;


查询的中间步骤占用的空间比仅查看表所占用的空间要大。这是我的猜测。是的,这也是我的想法。我尝试了一个连接、两个连接、三个连接等查询,结果都小于main的大小。我还将其分解为显式嵌套查询,但仍然遇到相同的错误。我对红移/Postgres的“引擎盖下”连接操作了解不多,但似乎有些不对劲。连接列上有索引吗?除了可能加快查询速度外,它还可能降低空间复杂性。@TimBiegeleisen:Redshift不支持索引:计时、集群大小和表大小感觉根本不对!我在1 x dc2上运行这种类型的更大版本。顺便说一句,您可能应该升级到dc2。查询的中间步骤占用的空间比仅查看表明显多。这是我的猜测。是的,这也是我的想法。我尝试了一个连接、两个连接、三个连接等查询,结果都小于main的大小。我还将其分解为显式嵌套查询,但仍然遇到相同的错误。我对红移/Postgres的“引擎盖下”连接操作了解不多,但似乎有些不对劲。连接列上有索引吗?除了可能加快查询速度外,它还可能降低空间复杂性。@TimBiegeleisen:Redshift不支持索引:计时、集群大小和表大小感觉根本不对!我在1 x dc2.large上运行了这种类型的更大版本。顺便说一句,你应该升级到dc2。@joshua dotson你试过这个了吗?它对你有用吗?我认为您的连接/数据仍然有问题-即使这样做有效。不幸的是,这并没有解决问题。我应该提到,main和lookup实际上都是派生表,每个表都在一个CTE中定义。我将把这些信息添加到原始问题中,以防万一。是的,CTE用于生成“main”和“lookup”非常重要。在红移中,CTE的使用有点像“视图”(不同于Postgre,它们在使用时被计算并存储为临时表)。您需要更新您的问题,以包括关于这些初始CTE是什么的信息,以及源表的大小和定义。我不知道它们在红移中被视为视图,这非常有用。我在问题中添加了一些信息。你认为这可能是问题所在吗?@joshua dotson你试过这个吗-对你有用吗?我认为您的连接/数据仍然有问题-即使这样做有效。不幸的是,这并没有解决问题。我应该提到,main和lookup实际上都是派生表,每个表都在一个CTE中定义。我将把这些信息添加到原始问题中,以防万一。是的,CTE用于生成“main”和“lookup”非常重要。红移,CTE