Question

Je suis en train de faire beaucoup de requêtes différentes sur un jeu de résultats qui a une très grand temps de création. Pour obtenir des gains de performance que je souhaite utiliser une table temporaire et juste faire de nombreuses requêtes sur cette table temporaire.

Semble assez standard. Pourtant, je me bats pour partager cette table temporaire dans SQL dynamique. Si je comprends bien, chaque objet SqlCommand exécute dans son propre thread et donc la table temporaire est dans une portée différente -. Rendant ainsi inaccessible à partir du fil de requête

J'ai essayé d'utiliser une table temporaire globale et qui fonctionne très bien, mais pas idéal?

Comment puis-je partager une table temporaire locale entre les requêtes SQL dynamiques?

Mon intention:

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
Était-ce utile?

La solution

Vous pouvez essayer d'utiliser une table temporaire globale (utilisation ##MyTemp plutôt que #MyTemp dans vos requêtes), avec cette mise en garde :

  

Les tables temporaires globales sont   automatiquement supprimé lorsque la session   qui a créé les extrémités de la table et tout   d'autres tâches ont arrêté le référencement   leur. L'association entre une tâche   et une table est maintenue uniquement pour la   la vie d'un seul Transact-SQL   déclaration. Cela signifie qu'un global   table temporaire est abandonnée au   l'achèvement de la dernière Transact-SQL   déclaration qui a été activement   référence à la table lorsque le   création de la session est terminée.


EDIT:. Oops, a raté le fait que vous avez déjà essayé des tables temporaires globales

Que diriez-vous de déplacer tous votre logique en une seule procédure stockée qui crée / renseigne la table temporaire et exécute ensuite les requêtes et renvoie plusieurs resultsets au code client?

Autres conseils

Je sais qu'il est un moment que celui-ci a été publié, mais la réponse, je crois, est assez simple.

Je présume que vous utilisez le MS Enterprise Library pour accéder à la base de données, ce qui explique pourquoi la table temporaire n'existe pas entre les commandes. L'Enterprise Library ferme EXPLICITE la connexion au DB (le remet dans la piscine) lorsque les finitions de commande. Autrement dit, si vous ne mettez les commandes dans une transaction. Si vous utilisez ADO.NET directement (en ouvrant la connexion, la construction et l'exécution des commandes, puis fermer la connexion) vous ne recevez pas ce problème (il est à vous lorsque la connexion se ferme - ce qui est plus risquée). Voici un code écrit en utilisant la MS Enterprise Library et une transaction (désolé, 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.

Si vous deviez prendre la portée de la transaction, le code échouerait sur le Select count (*) que la table n'existe plus. Spécification du champ d'application maintient la connexion ouverte entre les appels de commande.

J'espère que cela aide quelqu'un.

Neil.

Qu'est-ce qui manque à votre question est le cycle de vie de la table créée. Si vous l'aurez coller autour pendant un certain temps, alors il est pas tout à fait table temporaire, il est une table de travail que vous enrichissez et utilisez. Je ne voudrais pas utiliser une table temporaire du tout, juste une table régulière qui est créée par le SELECT INTO et utilisé par tout le monde jusqu'à ce qu'il soit abandonné (si jamais).

Une alternative que je l'ai utilisé avec succès est de créer une table de travail dans tempdb, et l'utiliser comme si elle est une table temporaire globale (par exemple, « TempDb.dbo.MyTable »). Rappelez-vous que les tables utilisateur sont supprimées lorsque redémarrages SQL Server.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top