あるデータベースから別のデータベースにデータをインポートおよび変換するストアドプロシージャを作成しました。インポートごとに1つの会社IDを取得し、この会社に関連するすべてのデータをインポートします。
変換手順を支援するために、一時テーブルを使用します。スクリプトのレビューの一環として、一時テーブルではなくテーブル変数を使用するように言われました。レビューアは、2つの異なるインポートを同時に実行すると、一時テーブルが共有され、インポートが破損すると主張しています。
質問:
EXEC
を呼び出すたびに新しいスコープが作成されますか?これは、スクリプトの不自然な例です。
CREATE PROC [dbo].[ImportCompany]
(
@CompanyId AS INTEGER
)
AS
EXEC [dbo].[ImportAddress] @CompanyId = @CompanyId
--Import other data
CREATE PROC [dbo].[ImportAddress]
(
@CompanyId AS INTEGER
)
AS
CREATE TABLE #Companies (OldAddress NVARCHAR(128), NewAddress NVARCHAR(128))
INSERT INTO #Companies(OldAddress, NewAddress)
SELECT
Address as OldAddress,
'Transformed ' + Address as NewAddress
FROM
[OldDb].[dbo].[Addresses]
WHERE
CompanyId = @CompanyId
--Do stuff with the transformed data
DROP TABLE #Companies
EXEC [dbo].[ImportCompany] @CompanyId = 12345
CREATE TABLE
から:
ローカル一時テーブルは、現在のセッションでのみ表示されます
そして更に重要なことに):
複数のユーザーが同時に実行できるストアドプロシージャまたはアプリケーションでローカル一時テーブルが作成される場合、データベースエンジンは、異なるユーザーによって作成されたテーブルを区別できる必要があります[ sic-ほとんど間違いなく、これはユーザーではなくセッションと言うべきです]。データベースエンジンは、各ローカル一時テーブル名に数値の接尾辞を内部的に追加することによりこれを行います。
これは、共有されると言った人のポイントにまったく反論します。
また、プロシージャの最後に(同じリンクから)DROP TABLE
する必要はありません。
ストアドプロシージャで作成されたローカル一時テーブルは、ストアドプロシージャが終了すると自動的に削除されます
##
は、グローバル一時テーブルに使用されます-さまざまなインポートで使用可能になります。
#
はローカルの一時テーブルに使用され、現在/内部のスコープでのみ使用可能です。
あるセッションは別のセッションの一時テーブルを見ることができません。したがって、一時テーブルまたはテーブル変数を使用するかどうかに関係なく、異なるインポートは相互に影響しません。
例外は、##
で始まるグローバル一時テーブルです。それらはすべての接続に表示されます。
トリガーで使用された一時テーブルが奇妙な動作をする理由を見つけるのに苦労しました。次に、一時テーブルは、トリガーを起動したデータを挿入するために使用されるストアドプロシージャの一時テーブルと同じ名前であることに気付きました。これはすぐに明らかになるはずだったことを今では認識していますが、それは何かが意味をなさない理由を見つけようとしたときに最も明白な原因を見落とす典型的なケースでした。
したがって、ストアドプロシージャが別のストアドプロシージャを呼び出すか、トリガーを起動する場合、望ましくない副作用を防ぐために、これらの間で一時テーブル名を一意にする必要があることを覚えておくことが重要です。
さらに、内部ストアドプロシージャで次のコードを実行しても、期待どおりに機能しません。外部ストアドプロシージャが一時テーブル名をロックしているようです。
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable