condivisione SQL tabella temporanea in diversi lettori SQL
-
23-08-2019 - |
Domanda
che sto cercando di fare molte domande differenti su una lista di prodotti che ha una molto di grandi dimensioni ora di creazione. Per ottenere miglioramenti delle prestazioni desidero utilizzare una tabella temporanea e solo fare molte domande su questo tabella temporanea.
Sembra piuttosto standard. Eppure io sto lottando per condividere questo tabella temporanea in SQL dinamico. A quanto mi risulta, ciascun oggetto SqlCommand eseguito nel proprio filo e quindi la tabella temporanea è in un ambito diverso -. Rendendo così inaccessibile dal filo di query
Ho provato ad utilizzare una tabella temporanea globale e che funziona benissimo, ma non è l'ideale?
Come posso condividere una tabella temporanea locale tra le query SQL dinamiche?
Il mio intento:
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
Soluzione
Si potrebbe provare a utilizzare una tabella temporanea globale (ad esempio, l'uso ##MyTemp
piuttosto che #MyTemp
nelle query), con questo avvertimento :
tabelle temporanee globali sono automaticamente caduto quando la sessione che ha creato le estremità della tabella e tutti altri compiti hanno smesso di riferimento loro. L'associazione tra un compito e una tabella viene fornita solo per la la vita di un singolo Transact-SQL dichiarazione. Ciò significa che a livello globale tabella temporanea è caduto al completamento dell'ultimo Transact-SQL dichiarazione che era attivamente riferimento alla tabella quando la creando seduta è terminata.
EDIT:. Spiacenti, perse il fatto che hai già provato tabelle temporanee globali
Come di spostare tutta la tua logica in un unico stored procedure che crea / popola la tabella temporanea e quindi esegue le query e restituisce più gruppi di risultati per il codice del client?
Altri suggerimenti
Lo so che è un po 'che questa è stata pubblicata, ma la risposta, credo, è abbastanza semplice.
Suppongo si utilizza il MS Enterprise Library per accedere al database, questo spiega perché la tabella temporanea non esiste tra i comandi. La Biblioteca Enterprise chiude esplicitamente la connessione al DB (lo rimette in piscina) Al termine di comando. A meno che non si mette i comandi in una transazione. Se si utilizza ADO.NET direttamente (con l'apertura del collegamento, la costruzione e l'esecuzione dei comandi, quindi chiudere la connessione) non si ottiene questo problema (che è fino a quando la connessione si chiude - che è più rischioso). Ecco alcuni codice scritto utilizzando il MS Enterprise Library e una transazione (mi dispiace, 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.
Se si dovesse prendere la portata dell'operazione, il codice fallirebbe sul conteggio Select (*) come la tabella non esiste più. Specificando la portata mantiene la connessione aperta tra le chiamate di comando.
Spero che questo aiuta qualcuno.
Neil.
Ciò che manca dalla tua domanda è il ciclo di vita della tabella creata. Se lo avrete attaccare in giro per un po ', allora non è piuttosto una tabella temporanea, si tratta di un tavolo di lavoro che si popolano e utilizzare. Non vorrei usare una tabella temporanea a tutti, solo una tabella normale che viene creato dal SELECT INTO e usate da tutti gli altri fino a quando non viene scartato (se mai).
Un'alternativa che ho usato con successo è quello di creare un tavolo di lavoro in tempdb, e usarlo come se fosse una tabella temporanea globale (ad esempio, "TempDb.dbo.MyTable"). Ricordate che l'utente le tabelle vengono eliminate quando SQL Server viene riavviato.