2009-02-16 10 views
1

J'essaie de faire beaucoup de requêtes différentes sur un ensemble de résultats qui a un très grand temps de création. Pour obtenir des gains de performances, je souhaite utiliser une table temporaire et effectuer de nombreuses requêtes sur cette table temporaire.Partage de table temporaire SQL entre différents lecteurs SQL

Semble assez standard. Pourtant, j'ai du mal à partager cette table temporaire en SQL dynamique. Si je comprends bien, chaque objet SqlCommand s'exécute dans son propre thread et donc la table temporaire est dans une portée différente - le rendant ainsi inaccessible à partir du thread de la requête.

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

Comment puis-je partager une table temporaire locale entre des 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 [email protected]"; 
    SqlCommand query1Comm = new SqlCommand(query1, conn); 
    query1Comm.Parameters.Add("@id", ...); 

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

    // And so on the queries go 

} // Now want #MyTemp to be destroyed 

Répondre

2

Vous pouvez essayer d'utiliser une table temporaire globale (c.-à-utiliser ##MyTemp plutôt que #MyTemp dans vos requêtes), with this caveat:

tables temporaires globales sont automatiquement abandonnées lorsque la session qui a créé la table se termine et toutes les autres tâches ont cessé de référencer eux. L'association entre une tâche et une table est conservée uniquement pour la durée de vie d'une seule instruction Transact-SQL . Cela signifie qu'une table temporaire est supprimée à l'achèvement de la dernière instruction Transact-SQL qui était activement faisant référence à la table lorsque la session de création s'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 toute votre logique dans une seule procédure stockée qui crée/remplit la table temporaire, puis exécute les requêtes et renvoie plusieurs jeux de résultats au code client?

+0

La question dit que l'affiche a déjà essayé que ... –

+0

Je * vraiment * ne veux pas aller sproc pour le moment. J'essaie de tester mon BL. Et j'ai besoin d'avoir le résultat à la DB, je suis allé sur cette route et la mémoire a été durement touchée. – Llyle

+0

@vanslly, je ne suis pas sûr de savoir ce que vous entendez par "avoir le jeu de résultats strictement à la DB", mais si vous ne voulez pas utiliser un sproc à ce moment-là, la seule option réaliste que je peux penser est une table temporaire globale. – LukeH

1

Ce qui manque à votre question, c'est le cycle de vie de la table créée. Si vous voulez que ça dure un moment, alors ce n'est pas tout à fait une table temporaire, c'est une table de travail que vous remplissez et utilisez. Je n'utiliserais pas du tout une table temporaire, juste une table normale créée par SELECT INTO et utilisée par tout le monde jusqu'à ce qu'elle soit supprimée (si jamais).

+0

Comme j'ai essayé d'indiquer avec le code d'intention, je souhaite que la table persiste * seulement * tant que cela prend pour compléter toutes les requêtes qui partagent une connexion. Le nombre de requêtes consécutives peut facilement dépasser 65k +, et donc le besoin de la table temporaire. – Llyle

0

Une alternative que j'ai utilisée avec succès est de créer une table de travail dans TempDb, et de l'utiliser comme s'il s'agissait d'une table temporaire globale (par exemple, "TempDb.dbo.MyTable"). N'oubliez pas que les tables utilisateur sont supprimées lors du redémarrage de SQL Server.

4

Je sais que ça fait un moment que celui-ci a été posté mais la réponse, je crois, est assez simple.

Je suppose que vous utilisez MS Enterprise Library pour accéder à la base de données, ce qui explique pourquoi la table temporaire n'existe pas entre les commandes. La bibliothèque d'entreprise ferme EXPLICITEMENT la connexion à la base de données (la remet dans le pool) lorsque la commande se termine. C'est-à-dire, SAUF si vous mettez les commandes dans une transaction. Si vous utilisez ADO.NET directement (en ouvrant la connexion, en construisant et en exécutant les commandes, puis en fermant la connexion) vous n'obtenez pas ce problème (c'est à vous de voir quand la connexion se ferme - ce qui est plus risqué). 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 le compte Select (*) car la table n'existe plus. La spécification de la portée maintient la connexion ouverte entre les appels de commande.

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

Neil.

Questions connexes