Frage

Ich versuche, viele verschiedene Abfragen auf einer Ergebnismenge zu tun, die eine hat sehr große Erstellungszeit. Um Performance-Gewinne erhalten möchte ich eine temporäre Tabelle verwenden und nur tun viele Abfragen auf dieser temporären Tabelle.

Es scheint ziemlich Standard. Doch ich habe Schwierigkeiten diese temporäre Tabelle in dynamischen SQL zu teilen. Wie ich es, jedes Objekt SqlCommand führt in einem eigenen Thread und so die temporäre Tabelle ist in einem anderen Bereich zu verstehen -. So unzugänglich aus dem Abfrage-Thread macht

Ich habe versucht, eine globale temporäre Tabelle verwenden und das funktioniert gut, aber nicht ideal?

Wie kann ich eine lokale temporäre Tabelle zwischen dynamischen SQL-Abfragen teilen?

Meine Absicht:

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
War es hilfreich?

Lösung

Sie könnten versuchen, eine globale temporäre Tabelle mit (dh Verwendung ##MyTemp statt #MyTemp in Ihren Anfragen), mit diesem Vorbehalt :

  

Globale temporäre Tabellen sind   automatisch gelöscht, wenn die Sitzung   dass erstellt die Tabellenende und all   andere Aufgaben haben aufgehört Referenzierung   Sie. Der Zusammenhang zwischen einer Aufgabe   und eine Tabelle aufrechterhalten wird nur für die   Leben eines einzelnen Transact-SQL   Aussage. Dies bedeutet, dass eine globale   temporäre Tabelle wird auf die abgenommene   Beendigung des letzten Transact-SQL   Anweisung, die aktiv war   Verweisen auf die Tabelle, wenn die   Erzeugen der Sitzung beendet.


EDIT:. Oops, verpasste die Tatsache, dass man bereits globale temporäre Tabellen versucht haben,

Wie wäre es, alle Ihre Logik in einem einzigen gespeicherten Prozedur zu bewegen, die die temporäre Tabelle erstellt / auffüllt und dann die Abfragen ausgeführt wird und mehrere Result an den Client-Code zurückgibt?

Andere Tipps

Ich weiß, es ist eine Weile her, seit diesem geschrieben wurde, aber die Antwort, glaube ich, ist ganz einfach.

Ich vermute, Sie die MS Enterprise Library verwenden die Datenbank zuzugreifen, erklärt dies, warum die temporäre Tabelle zwischen den Befehlen nicht vorhanden ist. Die Enterprise Library schließt EXPLIZIT die Verbindung zum DB (bringt es zurück in den Pool), wenn der Befehl ausgeführt. Das heißt, wenn Sie die Befehle in einer Transaktion setzen. Wenn Sie ADO.NET direkt verwenden (durch Öffnen der Verbindung, den Aufbau und die Befehle ausführt, dann die Verbindung geschlossen wird) bekommt man nicht dieses Problem (es ist an Ihnen, wenn die Verbindung geschlossen wird - was riskanter ist). Hier ist etwas geschrieben Code der MS Enterprise Library verwenden und eine Transaktion (sorry, 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.

Wenn Sie den Transaktionsbereich herauszunehmen, würde der Code nicht auf der SELECT COUNT (*) als die Tabelle nicht mehr vorhanden ist. den Umfang Angeben hält die Verbindung offen zwischen Befehl Anrufe.

Ich hoffe, das hilft jemand.

Neil.

Was aus Ihrer Frage fehlt, ist der Lebenszyklus der erstellten Tabelle. Wenn Sie es haben sich für eine Weile kleben, dann ist es nicht ganz temporäre Tabelle, ist es ein Arbeitstisch, die Sie bevölkern und verwenden. Ich würde nicht eine temporäre Tabelle verwendet überhaupt, nur eine regelmäßige Tabelle, die sonst durch den SELECT INTO und wurde von jedem erstellt wird, bis es gelöscht wird (wenn überhaupt).

Eine Alternative, die ich erfolgreich eingesetzt habe, ist, einen Arbeitstisch in Tempdb zu erstellen, und verwenden Sie es, als ob es sich um eine globale temporäre Tabelle ist (zum Beispiel „TempDb.dbo.MyTable“). Denken Sie daran, dass die Benutzertabellen werden gelöscht, wenn SQL Server neu gestartet wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top