SQL Server 2005 では、次の 2 つの方法のいずれかで一時テーブルを作成できます。
declare @tmp table (Col1 int, Col2 int);
また
create table #tmp (Col1 int, Col2 int);
これら2つの違いは何ですか?@tmp がまだ tempdb を使用しているかどうか、またはすべてがメモリ内で発生するかどうかについて、矛盾する意見を読みました。
どちらのシナリオで一方が他方より優れているか?
SQL Server 2005 では、次の 2 つの方法のいずれかで一時テーブルを作成できます。
declare @tmp table (Col1 int, Col2 int);
また
create table #tmp (Col1 int, Col2 int);
これら2つの違いは何ですか?@tmp がまだ tempdb を使用しているかどうか、またはすべてがメモリ内で発生するかどうかについて、矛盾する意見を読みました。
どちらのシナリオで一方が他方より優れているか?
一時テーブル (#tmp) とテーブル変数 (@tmp) にはいくつかの違いがありますが、tempdb の使用はそれらの 1 つではありませんが、以下の MSDN リンクで詳しく説明されています。
経験則として、少量から中量のデータおよび単純な使用シナリオでは、テーブル変数を使用する必要があります。(これは非常に広範なガイドラインであり、もちろん多くの例外があります。以下の記事と次の記事を参照してください。)
それらの中から選択する際に考慮すべきいくつかのポイント:
一時テーブルは実際のテーブルであるため、CREATE INDEX などを実行できます。大量のデータがある場合は、インデックスによるアクセスの方が高速であり、一時テーブルは適切なオプションです。
テーブル変数は、PRIMARY KEY または UNIQUE 制約を使用してインデックスを持つことができます。(一意でないインデックスが必要な場合は、主キー列を一意制約の最後の列として含めるだけです。一意の列がない場合は、ID 列を使用できます。) SQL 2014 には一意でないインデックスもあります。 .
テーブル変数はトランザクションに参加せず、SELECT
s は暗黙的に と一緒NOLOCK
です。トランザクションの動作は非常に役立ちます。たとえば、プロシージャの途中で ROLLBACK したい場合、そのトランザクション中に入力されたテーブル変数は引き続き入力されます。
一時テーブルは、おそらく頻繁にストアド プロシージャが再コンパイルされる可能性があります。テーブル変数はそうではありません。
SELECT INTO を使用して一時テーブルを作成できます。これは、書き込みが速く (アドホック クエリに適しています)、一時テーブル構造を前もって定義する必要がないため、時間の経過に伴うデータ型の変更に対処できる可能性があります。
関数からテーブル変数を渡すことができるため、ロジックをカプセル化して再利用することがはるかに簡単になります (たとえば、任意の区切り記号で文字列を値のテーブルに分割する関数を作成します)。
ユーザー定義関数内でテーブル変数を使用すると、これらの関数をより広く使用できます (詳細については、CREATE FUNCTION のドキュメントを参照してください)。関数を作成している場合は、やむを得ない必要がない限り、一時テーブルではなくテーブル変数を使用する必要があります。
テーブル変数と一時テーブルの両方が tempdb に格納されます。ただし、テーブル変数 (2005 年以降) は、tempdb ( ref )の既定の照合を使用する一時テーブルに対して、現在のデータベースの照合に既定で設定されます。これは、一時テーブルを使用していて、データベースの照合順序が tempdb の照合順序と異なる場合、照合の問題に注意する必要があることを意味します。一時テーブルのデータとデータベースのデータを比較する場合に問題が発生します。
グローバル一時テーブル (##tmp) は、すべてのセッションとユーザーが使用できる別のタイプの一時テーブルです。
さらに読む:
dba.stackexchange.com での Martin Smith の優れた回答
2 つの違いに関する MSDN FAQ: https://support.microsoft.com/en-gb/kb/305977
記事: https://searchsqlserver.techtarget.com/tip/Temporary-tables-in-SQL-Server-vs-table-variables
一時テーブルと一時変数の予期しない動作とパフォーマンスへの影響: SQLblog.com の Paul White
テーブル変数がロギングに参加しないという受け入れられた回答の主張を見るだけです。
ロギングの量に違いがあるというのは一般的には正しくないように思われます(少なくともテーブル自体への // 操作insert
については、システム テーブルが追加されているため、ストアド プロシージャにキャッシュされた一時オブジェクトに関して、この点で若干の違いがあることがわかりました)。更新)。update
delete
@table_variable
次の操作について、 aと a#temp
テーブルの両方に対するロギング動作を調べました。
トランザクション ログ レコードは、すべての操作でほぼ同じでした。
テーブル変数バージョンには、ベース テーブルにエントリが追加される (後で削除される) ため、実際にはいくつかの余分なログ エントリがありますが、テーブル変数の内部名はテーブルsys.syssingleobjrefs
よりも 236 バイト少なく消費するため、純粋にログに記録されるバイト数は全体的に数バイト少なくなります。 #temp
(118nvarchar
文字少ない)。
sqlcmd
です):setvar tablename "@T"
:setvar tablescript "DECLARE @T TABLE"
/*
--Uncomment this section to test a #temp table
:setvar tablename "#T"
:setvar tablescript "CREATE TABLE #T"
*/
USE tempdb
GO
CHECKPOINT
DECLARE @LSN NVARCHAR(25)
SELECT @LSN = MAX([Current LSN])
FROM fn_dblog(null, null)
EXEC(N'BEGIN TRAN StartBatch
SAVE TRAN StartBatch
COMMIT
$(tablescript)
(
[4CA996AC-C7E1-48B5-B48A-E721E7A435F0] INT PRIMARY KEY DEFAULT 0,
InRowFiller char(7000) DEFAULT ''A'',
OffRowFiller varchar(8000) DEFAULT REPLICATE(''B'',8000),
LOBFiller varchar(max) DEFAULT REPLICATE(cast(''C'' as varchar(max)),10000)
)
BEGIN TRAN InsertFirstRow
SAVE TRAN InsertFirstRow
COMMIT
INSERT INTO $(tablename)
DEFAULT VALUES
BEGIN TRAN Insert9Rows
SAVE TRAN Insert9Rows
COMMIT
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP 9 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns
BEGIN TRAN InsertFailure
SAVE TRAN InsertFailure
COMMIT
/*Try and Insert 10 rows, the 10th one will cause a constraint violation*/
BEGIN TRY
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP (10) (10 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))) % 20
FROM sys.all_columns
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH
BEGIN TRAN Update10Rows
SAVE TRAN Update10Rows
COMMIT
UPDATE $(tablename)
SET InRowFiller = LOWER(InRowFiller),
OffRowFiller =LOWER(OffRowFiller),
LOBFiller =LOWER(LOBFiller)
BEGIN TRAN Delete10Rows
SAVE TRAN Delete10Rows
COMMIT
DELETE FROM $(tablename)
BEGIN TRAN AfterDelete
SAVE TRAN AfterDelete
COMMIT
BEGIN TRAN EndBatch
SAVE TRAN EndBatch
COMMIT')
DECLARE @LSN_HEX NVARCHAR(25) =
CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 1, 8),2) AS INT) AS VARCHAR) + ':' +
CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 10, 8),2) AS INT) AS VARCHAR) + ':' +
CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 19, 4),2) AS INT) AS VARCHAR)
SELECT
[Operation],
[Context],
[AllocUnitName],
[Transaction Name],
[Description]
FROM fn_dblog(@LSN_HEX, null) AS D
WHERE [Current LSN] > @LSN
SELECT CASE
WHEN GROUPING(Operation) = 1 THEN 'Total'
ELSE Operation
END AS Operation,
Context,
AllocUnitName,
COALESCE(SUM([Log Record Length]), 0) AS [Size in Bytes],
COUNT(*) AS Cnt
FROM fn_dblog(@LSN_HEX, null) AS D
WHERE [Current LSN] > @LSN
GROUP BY GROUPING SETS((Operation, Context, AllocUnitName),())
結果
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| | | | @TV | #TV | |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Operation | Context | AllocUnitName | Size in Bytes | Cnt | Size in Bytes | Cnt | Difference Bytes |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| LOP_ABORT_XACT | LCX_NULL | | 52 | 1 | 52 | 1 | |
| LOP_BEGIN_XACT | LCX_NULL | | 6056 | 50 | 6056 | 50 | |
| LOP_COMMIT_XACT | LCX_NULL | | 2548 | 49 | 2548 | 49 | |
| LOP_COUNT_DELTA | LCX_CLUSTERED | sys.sysallocunits.clust | 624 | 3 | 624 | 3 | |
| LOP_COUNT_DELTA | LCX_CLUSTERED | sys.sysrowsets.clust | 208 | 1 | 208 | 1 | |
| LOP_COUNT_DELTA | LCX_CLUSTERED | sys.sysrscols.clst | 832 | 4 | 832 | 4 | |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL | | 120 | 3 | 120 | 3 | |
| LOP_DELETE_ROWS | LCX_INDEX_INTERIOR | Unknown Alloc Unit | 720 | 9 | 720 | 9 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysallocunits.clust | 444 | 3 | 444 | 3 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysallocunits.nc | 276 | 3 | 276 | 3 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.syscolpars.clst | 628 | 4 | 628 | 4 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.syscolpars.nc | 484 | 4 | 484 | 4 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysidxstats.clst | 176 | 1 | 176 | 1 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysidxstats.nc | 144 | 1 | 144 | 1 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysiscols.clst | 100 | 1 | 100 | 1 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysiscols.nc1 | 88 | 1 | 88 | 1 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysobjvalues.clst | 596 | 5 | 596 | 5 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysrowsets.clust | 132 | 1 | 132 | 1 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysrscols.clst | 528 | 4 | 528 | 4 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.clst | 1040 | 6 | 1276 | 6 | 236 |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc1 | 820 | 6 | 1060 | 6 | 240 |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc2 | 820 | 6 | 1060 | 6 | 240 |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc3 | 480 | 6 | 480 | 6 | |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.syssingleobjrefs.clst | 96 | 1 | | | -96 |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.syssingleobjrefs.nc1 | 88 | 1 | | | -88 |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | Unknown Alloc Unit | 72092 | 19 | 72092 | 19 | |
| LOP_DELETE_ROWS | LCX_TEXT_MIX | Unknown Alloc Unit | 16348 | 37 | 16348 | 37 | |
| LOP_FORMAT_PAGE | LCX_HEAP | Unknown Alloc Unit | 1596 | 19 | 1596 | 19 | |
| LOP_FORMAT_PAGE | LCX_IAM | Unknown Alloc Unit | 252 | 3 | 252 | 3 | |
| LOP_FORMAT_PAGE | LCX_INDEX_INTERIOR | Unknown Alloc Unit | 84 | 1 | 84 | 1 | |
| LOP_FORMAT_PAGE | LCX_TEXT_MIX | Unknown Alloc Unit | 4788 | 57 | 4788 | 57 | |
| LOP_HOBT_DDL | LCX_NULL | | 108 | 3 | 108 | 3 | |
| LOP_HOBT_DELTA | LCX_NULL | | 9600 | 150 | 9600 | 150 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysallocunits.clust | 456 | 3 | 456 | 3 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.syscolpars.clst | 644 | 4 | 644 | 4 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysidxstats.clst | 180 | 1 | 180 | 1 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysiscols.clst | 104 | 1 | 104 | 1 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysobjvalues.clst | 616 | 5 | 616 | 5 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysrowsets.clust | 136 | 1 | 136 | 1 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysrscols.clst | 544 | 4 | 544 | 4 | |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.sysschobjs.clst | 1064 | 6 | 1300 | 6 | 236 |
| LOP_INSERT_ROWS | LCX_CLUSTERED | sys.syssingleobjrefs.clst | 100 | 1 | | | -100 |
| LOP_INSERT_ROWS | LCX_CLUSTERED | Unknown Alloc Unit | 135888 | 19 | 135888 | 19 | |
| LOP_INSERT_ROWS | LCX_INDEX_INTERIOR | Unknown Alloc Unit | 1596 | 19 | 1596 | 19 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysallocunits.nc | 288 | 3 | 288 | 3 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.syscolpars.nc | 500 | 4 | 500 | 4 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysidxstats.nc | 148 | 1 | 148 | 1 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysiscols.nc1 | 92 | 1 | 92 | 1 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysschobjs.nc1 | 844 | 6 | 1084 | 6 | 240 |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysschobjs.nc2 | 844 | 6 | 1084 | 6 | 240 |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.sysschobjs.nc3 | 504 | 6 | 504 | 6 | |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF | sys.syssingleobjrefs.nc1 | 92 | 1 | | | -92 |
| LOP_INSERT_ROWS | LCX_TEXT_MIX | Unknown Alloc Unit | 5112 | 71 | 5112 | 71 | |
| LOP_MARK_SAVEPOINT | LCX_NULL | | 508 | 8 | 508 | 8 | |
| LOP_MODIFY_COLUMNS | LCX_CLUSTERED | Unknown Alloc Unit | 1560 | 10 | 1560 | 10 | |
| LOP_MODIFY_HEADER | LCX_HEAP | Unknown Alloc Unit | 3780 | 45 | 3780 | 45 | |
| LOP_MODIFY_ROW | LCX_CLUSTERED | sys.syscolpars.clst | 384 | 4 | 384 | 4 | |
| LOP_MODIFY_ROW | LCX_CLUSTERED | sys.sysidxstats.clst | 100 | 1 | 100 | 1 | |
| LOP_MODIFY_ROW | LCX_CLUSTERED | sys.sysrowsets.clust | 92 | 1 | 92 | 1 | |
| LOP_MODIFY_ROW | LCX_CLUSTERED | sys.sysschobjs.clst | 1144 | 13 | 1144 | 13 | |
| LOP_MODIFY_ROW | LCX_IAM | Unknown Alloc Unit | 4224 | 48 | 4224 | 48 | |
| LOP_MODIFY_ROW | LCX_PFS | Unknown Alloc Unit | 13632 | 169 | 13632 | 169 | |
| LOP_MODIFY_ROW | LCX_TEXT_MIX | Unknown Alloc Unit | 108640 | 120 | 108640 | 120 | |
| LOP_ROOT_CHANGE | LCX_CLUSTERED | sys.sysallocunits.clust | 960 | 10 | 960 | 10 | |
| LOP_SET_BITS | LCX_GAM | Unknown Alloc Unit | 1200 | 20 | 1200 | 20 | |
| LOP_SET_BITS | LCX_IAM | Unknown Alloc Unit | 1080 | 18 | 1080 | 18 | |
| LOP_SET_BITS | LCX_SGAM | Unknown Alloc Unit | 120 | 2 | 120 | 2 | |
| LOP_SHRINK_NOOP | LCX_NULL | | | | 32 | 1 | 32 |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Total | | | 410144 | 1095 | 411232 | 1092 | 1088 |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
どのシナリオで一方が他方よりも優れていますか?
小さいテーブル(1000行未満)の場合は一時変数を使用し、それ以外の場合は一時テーブルを使用します。
@wcm - 実際には、テーブル変数を選択するのは Ram だけではなく、部分的にディスクに保存できます。
一時テーブルにはインデックスを設定できますが、テーブル変数にはプライマリ インデックスしか設定できません。速度が問題になる場合は、テーブル変数の方が高速になる可能性がありますが、明らかに多くのレコードがある場合、またはクラスター化されたインデックスの一時テーブルを検索する必要がある場合は、一時テーブルの方が適しています。
一時テーブル: 一時テーブルは、データの作成とバックアップが簡単です。
テーブル変数: ただし、通常のテーブルを作成する場合、テーブル変数には手間がかかります。
一時テーブル: 一時テーブルの結果は、複数のユーザーが使用できます。
テーブル変数: ただし、テーブル変数は現在のユーザーのみが使用できます。
一時テーブル: 一時テーブルは tempdb に格納されます。これにより、ネットワーク トラフィックが発生します。一時テーブルに大きなデータがある場合、データベース全体で機能する必要があります。パフォーマンスの問題が存在します。
テーブル変数: ただし、テーブル変数はデータの一部を物理メモリに格納し、後でサイズが大きくなると tempdb に移動します。
一時テーブル: 一時テーブルはすべての DDL 操作を実行できます。インデックスの作成、削除、変更などが可能です。
テーブル変数: 一方、テーブル変数では DDL 操作を実行できません。ただし、テーブル変数を使用すると、クラスター化インデックスのみを作成できます。
一時テーブル: 一時テーブルは、現在のセッションまたはグローバルに使用できます。複数のユーザー セッションでテーブル内の結果を利用できるようにします。
テーブル変数: ただし、テーブル変数はそのプログラムまで使用できます。(ストアド プロシージャ)
一時テーブル: 一時変数はトランザクションを使用できません。一時テーブルで DML 操作を実行すると、トランザクションをロールバックまたはコミットできます。
テーブル変数: ただし、テーブル変数に対してはできません。
一時テーブル: 関数は一時変数を使用できません。さらに、関数内で DML 操作を行うことはできません。
テーブル変数: ただし、この関数ではテーブル変数を使用できます。しかし、テーブル変数を使用してそれを行うことができます。
一時テーブル: 後続の呼び出しごとに一時変数を使用すると、ストアド プロシージャが再コンパイルを行います (同じ実行プランを使用することはできません)。
テーブル変数: 一方、テーブル変数はそのようには機能しません。
一時変数はメモリにのみ存在するという神話を信じているすべての人のために
まず、テーブル変数は必ずしもメモリに常駐しているとは限りません。メモリ不足の場合、テーブル変数に属するページをtempdbにプッシュできます。
こちらの記事をお読みください:TempDB::テーブル変数とローカル一時テーブル
引用元; Professional SQL Server 2012 の内部構造とトラブルシューティング
統計 一時テーブルとテーブル変数の主な違いは、テーブル変数では統計が作成されないことです。これには 2 つの大きな影響があります。1 つ目は、テーブル変数に含まれるデータに関係なく、クエリ オプティマイザーがテーブル変数の行数に対して固定推定を使用することです。さらに、データを追加または削除しても、見積もりは変わりません。
インデックス制約を作成することはできますが、テーブル変数にインデックスを作成することはできません。これは、主キーまたは一意の制約を作成することにより、テーブル変数にインデックス (これらは制約をサポートするために作成されるため) を持つことができることを意味します。制約があり、したがって統計を持つインデックスがある場合でも、インデックスはコンパイル時に存在しないため、クエリのコンパイル時に使用されず、再コンパイルも発生しません。
スキーマの変更スキーマの変更は、一時テーブルでは可能ですが、テーブル変数ではできません。一時テーブルではスキーマの変更が可能ですが、テーブルを使用するステートメントの再コンパイルが発生するため、一時テーブルの使用は避けてください。
テーブル変数はメモリ内に作成されません
テーブル変数はメモリ内構造であり、一時テーブルよりも高速に実行されるという一般的な誤解があります。sys という DMV に感謝します。セッションごとの tempdb の使用状況を示す dm_db_session_space_usage は、そうではないことを証明できます。SQL Server を再起動して DMV をクリアした後、次のスクリプトを実行して、セッション _ id が user _ objects _ alloc _ page _ count に対して 0 を返すことを確認します。
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;
次のスクリプトを実行して、1 つの列を持つ一時テーブルを作成し、1 つの行を挿入することで、一時テーブルが使用する領域を確認できます。
CREATE TABLE #TempTable ( ID INT ) ;
INSERT INTO #TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;
私のサーバーでの結果は、テーブルが tempdb で 1 ページ割り当てられたことを示しています。同じスクリプトを実行しますが、今回はテーブル変数を使用します。
DECLARE @TempTable TABLE ( ID INT ) ;
INSERT INTO @TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;
どちらを使用しますか?
一時テーブルまたはテーブル変数を使用するかどうかは、徹底的なテストによって決定する必要がありますが、問題が発生する可能性がはるかに少ないため、デフォルトとして一時テーブルを使用することをお勧めし ます。
テーブル変数を使用してコードを開発しているお客様を見てきました。これは、処理する行数が少ないためで、一時テーブルよりも高速でしたが、数年後にはテーブル変数に数十万行があり、パフォーマンスがひどいものでしたですので、決定を下す際にはキャパシティ プランニングを検討してください。
その他の主な違いは、テーブル変数には、一時テーブルのような列統計がないことです。これは、クエリ オプティマイザーがテーブル変数に含まれる行数を認識していないことを意味し (1 と推測します)、テーブル変数に実際に多数の行がある場合、非常に非最適なプランが生成される可能性があります。
別の違い:
テーブル var は、それを作成するプロシージャ内のステートメントからのみアクセスできます。そのプロシージャまたはネストされた動的 SQL (exec または sp_executesql を介して) によって呼び出される他のプロシージャからはアクセスできません。
一方、一時テーブルのスコープには、呼び出されたプロシージャとネストされた動的 SQL のコードが含まれます。
プロシージャによって作成されたテーブルが、呼び出された他のプロシージャまたは動的 SQL からアクセスできる必要がある場合は、一時テーブルを使用する必要があります。これは、複雑な状況で非常に便利です。
また、多くの場合、両方をより高速な派生テーブルに置き換えることができることも考慮してください。ただし、すべてのパフォーマンス チューニングと同様に、実際のデータに対する実際のテストのみが、特定のクエリに対する最適なアプローチを教えてくれます。
SQL では、一時テーブルは TempDB に格納され、ローカルの一時テーブルは現在のセッションでのみ表示され、別のセッションでは表示されません。これは、ネストされたストアド プロシージャ コール間で共有できます。グローバル一時テーブルは他のすべてのセッションに表示され、最後の接続参照テーブルが閉じられると破棄されます。例えば、
Select Dept.DeptName, Dept.DeptId, COUNT(*) as TotalEmployees
into #TempEmpCount
from Tbl_EmpDetails Emp
join Tbl_Dept Dept
on Emp.DeptId = Dept.DeptId
group by DeptName, Dept.DeptId
テーブル変数は tempTables に似ており、TempDB にもテーブル変数が作成されます。テーブル変数のスコープは、それが宣言されているバッチ、ストアド プロシージャ、またはステートメント ブロックです。これらは、プロシージャ間でパラメーターとして渡すことができます。テーブル変数を使用して、同じクエリを次のように記述できます。
Declare @tblEmployeeCount table
(DeptName nvarchar(20),DeptId int, TotalEmployees int)
Insert @tblEmployeeCount
Select DeptName, Tbl_Dept.DeptId, COUNT(*) as TotalEmployees
from Tbl_EmpDetails
join Tbl_Dept
on Tbl_EmpDetails.DeptId = Tbl_Dept.DeptId
group by DeptName, Tbl_Dept.DeptId