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をまだ使用しているかどうか、またはすべてがメモリ内で発生するかどうかについて、私は矛盾する意見を読みました。
どちらが優れているのか?
回答:
tempdbの使用はそれらの1つではありませんが、一時テーブル(#tmp)とテーブル変数(@tmp)の間にはいくつかの違いがあります。
経験則として、少量から中規模のデータおよび単純な使用シナリオでは、テーブル変数を使用する必要があります。(これは非常に広範なガイドラインですが、もちろん多くの例外があります。以下および以下の記事を参照してください。)
それらから選択する際に考慮すべきいくつかのポイント:
一時テーブルは実際のテーブルなので、CREATE INDEXなどを実行できます。大量のデータがあり、インデックスによるアクセスが高速な場合は、一時テーブルが適切なオプションです。
テーブル変数は、PRIMARY KEYまたはUNIQUE制約を使用してインデックスを持つことができます。(一意でないインデックスが必要な場合は、主キー列をUNIQUE制約の最後の列として含めるだけです。一意の列がない場合は、ID列を使用できます。)SQL 2014にも一意でないインデックスがあります。。
テーブル変数はトランザクションに参加せず、SELECT
は暗黙的にで使用されNOLOCK
ます。トランザクションの動作は非常に役立ちます。たとえば、プロシージャの途中でROLLBACKしたい場合、そのトランザクション中に入力されたテーブル変数は引き続き入力されます。
一時テーブルにより、ストアドプロシージャが再コンパイルされる可能性があります。テーブル変数はしません。
SELECT INTOを使用して一時テーブルを作成できます。これは書き込みが速く(アドホッククエリに適しています)、一時テーブルの構造を事前に定義する必要がないため、時間の経過に伴うデータ型の変化に対応できる場合があります。
関数からテーブル変数を返すことができるため、ロジックをより簡単にカプセル化して再利用できます(たとえば、文字列を任意の区切り文字で値のテーブルに分割する関数を作成できます)。
ユーザー定義関数内でテーブル変数を使用すると、それらの関数をより広く使用できます(詳細については、CREATE FUNCTIONのドキュメントを参照してください)。関数を作成している場合は、特に必要がない限り、一時テーブルではなくテーブル変数を使用する必要があります。
テーブル変数と一時テーブルの両方がtempdbに格納されます。ただし、テーブル変数(2005以降)は、現在のデータベースの照合に対してデフォルトで設定されます。tempdbのデフォルトの照合を使用する一時テーブル(ref)に対して照合が行われます。つまり、一時テーブルを使用していて、db照合がtempdbと異なる場合は、照合の問題に注意する必要があります。これにより、一時テーブルのデータをデータベースのデータと比較する場合に問題が発生します。
グローバル一時テーブル(## tmp)は、すべてのセッションとユーザーが使用できる別のタイプの一時テーブルです。
さらに読む:
マーティン・スミスの dba.stackexchange.com に対する素晴らしい答え
2つの違いに関するMSDN FAQ:https : //support.microsoft.com/en-gb/kb/305977
MDSNブログ記事:https ://docs.microsoft.com/archive/blogs/sqlserverstorageengine/tempdb-table-variable-vs-local-temporary-table
記事:https : //searchsqlserver.techtarget.com/tip/Temporary-tables-in-SQL-Server-vs-table-variables
一時テーブルと一時変数の予期しない動作とパフォーマンスへの影響:SQLblog.comのPaul White
受け入れられた回答で、テーブル変数はロギングに参加しないという主張を見るだけです。
ログの量に違いがあることは、一般的には正しくないようです(少なくとも、テーブル自体へのinsert
/ update
/ delete
操作の場合)。ただし、システムテーブルの追加により、ストアドプロシージャのキャッシュされた一時オブジェクトについて、この点で多少の違いがあることがわかりました。アップデート)。
次の操作について、@table_variable
と#temp
テーブルの両方に対するロギング動作を確認しました。
トランザクションログレコードは、すべての操作でほぼ同じでした。
テーブル変数バージョンは、ベーステーブルに追加された(後で削除された)エントリを取得するため、実際にはいくつかの余分なログエントリがありsys.syssingleobjrefs
ますが、テーブル変数の内部名がテーブルよりも236バイト少ないため、純粋にログに記録されるバイト数は全体的に少し少なくなりました#temp
。 (118 nvarchar
文字少ない)。
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 |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
INSERT ... SELECT
ではSELECT INTO ...
、テーブル変数は最小限のログに記録されず、テーブル変数を使用できないため、実際には不利になります。
どちらが優れているのか?
小さいテーブル(1000行未満)の場合は一時変数を使用し、それ以外の場合は一時テーブルを使用します。
@wcm-実際にテーブル変数を選択するのはRamだけではありません-ディスクに部分的に保存できます。
一時テーブルはインデックスを持つことができますが、テーブル変数はプライマリインデックスしか持つことができません。速度が問題になる場合は、テーブル変数の方が高速ですが、レコードが多い場合や、クラスター化インデックスの一時テーブルを検索する必要がある場合は、一時テーブルの方が適しています。
一時テーブル:一時テーブルはデータの作成とバックアップが簡単です。
テーブル変数:ただし、テーブル変数には、通常のテーブルを通常作成するときの労力が含まれます。
一時テーブル:一時テーブルの結果は複数のユーザーが使用できます。
テーブル変数:ただし、テーブル変数は現在のユーザーのみが使用できます。
一時テーブル:一時テーブルはtempdbに格納されます。ネットワークトラフィックが発生します。一時テーブルに大きなデータがある場合、データベース全体で機能する必要があります。パフォーマンスの問題が存在します。
テーブル変数:ただし、テーブル変数は一部のデータの物理メモリに格納され、後でサイズが増加するとtempdbに移動されます。
一時テーブル:一時テーブルはすべてのDDL操作を実行できます。インデックスの作成、削除、変更などが可能です。
テーブル変数:テーブル変数ではDDL操作を実行できません。ただし、テーブル変数を使用すると、クラスター化インデックスのみを作成できます。
一時テーブル:一時テーブルは、現在のセッションまたはグローバルで使用できます。そのため、複数のユーザーセッションでテーブルの結果を利用できます。
テーブル変数:ただし、テーブル変数はそのプログラムまで使用できます。(ストアドプロシージャ)
一時テーブル:一時変数はトランザクションを使用できません。一時テーブルを使用してDML操作を実行すると、トランザクションをロールバックまたはコミットできます。
テーブル変数:ただし、テーブル変数に対しては実行できません。
一時テーブル:関数は一時変数を使用できません。さらに、関数でDML操作を行うことはできません。
テーブル変数:ただし、この関数ではテーブル変数を使用できます。しかし、テーブル変数を使用すると、それを行うことができます。
一時テーブル:後続のすべての呼び出しで一時変数を使用すると、ストアドプロシージャは再コンパイルを行います(同じ実行プランは使用できません)。
テーブル変数:テーブル変数はそのように動作しませんが。
一時変数はメモリにのみ存在するという神話を信じているすべての人にとって
まず、テーブル変数は必ずしもメモリに常駐しているわけではありません。メモリ不足の場合、テーブル変数に属するページをtempdbにプッシュできます。
ここの記事を読んでください:TempDB ::テーブル変数vsローカル一時テーブル
引用元; Professional SQL Server 2012の内部とトラブルシューティング
統計 一時テーブルとテーブル変数の主な違いは、統計がテーブル変数で作成されないことです。これには2つの大きな影響があります。1つ目は、クエリオプティマイザーが、含まれているデータに関係なく、テーブル変数の行数に固定推定値を使用することです。さらに、データを追加または削除しても、推定値は変わりません。
インデックス制約を作成することはできますが、テーブル変数にインデックスを作成することはできません。つまり、主キーまたは一意の制約を作成することで、テーブル変数にインデックスを作成できます(これらは制約をサポートするために作成されるため)。制約があり、したがって統計を持つインデックスがある場合でも、インデックスはコンパイル時に存在しないため、クエリのコンパイル時に使用されず、再コンパイルも発生しません。
スキーマの変更スキーマの変更は一時テーブルでは可能ですが、テーブル変数ではできません。スキーマの変更は一時テーブルで可能ですが、テーブルを使用するステートメントの再コンパイルが発生するため、使用しないでください。
テーブル変数はメモリに作成されません
テーブル変数はメモリ内構造であるため、一時テーブルよりも高速に実行されるという一般的な誤解があります。sysというDMVに感謝します。dm _ db _セッション_スペース_使用状況。これは、セッションごとのtempdbの使用状況を示しますが、そうでないことを証明できます。SQL Serverを再起動してDMVをクリアした後、次のスクリプトを実行して、セッション_ idがユーザー_オブジェクト_ alloc _ページ_ 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 ;
どちらを使用しますか?
一時テーブルまたはテーブル変数を使用するかどうかは、十分なテストによって決定する必要がありますが、問題が発生する可能性がはるかに少ないため、デフォルトとして一時 テーブルを使用することをお勧めし ます。
少量の行を処理していたため、テーブル変数を使用してコードを開発している顧客を見てきました。一時テーブルよりも高速でしたが、数年後、テーブル変数に数十万行があり、パフォーマンスはひどいものでした。 、それであなたの決定をするときにいくつかの容量計画を試してみてください!
別の違い:
テーブルvarには、それを作成するプロシージャ内のステートメントからのみアクセスできます。そのプロシージャから呼び出された他のプロシージャやネストされた動的SQL(execまたはsp_executesqlを介して)からはアクセスできません。
一方、一時テーブルのスコープには、呼び出されたプロシージャとネストされた動的SQLのコードが含まれます。
プロシージャによって作成されたテーブルに他の呼び出されたプロシージャまたは動的SQLからアクセスできる必要がある場合は、一時テーブルを使用する必要があります。これは複雑な状況で非常に便利です。
違いTemporary Tables (##temp/#temp)
とはTable Variables (@table)
のとおりです。
Table variable (@table)
で作成されますmemory
。一方、はでTemporary table (##temp/#temp)
作成されますtempdb database
。ただし、メモリが不足している場合、テーブル変数に属するページがtempdbにプッシュされることがあります。
Table variables
に関与することはできませんtransactions, logging or locking
。これはになり@table faster then #temp
ます。したがって、テーブル変数は一時テーブルよりも高速です。
Temporary table
とは異なり、スキーマの変更を許可しますTable variables
。
Temporary tables
作成されたルーチンと子ルーチンにも表示されます。一方、テーブル変数は、作成されたルーチンでのみ表示されます。
Temporary tables
は許可されCREATE INDEXes
ますが、代わりにを使用してインデックスを持つことはできTable variables
ません。CREATE INDEX
Primary Key or Unique Constraint
これらの2つの主な違いについて誰も言及しなかったことに驚いています。一時変数は並列挿入をサポートしていますが、テーブル変数はサポートしていません。実行計画との違いを確認できるはずです。そしてこれがChannel 9のSQL Workshopsからのビデオです。
これは、SQLMenaceが以前に回答したように、小さいテーブルに一時変数を使用する必要がある理由、または一時テーブルを使用する理由も説明します。