4

したがって、私がWITH使用した方法と、MSDNのドキュメントに基づいています。

共通テーブル式(CTE)と呼ばれる、一時的な名前付き結果セットを指定します。

はテーブルWITHの代わりのようです。#TEMPあれは正しいですか?

4

3 に答える 3

14

いいえ。CTE(によって導入されたWITH)は一時テーブルを置き換えませんが、過去に一時テーブルを使用したことがある場合に使用できる場合もあります。

WITHは実際には派生テーブルにすぎませんが、インラインではなくクエリの前に導入され、クエリ全体でテーブルとして複数回使用できるエイリアスが与えられるという違いがあります。

派生テーブルは、括弧内の完全なクエリであり、実際のテーブルであるかのように使用されます。ビューとテーブル値関数も派生テーブルと見なされますが、インラインで定義される種類に焦点を当てています。次に例を示します。

SELECT
   C.Name,
   S.SalesTotal
FROM
   dbo.Customer C
   INNER JOIN (
      SELECT
         O.CustomerID,
         SalesTotal = Sum(OrderTotal)
      FROM
         dbo.CustomerOrder O
      GROUP BY
         O.CustomerID
   ) S
      ON C.CustomerID = S.CustomerID;

独自の行セット(GROUP BYクエリ)を返す完全に無傷のクエリがあります。これを括弧の中に入れてエイリアスを割り当てることでS、テーブルのように使用できるようになります。これにさらに多くのテーブルを結合することができます。ただし、このテーブルに参加したのは1回だけです。

これをCTEに変換するには、非常に簡単な変更を加えます。

WITH SalesTotals AS (
   SELECT
      O.CustomerID,
      SalesTotal = Sum(OrderTotal)
   FROM
      dbo.CustomerOrder O
   GROUP BY
      O.CustomerID
)
SELECT
   C.Name,
   S.SalesTotal
FROM
   dbo.Customer C
   INNER JOIN SalesTotals S
      ON C.CustomerID = S.CustomerID
   -- and for an example of using the CTE twice:
   INNER JOIN (
      SELECT Avg(SalesTotal)
      FROM SalesTotals
   ) A (AverageSalesTotal)
      ON S.SalesTotal >= A.AverageSalesTotal;

さて、臨時雇用者テーブルは完全に異なる動物です。CTEまたは派生テーブルとは非常に重要な違いがあります。

  • 一時テーブルは多くのクエリにわたって存続しますが(クライアント接続の存続期間中、または明示的にドロップされるまで)、CTEは1つのクエリに対してのみ「存在」します。
  • CTEは、論理的には「単一の」テーブルですが、クエリで複数回使用されると、データが複数回生成される可能性があります。一時テーブルのデータは、他の「実際の」テーブルと同じように読み取られます。上記の例では、Avg(SalesTotal)少なくとも2012年までのバージョンのSQL Serverでの計算には、SalesTotals集計を2回実行するという完全に別個の操作が含まれます。エンジンがCTEの結果を具体化することは可能ですが、これまでのところSQLServerはこれを実行していません。Oracleなどの他のDBMSがCTEの結果を具体化する可能性があることは注目に値します。いずれにせよ、この二重クエリは(もちろん!)パフォーマンスに深刻な影響を与える可能性があることに注意する必要があります。
  • 一時テーブルには自動的に生成された列統計があり、これはクエリオプティマイザがより適切な実行プランを選択するのに役立ちます。CTEの「最終」行セットには統計がありません。基礎となるテーブルの統計が使用されます。
  • 一時テーブルは、インクリメンタルに追加したり、複数または繰り返しのステートメントによって行を削除したりできます。更新できます。
  • 一時テーブルを変更して、列を追加または削除したり、データ型を変更したりできます。
  • 一時テーブルには、クラスター化インデックスと非クラスター化インデックスおよび制約を含めることができます。
  • ユーザー定義関数内で一時テーブルを使用することはできません。
  • CTEは、クエリの一部を論理的に分離しているように見えますが、そのようなことはしません。CTEは、述語のプッシュダウン、最終的な行セットに影響を与えないと判断された場合の削除(またはテーブルや結合の一部の削除)、または予期しない式の評価順序の対象となる可能性がある場合の削除の完全な候補です。たとえば、CTEではテキスト列から数値文字列のみを返し、外部クエリではこれらの文字列を数値データ型に変換しようとしますが、驚いたことに、数値以外の文字列を変換しようとするとエラーが発生します。数値データ型に。これは、オプティマイザーがクエリを自由に再編成でき、数値を含む文字列のフィルターの前に数値に変換できるためです。一時テーブル。2つのステートメントが必要です(1つはデータを挿入するためのもので、

最後に、CTEは、一時テーブルでは実行できないことを実行できます。再帰的である可能性があります。Oracleでは、これはによって表現されCONNECT BY、SQL ServerではUNION ALL SELECT、CTE自体のエイリアスを参照できるCTEの内部で実行されます。

CTEには注意してください。CTEは優れた抽象化ですが、それ以上のものではなく、深刻な問題に遭遇する可能性があります。一度に1行ずつ再帰CTEを使用して100万行を生成できますが、これは100倍以上の最悪の方法です。

SQL Server 2005以降には、「テーブル変数」と呼ばれる別の特別な種類の一時テーブルがあります。これは、いくつかの注目すべき例外を除いて、一時テーブルに非常によく似ています(tempdbにまったく同じに保持されます)。

  • 接続ではなく、バッチの期間のみ持続します。
  • ユーザー定義関数内でテーブル変数を使用できます。一部のタイプのUDFには1つ必要です。
  • インライン制約(主キーや一意性など)のみを宣言でき、行の更新/挿入/削除は可能ですが、宣言後にスキーマを変更することはできないため、列の追加/削除、データ型の変更、またはインデックスを追加します。
  • 統計は収集しません。
  • SQL Server 2008以降では、パラメーター(テーブル値パラメーター)として渡すことができます。
于 2013-02-12T17:28:10.193 に答える
1

SQLオプティマイザーは、今日、優れた実行プランを選択する上ではるかに優れた仕事をしますが、特にいくつかの大きなテーブルとビューで10を超えるテーブルを結合し、複数のフィルターを使用する必要がある場合、最適に実行されないことがよくあります。#TEMPテーブルを使用し、クエリを結合する前にクエリをはるかに小さなサブセットに分割するほど高速なものはまだありません。注:#TEMPテーブルにインデックスを追加するとパフォーマンスが向上することはめったにありません。

于 2013-02-12T21:16:14.317 に答える
0

いいえ、それは正しくありません。これらは両方とも別個の機能であり、それぞれに個別の用途があります。

たとえば、CTEは小さなデータに適していますが、一時テーブルは通常、大きなデータセットに適しています。一時テーブルにはインデックスを付けてパフォーマンスを向上させることができますが、CTEではできません。

MSDNのドキュメントを読み、どちらか一方を使用する特定のインスタンスを確認するのに少し時間を費やします。

于 2013-02-12T17:31:43.307 に答える