313

テーブル変数で詳細を学習しています。一時テーブルは常にディスク上にあり、テーブル変数はメモリ内にあると言われています。つまり、テーブル変数は一時テーブルよりも少ない IO 操作を使用するため、テーブル変数のパフォーマンスは一時テーブルよりも優れています。

ただし、テーブル変数にメモリに格納できないレコードが多すぎる場合、テーブル変数は一時テーブルのようにディスクに配置されることがあります。

しかし、「多すぎるレコード」が何であるかはわかりません。100,000 レコード? または1000,000レコード?使用しているテーブル変数がメモリ内にあるかディスク上にあるかを確認するにはどうすればよいですか? SQL Server 2005 には、テーブル変数のスケールを測定したり、テーブル変数がメモリからディスクに配置されたときに通知したりする機能やツールはありますか?

4

6 に答える 6

377

あなたの質問は、テーブル変数と一時テーブルを取り巻く一般的な誤解のいくつかに屈したことを示しています。

2 つのオブジェクト タイプの違いを調べて、DBA サイトに非常に広範な回答を書きました。これは、ディスクとメモリに関する質問にも対処します (2 つの動作に大きな違いは見られませんでした)。

タイトルの質問に関しては、テーブル変数とローカル一時テーブルをいつ使用するかについて、常に選択肢があるとは限りません。たとえば、関数では、テーブル変数のみを使用でき、子スコープのテーブルに書き込む必要がある場合は、#tempテーブルのみが実行できます (テーブル値パラメーターは読み取り専用アクセスを許可します)。

選択肢がある場合は、いくつかの提案を以下に示します (ただし、最も信頼できる方法は、特定のワークロードで両方を単純にテストすることです)。

  1. テーブル変数で作成できないインデックスが必要な場合は、もちろん#temporaryテーブルが必要です。ただし、これの詳細はバージョンに依存します。SQL Server 2012 以前では、テーブル変数で作成できる唯一のインデックスは、UNIQUEorPRIMARY KEY制約によって暗黙的に作成されたものでした。SQL Server 2014 では、 で使用できるオプションのサブセットにインライン インデックス構文が導入されましたCREATE INDEX。これは、フィルタリングされたインデックス条件を許可するために拡張されました。ただし、INCLUDE-d 列または列ストア インデックスを含むインデックスは、テーブル変数で作成することはできません。

  2. テーブルに多数の行を繰り返し追加および削除する場合は、テーブルを使用し#temporaryます。これはTRUNCATE(大きなテーブルよりも効率的ですDELETE) をサポートし、さらに、 a に続く後続の挿入は、ここに示すTRUNCATEように、 a に続く挿入よりも優れたパフォーマンスを発揮できます。DELETE

  3. 多数の行を削除または更新する場合、行セット共有を使用できる場合、一時テーブルはテーブル変数よりもはるかに優れたパフォーマンスを発揮する可能性があります (例については、以下の「行セット共有の影響」を参照してください)。
  4. テーブルを使用した最適な計画がデータによって異なる場合は、テーブルを使用し#temporaryます。これにより、データに従って計画を動的に再コンパイルできる統計の作成がサポートされます (ただし、ストアド プロシージャ内のキャッシュされた一時テーブルの場合、再コンパイルの動作を個別に理解する必要があります)。
  5. テーブルを使用したクエリの最適なプランが変更される可能性が低い場合は、テーブル変数を使用して、統計の作成と再コンパイルのオーバーヘッドをスキップすることを検討できます (必要なプランを修正するためのヒントが必要になる可能性があります)。
  6. テーブルに挿入されたデータのソースが潜在的に高価なSELECTステートメントからのものである場合、テーブル変数を使用すると、並列プランを使用してこの可能性がブロックされることを考慮してください。
  7. 外部ユーザー トランザクションのロールバックに耐えられるようにテーブル内のデータが必要な場合は、テーブル変数を使用します。これの考えられる使用例は、長い SQL バッチのさまざまなステップの進行状況をログに記録することです。
  8. ユーザー トランザクション内でテーブルを使用する場合#temp、テーブル変数よりも長くロックを保持できます (ロックのタイプと分離レベルに応じて、トランザクションの終了とステートメントの終了までの可能性があります) tempdb。ユーザーのトランザクションが終了します。したがって、これはテーブル変数の使用を支持するかもしれません。
  9. ストアド ルーチン内では、テーブル変数と一時テーブルの両方をキャッシュできます。キャッシュされたテーブル変数のメタデータのメンテナンスは、テーブルの場合よりも少なくなります#temporarytempdbBob Ward はプレゼンテーションの中で、これにより、同時実行性の高い条件下でシステム テーブルに追加の競合が発生する可能性があると指摘しています。さらに、少量のデータを処理する場合、パフォーマンスに測定可能な違いが生じる可能性があります

行セット共有の影響

DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);

CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);

INSERT INTO @T 
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2

SET STATISTICS TIME ON

/*CPU time = 7016 ms,  elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;

/*CPU time = 6234 ms,  elapsed time = 7236 ms.*/
DELETE FROM @T

/* CPU time = 828 ms,  elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;

/*CPU time = 672 ms,  elapsed time = 980 ms.*/
DELETE FROM #T

DROP TABLE #T
于 2012-12-08T13:20:10.493 に答える
77

非常に少量のデータ(数千バイト)の場合は、テーブル変数を使用します

大量のデータに一時テーブルを使用する

別の見方をすれば、インデックス、自動統計、またはSQLオプティマイザーの優れた機能の恩恵を受ける可能性があると思われる場合は、データセットがテーブル変数に対して大きすぎる可能性があります。

私の例では、永続的なテーブルをUPDATE / INSERTするために使用する前に、約20行をフォーマットに入れて、それらをグループとして変更したかっただけです。したがって、テーブル変数は完璧です。

しかし、SQLを実行して、一度に数千行を埋め戻しています。一時テーブルのパフォーマンスは、テーブル変数よりもはるかに優れていると断言できます。

これは、同様のサイズの理由でCTEが懸念される方法と同じです。CTEのデータが非常に小さい場合、CTEのパフォーマンスはオプティマイザーが想定するものと同等かそれ以上であることがわかりますが、非常に大きい場合はそれはあなたをひどく傷つけます。

私の理解は主にhttp://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/に基づいており、詳細が記載されています。

于 2013-01-22T18:06:26.237 に答える
4

変数テーブルは現在のセッションでのみ使用できます。たとえば、現在のセッションEXEC内で別のストアド プロシージャが必要な場合は、テーブルを渡す必要がありますTable Valued Parameter。もちろん、これはパフォーマンスに影響します。一時テーブルを使用すると、これを行うことができます。一時テーブル名を渡す

一時テーブルをテストするには:

  • Management Studio クエリ エディターを開く
  • 一時テーブルを作成する
  • 別のクエリ エディター ウィンドウを開く
  • この表から選択 「利用可能」

変数テーブルをテストするには:

  • Management Studio クエリ エディターを開く
  • 変数テーブルを作成する
  • 別のクエリ エディター ウィンドウを開く
  • この表から選択してください "利用できません"

他に私が経験したことは次のとおりです。スキーマにテーブルを作成する権限がない場合は、GRANT変数テーブルを使用してください。

于 2016-07-06T16:20:20.287 に答える
3

宣言されたテーブルにデータを書き込みdeclare @tb、他のテーブルと結合した後、一時テーブルと比較して応答時間tempdb .. # tbがはるかに長いことに気付きました。

それらを@tbで結合すると、 #tmとは異なり、結果を返すのに時間がかかります。戻りはほぼ瞬時です。

10,000行の結合と他の5つのテーブルとの結合でテストを行いました

于 2017-07-14T14:38:25.253 に答える