2

作成時間が非常に長い結果セットに対して、さまざまなクエリを実行しようとしています。パフォーマンスを向上させるために、一時テーブルを使用し、この一時テーブルに対して多くのクエリを実行したいと考えています。

かなり標準的なようです。それでも、この一時テーブルを動的 SQL で共有するのに苦労しています。私が理解しているように、各 SqlCommand オブジェクトは独自のスレッドで実行されるため、一時テーブルは異なるスコープにあり、クエリスレッドからアクセスできなくなります。

グローバル一時テーブルを使用してみましたが、うまく機能しますが、理想的ではありませんか?

動的 SQL クエリ間でローカル一時テーブルを共有するにはどうすればよいですか?

私の意図:

using (var conn = new SqlClient.SqlConnection("..."))
{
    // Creation involes many table joins in reality
    String creationScript = "SELECT * FROM FooTable INTO #MyTemp";
    SqlCommand createTempTbl = new SqlCommand(creationScript, conn);
    createTempTbl.ExecuteNonQuery();

    String query1 = "SELECT * FROM #MyTemp where id=@id";
    SqlCommand query1Comm = new SqlCommand(query1, conn);
    query1Comm.Parameters.Add("@id", ...);

    String query2 = "SELECT * FROM #MyTemp where name=@name";
    SqlCommand query2Comm = new SqlCommand(query2, conn);
    query2Comm.Parameters.Add("@name", ...);

    // And so on the queries go

} // Now want #MyTemp to be destroyed
4

4 に答える 4

6

これが投稿されてからしばらく経っていることはわかっていますが、答えは非常に簡単だと思います。

MS Enterprise Library を使用してデータベースにアクセスしていると思います。これは、コマンド間に一時テーブルが存在しない理由を説明しています。Enterprise Library は、コマンドが終了すると、明示的に DB への接続を閉じます (プールに戻します)。つまり、コマンドをトランザクションに入れない限りです。ADO.NET を直接使用する場合 (接続を開き、コマンドをビルドして実行し、接続を閉じる)、この問題は発生しません (接続をいつ閉じるかはユーザー次第であり、リスクが高くなります)。以下は、MS Enterprise Library とトランザクション (申し訳ありませんが、VB.NET) を使用して記述されたコードです。

' Get a reference to the database
Dim sqlNET As New Sql.SqlDatabase("*Your Connection String Here...*")

' Specify the transaction options
Dim oTranOpt As TransactionOptions = New TransactionOptions
' What type of isolation the transaction should have (V. Important):
oTranOpt.IsolationLevel = IsolationLevel.ReadUncommitted ' This one doesn't place locks on DB but allows dirty reads
' How long the transaction has to complete before implicitly failing (h,m,s):
oTranOpt.Timeout = New TimeSpan(0, 0, 30)

' Start the scope of the transation
Using oTranScope As TransactionScope = New TransactionScope(TransactionScopeOption.Required, oTranOpt)

    ' Create the connection to the DB. Not abs. necessary. EL will create one but best to do so.
    Using Conn As Common.DbConnection = sqlNET.CreateConnection

        ' Create a Temp Table
        sqlNET.ExecuteNonQuery(CommandType.Text, "SELECT * INTO #MyTemp FROM FooTable")

        ' Get results from table, e.g.
        Dim intCount As Integer = sqlNET.ExecuteScalar(CommandType.Text, "Select Count(*) from #MyTemp")

        MsgBox(intCount)

        ' Flag transaction as successful (causes a commit when scope is disposed)
        oTranScope.Complete()

    End Using ' Disposes the connection

End Using ' If this point is reached without hitting the oTranScope.Complete - the transaction is rolled back and locks, if any, are released.

トランザクション スコープを削除すると、テーブルが存在しなくなるため、コードは Select カウント (*) で失敗します。スコープを指定すると、コマンド呼び出し間で接続が開かれたままになります。

これが誰かに役立つことを願っています。

ニール。

于 2010-09-02T09:43:48.163 に答える
2

グローバル一時テーブルを使用してみることができます (つまり、クエリ##MyTempではなく使用します)。ただし、次の注意事項があります。#MyTemp

テーブルを作成したセッションが終了し、他のすべてのタスクがそれらの参照を停止すると、グローバル一時テーブルは自動的に削除されます。タスクとテーブルの間の関連付けは、1 つの Transact-SQL ステートメントが存続している間だけ維持されます。これは、作成セッションの終了時にテーブルをアクティブに参照していた最後の Transact-SQL ステートメントの完了時に、グローバル一時テーブルが削除されることを意味します。


編集:おっと、既にグローバル一時テーブルを試したという事実を見逃しました。

すべてのロジックを単一のストアド プロシージャに移動して、一時テーブルを作成/設定し、クエリを実行して複数の結果セットをクライアント コードに返すのはどうでしょうか?

于 2009-02-16T00:31:43.257 に答える
1

あなたの質問に欠けているのは、作成されたテーブルのライフサイクルです。しばらくそのままにしておく場合、それは完全な一時テーブルではなく、データを入力して使用する作業テーブルです。私は一時テーブルをまったく使用しません。SELECT INTO によって作成され、削除されるまで他のすべての人が使用する通常のテーブルだけです。

于 2009-02-16T00:46:55.217 に答える
0

私がうまく使用した別の方法は、TempDbで作業テーブルを作成し、それをグローバル一時テーブル(たとえば、「TempDb.dbo.MyTable」)であるかのように使用することです。SQL Serverの再起動時に、ユーザーテーブルが削除されることに注意してください。

于 2009-06-16T18:54:28.437 に答える