2011-09-16 11 views
10

with (Nolock)を追加すると、テンポラリテーブルから選択する際に競合が減るのですか?またはSQL Serverが最初の場所にテンポラリテーブルの競合を作成しないほどスマートですか?SQL Server 2008のテンポラリテーブルでnolock

PS:はい私はREADUNCOMMITTEDの危険性を認識しています。

select * from #myTempTable with (nolock) --is this faster? 

答えて

9

(私はこれがグローバルだと思うよう開発マシン上で)あなたはそれが当然違いの多くを作る自分のためにグローバルな一時テーブルの場合

SET NOCOUNT ON; 

CREATE TABLE ##T 
(
X INT 
) 

INSERT INTO ##T 
SELECT number 
FROM master..spt_values 

CREATE TABLE #T 
(
X INT 
) 
INSERT INTO #T 
SELECT * 
FROM ##T 

/*Run the commands first with the trace flag off so the locking 
info is less full of irrelevant stuff about plan compilation 
*/ 
GO 

PRINT '##T Read Committed' 
SELECT COUNT(*) FROM ##T 
PRINT '##T NOLOCK' 
SELECT COUNT(*) FROM ##T WITH (NOLOCK) 
PRINT '##T Finished' 

GO 

PRINT '#T Read Committed' 
SELECT COUNT(*) FROM #T 
PRINT '#T NOLOCK' 
SELECT COUNT(*) FROM #T WITH (NOLOCK) 
PRINT '#T Finished' 

GO 

DBCC TRACEON(-1,3604) 
DBCC TRACEON(-1,1200) 

GO 

PRINT '##T Read Committed' 
SELECT COUNT(*) FROM ##T 
PRINT '##T NOLOCK' 
SELECT COUNT(*) FROM ##T WITH (NOLOCK) 
PRINT '##T Finished' 

GO 

PRINT '#T Read Committed' 
SELECT COUNT(*) FROM #T 
PRINT '#T NOLOCK' 
SELECT COUNT(*) FROM #T WITH (NOLOCK) 
PRINT '#T Finished' 

GO 

DBCC TRACEOFF(-1,3604) 
DBCC TRACEOFF(-1,1200) 

DROP TABLE ##T 
DROP TABLE #T 

を取り出してロックを確認するためにトレースフラグ1200を使用することができます。

ローカル#tempテーブルのロックのタイプにはまだ小さな違いがあります。私は

#T Read Committed 
Process 56 acquiring IS lock on OBJECT: 2:301244128:0 (class bit0 ref1) result: OK 

Process 56 acquiring S lock on OBJECT: 2:301244128:0 (class bit0 ref1) result: OK 

Process 56 releasing lock on OBJECT: 2:301244128:0 

#T NOLOCK 
Process 56 acquiring Sch-S lock on OBJECT: 2:301244128:0 (class bit0 ref1) result: OK 

Process 56 acquiring S lock on HOBT: 2:9079256880114171904 [BULK_OPERATION] (class bit0 ref1) result: OK 

Process 56 releasing lock on OBJECT: 2:301244128:0 

編集以下の出力の一部を再現:上記の結果は、ヒープのためのものです。クラスタード・インデックスを持つ一時テーブルの場合、結果は以下のとおりです。

#T Read Committed 
Process 55 acquiring IS lock on OBJECT: 2:1790629422:0 (class bit0 ref1) result: OK 

Process 55 acquiring S lock on OBJECT: 2:1790629422:0 (class bit0 ref1) result: OK 

Process 55 releasing lock on OBJECT: 2:1790629422:0 

#T NOLOCK 
Process 55 acquiring Sch-S lock on OBJECT: 2:1790629422:0 (class bit0 ref1) result: OK 

Process 55 releasing lock on OBJECT: 2:1790629422:0 

#T Finished 

ヒープバージョンのBULK_OPERATIONロックの理由はexplained hereです。しかし、ロックオーバーヘッドは非常に最小限であることがわかります。

+0

非常に良い答え。私はこの有用なトレースフラグについて知らなかった!スクリプトは、テストの最後に3604を不必要に無効にすることに注意してください。私はこのフラグを私の開発者ボックスで起動可能にしました。セッションスコープで使うべきだと思います。何らかの理由で、これは1200で動作しませんでした。 1200はなぜグローバルでなければならないのですか? – usr

+0

私は 'DBCC TRACEON'と' DBCC TRACEOFF'に渡したパラメータのうち、最初のパラメータとしてトレースフラグを渡し、最後のパラメータとしてグローバルフラグを渡すべきです。なぜあなたは最初のものとして '-1'を入れますか? –

+0

@OgrishManどのような順序でも同じように動作します。 –

5

select * from #myTempTable 

一時テーブルのスコープが同じ接続であるので、それは大きな違いを作る可能性は低いです。

あなたは同じ接続であなた自身とロックを競合しています。一時テーブルを読んでいるのであれば、おそらく唯一のものです。

通常、SQL Serverクエリエンジンが過度に最適化されず、信頼性が高いとは限りません。何かを修正しようとする前に問題が生じるまで待ってください。

EDIT(ややオフトピック):(更新されたリンク)が

しかし、あなたは一時テーブルを作成のtempdb全体への影響の周りにいくつかの議論があります。 - see options here(ただしこれは古い記事 - SQL Server 6.5/7.0)とその可能性の高いSQL Server 2000の上位バージョンは、このシナリオを自動的に処理する可能性があります。

もう一度問題が発生するまでお待ちくださいあなたのソリューションは複雑です。

+0

ps - 私はすでに最適化の問題があります:) – dan

0

これは、クエリによって大きく異なる場合があります。 私はテンポラリテーブルにWITH(NO LOCK)を追加するだけで、クエリ実行時間を1295から590に減らしました。結果は異なる場合があります。