2017-10-24 7 views
0

私は2つのテーブルを持っています。最初は "main"と呼ばれ、 "lookup"と呼ばれる別のテーブルに1対1で対応する6つのカラム(a〜f)があります。次のように私のクエリは次のとおりです。複数の結合クエリで赤いシフトディスクがいっぱい

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ノードの赤方偏移のクラスタ上で、これを実行しています。クラスタ全体で、私は約60%のディスク容量を使用しています。つまり、240GBを超えるメモリと1.02 TBのディスクスペースを使用できません(これは、Redshiftの内部使用のために予約されているため、 。

これらの結合はそれぞれ1対1であるため、クエリの結果はmainのサイズを超えないようにする必要があります。 mainが4,496行の場合、クエリは約15秒で実行され、ディスク容量はほとんどまたはまったく使用されません。ただし、7,304行(主に離散的に増加)で、ディスクの完全なエラーで約5分後にクエリが失敗します。

CloudWatchは、エラーがノードの1つが記憶容量に達していることを原因としていることを示しています。クエリ全体を通じてストレージが均等にノードに成長することはなく、最初のノードが100%に達したときにクエリが正確に失敗するため、クエリがクラスタ内のすべての使用可能なディスク領域を消費しているかのようになりません。それでも、容量の近くにはいけません。誰もこの行動を見たことがありますか?なぜ私のクエリはこのように爆発するのですか?

データベースはほぼ新鮮なテーブルで作られているので、断片はありません。私はパフォーマンスの最適化のために私のテーブルをリファクタリングすることはできませんので、私はテーブルのリファクタリングができません(私はクエリで6つの結合を持つことはおそらく貧弱な設計の指標であると認識しています)私はRedshiftがそんなに多くのストレージを吸収する理由を理解しようとしています。

編集: mainとlookupは両方とも派生テーブルであり、それぞれがCTEで定義されています。 a-fにはいくつかの異なるオプションがあります。 Mainは最初にa-f(クロスジョイン)のすべての異なる組み合わせを計算し、次にそれを別のデータセットと結合することによって生成されます。この他のデータセット(92行)は、別のテーブル(196,154,352行、このbase1と呼ぶ)のフィルタリングされた集約バージョンでもあるCTEです。 a-fの組み合わせごとに、メインに約30の異なる行が存在します(これは、メインのサイズが離散的に増加する理由で、a-fにいくつのオプションがあるかによって異なります)。この場合も、メインが約7,000行(a-fの場合は2.5オプション)であるときに、クエリーはディスクスペースの節約を開始します。 Lookupは別のテーブルのフィルタリングされ集められたバージョンです。これをbase2と呼びます(172,867行から1,241行まで)。

したがって、このクエリではbase1とbase2のみが実テーブルです。 Mainはa-fのクロス結合から導かれ、base1から派生した別のCTEと結合され、ルックアップはbase2から直接導出されます。上記のクエリの更新を参照してください。

+0

クエリの中間ステップは、テーブルだけを見るだけで明らかなものよりも多くの領域を占めています。これは私の推測です。 –

+0

ええ、それは私の考えでした。私は1つの結合、2つの結合、3つの結合などでクエリを試しました、そして、それは私にすべてのためのメインのサイズよりも小さい結果を与えました。明示的なネストされたクエリに分割しても、同じエラーが発生しました。 Redshift/Postgresが「フードの下で」操作に参加することについて私はよく分かりませんが、何かが正しいように見えません。 –

+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 
; 
+0

@ joshua-dotsonこれを試しましたか?それはあなたのために働いたのですか?私が思うには、たとえこれが機能していても、あなたのジョイン/データで何かが残っています。 –

+0

残念ながら、これは問題を解決しませんでした。私は、mainとlookupが実際には両方ともCTEで定義された両方の派生テーブルであることに言及する必要があります。それが関連している場合に備えて、元の質問にその情報を追加します。 –

+0

はい、 "メイン"と "ルックアップ"を生成するためにCTEが使用されていることは大変重要です。 Redshiftでは、CTEは「ビュー」と同じように少し使用されます(計算され、使用されるように一時テーブルとして保存されるポストグラムとは異なります)。これらの最初のCTEの情報と、ソーステーブルのサイズと定義を含めるように質問を更新する必要があります。 –

関連する問題