web-dev-qa-db-ja.com

ストアドプロシージャを異なるユーザーが同時に実行できる場合は、一時テーブルを使用することをお勧めしますか?

Active DirectoryからobjectGUIDを取得するストアドプロシージャに取り組んでいます。結果を一時テーブルに格納し、他のプロセスで使用するために出力パラメーターに値を返します。 SPは、さまざまなストアドプロシージャおよびWebアプリケーションPHPから呼び出されます。ASPクラシックおよびASP.Net。

私は [〜#〜]ここ[〜#〜] を読みます(一時テーブルに関して):

ストアドプロシージャ内で作成された場合、それらはストアドプロシージャの完了時に破棄されます。さらに、特定の一時テーブルのスコープは、それが作成されたセッションです。つまり、現在のユーザーにのみ表示されます。複数のユーザーが#TableXという名前の一時テーブルを作成でき、同時に実行されるクエリは互いに影響しません。ユーザーは自律型トランザクションのままであり、テーブルは自律型オブジェクトのままです。サンプルの一時テーブル名が「#」記号で始まっていることに気付くでしょう。

私は行ってもいいように思えますが、私が知らない落とし穴がないことを確認するためにいくつかのアドバイスを求めたかったのです。こちらがSPです。

前もって感謝します。

CREATE PROCEDURE stp_adlookup
@user varchar(100),
@objectGUID varbinary(256) OUTPUT
AS
SET NOCOUNT ON;
DECLARE @qry char(1000)
CREATE TABLE #tmp(
objectGUID nvarchar(256)
)

SET @qry = 'SELECT *
FROM openquery(ADSI, ''
SELECT  objectGUID              
FROM    ''''LDAP://mydomaincontroller.com''''
WHERE sAMAccountName = ''''' + @user + '''''
'')'
INSERT INTO #tmp
EXEC(@qry)
SELECT @objectGUID=CAST(objectGUID as varbinary(256))  FROM #tmp;
DROP TABLE #tmp
SET NOCOUNT OFF;
GO
8
user1633947

はい。ユーザーがまったく同時に実行した場合でも、各ユーザーは#tempテーブルの独自のコピーを取得します。

(ただし、twoで始まるグローバル## tempテーブルは、先頭にポンド/ハッシュ記号を使用しないでください。)

しかし、なぜここに#tempテーブルが必要なのでしょうか。このようなものが機能するはずです(私は私の近くにLDAPを持っていないため、期待外れです)。

CREATE PROCEDURE dbo.stp_adlookup -- ALWAYS use schema prefix
  @user varchar(100),
  @objectGUID varbinary(256) OUTPUT
AS
BEGIN -- use body wrappers
  SET NOCOUNT ON;

  DECLARE @qry nvarchar(max); -- don't use CHAR for dynamic SQL

  SET @qry = N'SELECT @o = objectGUID
    FROM openquery(ADSI, ''SELECT  objectGUID              
      FROM    ''''LDAP://mydomaincontroller.com''''
      WHERE sAMAccountName = ''''' + @user + ''''''')';

  -- can probably parameterize the above, but those single
  -- quotes are a nightmare. Not sure if they're necessary
  -- but I do not feel like trying to untangle them.

  EXEC sys.sp_executesql @qry, N'@o UNIQUEIDENTIFIER', @o = @objectGUID OUTPUT;

  -- SET NOCOUNT OFF; -- don't do this.
END
GO
15
Aaron Bertrand

あなたは大丈夫です、同じ名前の一時テーブルで問題なく1日に何千回も実行される無数のSPがここにあります。

これは視覚的な例です。 SQL2014インスタンスに2つのテーブルを作成しました。 1つはSPID 53から作成され、もう1つはSPID 57から作成されました。オブジェクトエクスプローラーでの表示は次のとおりです。

enter image description here

ご覧のとおり、「名前」は同じですが、最後に、テーブルを異なるものにする素敵な文字セットがあります。唯一の違いは、異なるクエリウィンドウからCREATEステートメントを実行したことです。これは、視覚的に表示する方法です。 #tmpテーブルをクエリする場合、セッションに適用されるテーブルのみをクエリします。

ただし、1つの提案をします。それは私が完全に罪を犯していることであり、私は移行に取り組んでいます。 EXEC()の代わりにsp_executesqlを使用してください。アーロン・バートランドはこれを「キックへの悪い習慣」の一つとして書いた:

基本的に、sp_executesqlを使用すると、SQLインジェクションの可能性が減り、実行プランが再利用される可能性が高くなります。アーロンはこの記事でより詳細に説明していますが、それは1000フィートのビューです。

8

広義では、この方法で問題なく実行できます。ストアドプロシージャのスコープは限られているため、(例)3人のユーザーが同じストアドプロシージャを実行し、一時テーブルが混在しない場合でも、お互いを見ることはできません。

別のセッションまたは別のプロセスを実行しているユーザーと結果を共有する必要がない限り、Tempテーブルは完全に適切な方法です。

2
Brad D