web-dev-qa-db-ja.com

#を使用したSQLサーバーの一時テーブル-同じログインでの複数の接続のクエリを含む場合にのみアクセスできますか?

同じ名前の一時テーブルを参照する2つの完全に異なるクエリがあるとします。

1つのクエリ.... operates on:#tempTableName

クエリ2 .... operates on:#tempTableName

私はこれを調査し、「#tempはローカル一時テーブルであるため、他の接続からは見えない」ことを発見しましたが、どの接続が本当には、SQLクエリのコンテキストで詳細を意味します。 SQLは、実行されるクエリごとに個別の「接続」があると考えていますか、それとも何らかの方法で接続を共有していますか?

具体的には、私の質問は、「私のシナリオの2つのクエリが同じログインでアクセスされている場合はどうなるか」です。複数の.NETアプリケーションが同じ.NET接続文字列を使用しており、同時にデータベースにアクセスしています。次に、私のシナリオの両方のクエリが同時に実行されている場合、同じ一時テーブルにアクセスする可能性がありますか?ロックについてはどうですか?テーブルの操作中に不要なアクセスを防ぐために何かする必要がありますか?

私はこの答えを見ました https://stackoverflow.com/questions/466947/are-temporary-tables-thread-safe しかし、私は本当に '6のふりをするようなものが必要ですSQLクエリが接続をどのように利用し、排他的アクセスを決定しているのかなど、仮想シナリオで何が起こっているのかを明確にするために、何年も前からの説明。これは素晴らしいです!

7
Chris Halcrow

ローカルの一時オブジェクトはセッションで区切られます。 2つのクエリを同時に実行している場合、それらは明らかに2つの完全に別個のセッションであり、心配する必要はありません。ログインは重要ではありません。また、接続プーリングを使用している場合も同様です。ローカルの一時オブジェクト(ほとんどの場合はテーブルですが、ストアドプロシージャも)は、他のセッションから見えないように安全です。

コードにはローカル一時オブジェクトの単一の共通名がありますが、SQL Serverは、各セッションごとに(および必要に応じて各サブプロセスごとに)各オブジェクト名に一意の文字列を追加して、それらを分離します。 SSMSで次のクエリを実行すると、これを確認できます。

CREATE TABLE #T (Col1 INT)

SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';

次のような名前が表示されます(ここでスクロールする必要をなくすために、名前の中央からアンダースコアのほとんどを削除しました)。

#T_______________00000000001F

次に、そのクエリタブを閉じずに、新しいクエリタブを開き、同じ2つのクエリを貼り付けて実行します。次のようなものが表示されます。

#T_______________00000000001F
#T_______________000000000020

したがって、コードが#Tを参照するたびに、SQL Serverはそれをセッションに基づいて適切な名前に変換します。すべて自動的に魔法で処理されます:-)。

この点を説明します。私は非常にトランザクションの多いシステム(1秒あたり数千のトランザクション)で作業し、SaaS(サービスとしてのソフトウェア))Webアプリを24/7で実行しました。すべてのT-SQLコードはストアドプロシージャにありました(つまり、そのコードのすべての実行で同じローカル一時テーブル名)、ローカル一時テーブルをかなり活用しました。Webアプリであるため、ログインはほぼすべての接続で同じであり、接続プールを使用していました。 any同じ名前のローカル一時オブジェクトのセッション間アクセスを示す問題。非常に率直に言って、私たちはショックを受け、Microsoftとのサポート契約を利用して、それが発生した場合にそれを修正していました。 。

ローカル一時テーブルに関して留意すべき追加のポイント:

  1. theirの名前は一意ですが、依存オブジェクトは一意ではありません。一時テーブルにトリガーまたは外部キーを作成することはできないため、これは主キー、チェック制約、およびデフォルト制約に関するものです。つまり、主キーに#PK_#Tという名前を付けても、背後に一意のIDが追加された一意の名前にはなりません。これを試みると、「オブジェクトを作成できません。オブジェクトは既に存在します。」と表示されます。エラー(まあ、複数の同時実行をこの同じコードと仮定します)。したがって、ローカルの一時テーブルにこれら3つのオブジェクトタイプのいずれかが必要な場合は、依存オブジェクトをインラインで作成して、システム間で一意でセッション間で競合しないシステム生成の名前を取得できるようにします。

    インデックス名は[object_id]ごとに既に分離されているため、心配する必要はありません。

  2. 「オブジェクトを作成できません。オブジェクトは既に存在します」と表示されます。名前付きの依存オブジェクトを作成するときのエラー。これは、「セッションごとに完全に分離されたローカル一時オブジェクトである」というこの質問に関して見落とされがちな良い点をもたらします。ローカル一時テーブルが他のセッションから見える場合、CREATE TABLEステートメントはエラーになりますよね?
  3. ローカル一時テーブルのニュアンス(上記の#2に対する緩いカウンターポイントでもあります)は、そのサブプロセスの前に作成されたサブプロセス(つまりEXEC)でローカル一時テーブルを参照する場合です。 -プロセスが開始すると、そのローカル一時テーブルを表示(および変更)できるようになります。ただし、そのサブプロセスが同じ名前の別の一時テーブルを作成する場合、2つのオブジェクトがあり、それぞれに一意のIDが末尾に追加され、短い名前でアクセスできます。サブプロセスで#nameを参照すると、サブプロセスで作成されたオブジェクトのバージョンに常に解決されるという保証がないことをどこかで読んだことを覚えています。したがって、ネストされたストアドプロシージャ呼び出しのチェーンで実行される可能性のあるストアドプロシージャ間でローカル一時テーブル名を一意にすることが最善です。
11
Solomon Rutzky