2017-02-17 23 views
1

私は短い質問があります。シンプルなCTEはどのように機能しますか?

with test_cte as(
select * 
from table1 
where conditions1 
) 
select * 
from table2 
inner join test_cte 
on conditions2 
where conditions3 

私は右のクエリは最初conditions1に基づいて行をフィルタリングするtest_cteを通過すると仮定することは、どこかにデータを格納し、TABLE2し接合する際、再び後test_cteから残りの行を通過するだろうか?データはどこに格納されますか? RAM?またはこれは

select * 
from table2 
inner join table1 
on conditions2 
where conditions3 and conditions1 

と同等ですが、大きなクエリで読みやすくなりますか?

+0

「テーブル」を1回使用するとすぐに消える一時テーブルと考えてください。 – Snowlockk

+0

@Snowlockk - あなたはどこでそれを考え出しましたか? CTEは、テンポラリ・テーブルまたはインライン・ビュー(サブクエリ)のいずれかとして使用でき、オプティマイザはどちらを選択するかを決定します。 ** CTEは一度**使用されるとすぐに消えません。 – mathguy

+0

しばらくしてからもう一度電話をかけてください。 – Snowlockk

答えて

2

あなたのCTEは、(Oracleはインライン表示を呼び出します)派生表のちょうど構文バリエーションです:

select * 
from table2 
inner join 
(
    select * 
    from table1 
    where conditions1 
) AS test_cte 
on conditions2 
where conditions3 

まともoptmizerが常にいる場合にのみ(最初のCTE/DTの結果を作成しませんそれは複雑すぎるので)、あなたのケースでは計画は2番目のクエリと似ているはずです。両方のクエリの計画を比較するだけです。

あなたが気づいたように、CTE/DTは主に、より複雑なクエリをより小さなロジックグループに分割して簡単に書くために使用されます。また、上位レベルの集計ウィンドウ集約。 "それは、データを保存しますか?RAMの?"

+1

実際、複雑なクエリの単純化はCTEの主な使用例ではないと思います。少なくともOracleではそうではありません。 – APC

2

依存します。オプティマイザはサブクエリのコストを評価します。コストが十分に高い場合(複雑さやサイズのために)、Oracleはグローバル一時表としてマテリアライズし、ディスクに書き出します。そうすることで明確なメリットがある場合に限り、CTEを使用してください。

メリットの1つは、メインクエリでCTEの結果を複数回再利用できることです。だからあなたの例を拡張:

with test_cte as(
    select * 
    from table1 
    where conditions1 
) 
select * 
from table2 
inner join test_cte 
    on conditions2 
where table1.whatever not in (select whatever 
           from test_cte 
           where conditions3) 

ここでは、一度table1を照会しているが、2倍のレコードを使用。

with test_cte as(
    select * 
    from table1 
    where conditions1 
) 
, next_cte as (
    select t1.* 
      , t23.* 
    from test_cte t1 
     join table23 t23 
     on t1.id = t23.id) 
select * 
from next_cte 

これはチャンクを理解することが容易に複雑なクエリを壊すのに有用であることができます。

のCTEのもう一つの利点は、我々は彼らをチェーンことができるということです。ただし、このルートに着手する前にオプティマイザよりも明確になっていることを確認することは重要です。

WITH句のもう1つの用途は、再帰的なクエリの作成です。 11gR2以降、Oracleの階層問合せ構文を使用せずに親子関係をナビゲートできるようになりました。 Find out more

with cte (id, parent_id, lvl) as 
    (select id, p_id, 0 as lvl 
     from t23 
     where p_id is null 
     union all 
     select t23.id, t23.p_id, cte.lvl + 1 
     from cte 
      join t23 
      on cte.id = t23.p_id) 
select * 
from cte 
order by lvl, id 
/
+0

CTEの結果セットのサイズが、CTEがマテリアライズされているかどうかを判断する要因ではないと私は信じています – BobC

+0

@BobC - だから何を信じますか?サイズが唯一の要因ではないので、私はその文章を書き直しました。オプティマイザはサブクエリのコストを評価し、実行時にそのサブクエリを実現するかどうかを決定します。私は、結果セットのサイズがクエリのコストに寄与していると信じていますが、オプティマイザがどのルールを適用するかについての明確な説明は見ていません。あなたがリンクを持っているなら、私はもっと学ぶことに興味があるので、投稿してください。 – APC

+0

CTE変換はコストベースではありません。したがって、基本的に、CTEを複数回参照する(またはMATERIALIZEヒントを使用する)と、それが具体化されます。 – BobC

関連する問題