どちらがよりパフォーマンスが高いですか、CTE
またはTemporary Tables
?
12 に答える
それらは異なる概念だと思いますが、「チョークとチーズ」と言うにはそれほど違いはありません.
一時テーブルは、再利用したり、一連のデータに対して複数の処理パスを実行したりするのに適しています。
CTE は、再帰するため、または単純に読みやすさを向上させるために使用できます。
また、ビューやインライン テーブル値関数と同様に、メイン クエリで展開されるマクロのように扱うこともできます。一時テーブルは、スコープに関するいくつかのルールを持つ別のテーブルです
両方(およびテーブル変数も)を使用するprocを保存しました
CTE には用途があります。CTE 内のデータが小さく、再帰テーブルの場合のように読みやすさが大幅に向上する場合です。ただし、そのパフォーマンスは確かにテーブル変数より優れているわけではなく、非常に大きなテーブルを扱う場合、一時テーブルは CTE を大幅に上回ります。これは、CTE でインデックスを定義できず、別のテーブルとの結合が必要な大量のデータがある場合に発生します (CTE は単なるマクロのようなものです)。それぞれに数百万行のレコードがある複数のテーブルを結合している場合、CTE は一時テーブルよりも大幅にパフォーマンスが低下します。
一時テーブルは常にディスク上にあるため、CTE をメモリに保持できる限り、(テーブル変数のように) 高速になる可能性が高くなります。
ただし、CTE (または一時テーブル変数) のデータ負荷が大きくなりすぎると、ディスクにも保存されるため、大きなメリットはありません。
一般的に、一時テーブルよりも CTE の方が好きです。CTE は使用後になくなってしまうからです。明示的にドロップすることなどを考える必要はありません。
したがって、最終的に明確な答えはありませんが、個人的には、一時テーブルよりも CTE を好みます。
そのため、最適化を担当したクエリは、SQL サーバーで 2 つの CTE を使用して作成されました。28秒かかりました。
それらを一時テーブルに変換するのに2分かかり、クエリには3秒かかりました
結合されていたフィールドの一時テーブルにインデックスを追加し、2秒に短縮しました
3 分間の作業で、CTE をすべて削除することで、12 倍高速に実行できるようになりました。個人的には、CTE はデバッグが難しいため、使用しません。
クレイジーなことに、CTE は両方とも 1 回しか使用されていませんでしたが、それでもインデックスを配置すると 50% 高速であることが証明されました。
CTE の優れたパフォーマンスが賢明であると感じた用途の 1 つは、比較的複雑なクエリを、それぞれ数百万行のいくつかのテーブルに結合する必要がある場合でした。
CTE を使用して、最初にインデックス付きの列に基づいてサブセットを選択し、まずこれらのテーブルをそれぞれ数千の関連する行に切り詰めてから、CTE をメイン クエリに結合しました。これにより、クエリの実行時間が指数関数的に短縮されました。
CTE の結果はキャッシュされず、テーブル変数の方が適切な選択だったかもしれませんが、実際にそれらを試してみて、上記のシナリオに適合することがわかりました。
パーティーに遅れましたが...
私が働いている環境は非常に制約されており、一部のベンダー製品をサポートし、レポートなどの「付加価値」サービスを提供しています。ポリシーと契約の制限により、通常、テーブル/データ スペースを分離したり、永続的なコードを作成したりするという贅沢は許されません [アプリケーションによっては、多少改善されます]。
IOW、通常、ストアド プロシージャ、UDF、または一時テーブルなどを開発することはできません。MYアプリケーション インターフェイス (Crystal Reports - テーブルの追加/リンク、CR を使用した where 句の設定など) を介してほとんどすべてを行う必要があります。 )。ちょっとした節約の恩恵の 1 つは、Crystal では COMMANDS (および SQL 式) を使用できることです。通常のテーブルの追加/リンク機能では効率的でないいくつかのことは、SQL コマンドを定義することで実行できます。私はそれを通してCTEを使用し、「リモートで」非常に良い結果を得ました。CTE はレポートのメンテナンスにも役立ちます。コードを開発し、DBA に渡してコンパイル、暗号化、転送、インストールし、複数レベルのテストを行う必要はありません。ローカル インターフェイスを介して CTE を実行できます。
CR 付きの CTE を使用することの欠点は、各レポートが個別であることです。レポートごとに各 CTE を維持する必要があります。SP と UDF を実行できる場合は、通常のテーブルで作業しているかのように、SP にリンクしてパラメーターを渡すだけで、複数のレポートで使用できるものを開発できます。CR はパラメーターを SQL コマンドに処理するのが得意ではないため、CR/CTE の側面が欠けている可能性があります。そのような場合、私は通常、CTE を定義して十分なデータ (ただし、すべてのデータではない) を返し、CR のレコード選択機能を使用してそれを細分化します。
だから...私の投票はCTEです(データスペースを取得するまで)。
私はこれをテストしました.CTEと非CTE(すべてのユニオンインスタンスに対してクエリが入力された場所)の両方で、約31秒かかりました. CTE により、コードがはるかに読みやすくなりましたが、241 行から 130 行に削減されました。これは非常に優れています。一方、一時テーブルは 132 行に削減され、実行に 5 秒かかりました。冗談抜き。このテストはすべてキャッシュされました。クエリはすべて、以前に複数回実行されました。
これは本当に自由形式の質問であり、それはすべて、その使用方法と一時テーブルのタイプ(テーブル変数または従来のテーブル)によって異なります。
従来の一時テーブルはデータを一時DBに格納しますが、これにより一時テーブルの速度が低下します。ただし、テーブル変数はそうではありません。
SQL Server での経験から、CTE が一時テーブルより優れているシナリオの 1 つを見つけました。
ストアド プロシージャで一度だけ複雑なクエリから DataSet(~100000) を使用する必要がありました。
一時テーブルは、プロシージャの実行速度が遅い SQL でオーバーヘッドを引き起こしていました (一時テーブルは tempdb に存在する実際の実体化されたテーブルであり、現在のプロシージャの存続期間中持続するため)
一方、CTE では、CTE は次のクエリが実行されるまでしか持続しません。したがって、CTE はスコープが制限された便利なメモリ内構造です。デフォルトでは、CTE は tempdb を使用しません。
これは、CTE がコードを簡素化し、一時テーブルより優れたパフォーマンスを発揮するのに役立つ 1 つのシナリオです。私は2つのCTEを使用しました。
WITH CTE1(ID, Name, Display)
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO