5

我慢してください、私は中級者に不慣れです。

私の質問は-いつCTEを使うべきですか?CTEを使用するかどうかをどのように決定しますか?

これはいつ使用する必要がありますか:

;with cteTesting as
(
    select  *
    from    testing.first_table
)
select  *
from    testing.second_table s
        inner join cteTesting t
            on s.key = t.key

これについて:

select  *
from    testing.second_table s
        inner join
        (
            select  *
            from    testing.first_table
        ) t
        on s.key = t.key

なぜ?これはコードフロー、コードの可読性のためだけですか?それとももっと技術的なものがありますか?状況によっては、より良い実行計画が得られるでしょうか?

編集:私のサンプルコード例は非常に貧弱であることに気づきました。CTEの代わりにfromステートメントでselectを使用できる場合が多いことを強調しようとしていましたが、どちらを使用するかをどのように決定すればよいですか?

4

4 に答える 4

5

簡単な例では、それほど違いはありません。再帰機能を使用して階層を構築する必要がある場合は、選択肢があまりありません。CTEを使用する必要があります。

おそらくパフォーマンスに大きな違いはないが、読みやすさには影響するもう1つのケースは、同じサブクエリに複数回参加する必要がある場合です。サブクエリを使用している場合は、式全体を繰り返す必要がありますが、CTEの場合は、名前を2回使用するだけです。

;With NamedExpression as (
    select t1.ID,t2.ID as ID2,SUM(t3.Value) as Val
    from
      Table1 t1
        left join
      Table2 t2 on t1.id = t2.t1id
         inner join
      Table3 t3 on t3.col = t1.id or t3.col2 = t2.id
    group by
      t1.ID,t2.ID
)
select
    *
from
    NamedExpression ne
        inner join
    NamedExpression ne2
        on
            ne.ID2 = ne2.ID

上記をサブクエリとして実行し、式が特に複雑な場合、リーダー/メンテナが2つのサブクエリが実際に同一であることを確認するのに時間がかかる場合があり、 2


また、サブクエリを囲んでいるクエリよりも右側に表示する必要があるというインデントスタイルがある場合、他の式に基づいて作成された式を使用すると、すべてのコードが右にシフトする可能性があります。CTEの場合は、停止して移動します。各部分式(CTE)を作成する際に左に戻る:

;WITH CTE1 AS (
    SELECT
    ...
), CTE2 as (
    SELECT
    ...
    FROM CTE1
), CTE3 as (
    SELECT
    ...
    FROM CTE2
)
select * from CTE3

vs:

select *
from
   (
        select ...
        from
             (
                 select ...
                 from
                     (
                          select ...
于 2012-07-12T07:18:54.777 に答える
4

私は個人的に、特に選択が大きくなると、CTEバージョンの方が読みやすくなると思います。

メインのSELECTで派生テーブルを複数回使用する場合は、CTEを使用する方がよい場合があります。これは、これを1回だけ実行することをデータベースに通知するためです。オプティマイザーがfrom句で2つの同一のサブ選択を検出し、それらを1回だけ実行するほど賢い場合でも、私は驚かないでしょう。

with foo as (
   select ..
   from bar
)
select f1.*
from foo f1 
  join foo f2 on ...

対。

select f1.*
from (select ... from bar ) f1
  join (select ... from bar) f2 on ...

最も重要な部分は、一貫性を保つことだと思います(あなたが書いたもの全体とチーム内で)。

于 2012-07-12T07:17:28.277 に答える
3

JOIN(特に多くのWHERE句と組み合わせると)は、大規模なデータセットが含まれる場合に壊滅的なパフォーマンスをもたらす可能性があることに気付きました。

CTEは、関連するレコードのみを選択し、これらのサブセットを結合することで、これを解決できます。

CTEを、最終的なSELECT用のデータを準備するための一種の事前選択と見なします。

于 2012-07-12T07:41:17.717 に答える
2

CTEを使用するもう1つの理由は、派生テーブルを置き換えることではなく、複雑なレポートSQLに正しいレコードが含まれていることを確認することです。したがって、ある種の財務報告を行っていて、必要なレコードを正確に返すようにしたいとします。結合が10個あると、データが正しいかどうかを判断するのが難しくなります。

そこで、CTEを使用して複雑なクエリを分割して作成します。したがって、たとえば、特定の条件を満たす注文のみが必要です。最初のCTEは、それらを選択するCTEです。私はそれを書き、CTEでselectを実行します。これにより、基本注文数がわかります。複雑さを増すと、番号がどこで変更されたかをすぐに確認して、変更する必要があるかどうか、またはクエリを変更する必要があるかどうかを判断できます。これにより、左結合または内部結合が必要かどうか、または関連するテーブルの条件を1つのレコードに制限する必要があるかどうかをかなり迅速に知ることができます。

多くの場合、これを行うと、最終的な選択に到達する前にCTESをチェーン化することになります。これははるかに簡単です。そして、これのさらなる価値は、これらの複雑なレポートクエリを変更するときにそれらを維持することがはるかに簡単であることに気付くということです。したがって、次のようなチェーンにCTEがあるとします。

  • 注文
  • コストの概要
  • 顧客の人口統計

次に、コスト計算の方法について何かを変更する必要がある場合、変更を行う場所を見つけるのが簡単であり、最終結果を確認するのも簡単です。

于 2012-07-12T14:55:49.027 に答える