Pregunta

Estoy intentando hacer muchas consultas diferentes en un conjunto de resultados que tiene un muy gran tiempo de creación.Para obtener ganancias de rendimiento, deseo usar una tabla temporal y simplemente hacer muchas consultas en esta tabla temporal.

Parece bastante estándar.Sin embargo, estoy luchando por compartir esta tabla temporal en SQL dinámico.Según tengo entendido, cada objeto SqlCommand se ejecuta en su propio subproceso, por lo que la tabla temporal tiene un alcance diferente, lo que la hace inaccesible desde el subproceso de consulta.

Intenté usar una tabla temporal global y funciona muy bien, ¿pero no es ideal?

¿Cómo puedo compartir una tabla temporal local entre consultas SQL dinámicas?

Mi intención:

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
¿Fue útil?

Solución

Se podría tratar de usar una tabla temporal global (es decir, el uso ##MyTemp en lugar de #MyTemp en sus consultas), con esta advertencia :

  

Las tablas temporales globales son   caído de forma automática cuando la sesión   que creó los extremos de mesa y todos   otras tareas han dejado de referencia   ellos. La asociación entre una tarea   y una mesa se mantiene sólo para el   vida de un solo Transact-SQL   declaración. Esto significa que un mundial   tabla temporal se deja caer en el   finalización de la última Transact-SQL   declaración que fue activamente   referencia a la tabla cuando el   Creando terminó la sesión.


EDIT:. Vaya, se perdió el hecho de que ya haya probado tablas temporales globales

¿Qué hay de mover toda la lógica en un solo procedimiento almacenado que crea / rellena la tabla temporal y luego ejecuta las consultas y devuelve varios conjuntos de resultados para el código de cliente?

Otros consejos

Sé que es un tiempo desde que éste se publicó, pero la respuesta, creo, es bastante simple.

Conjeturo que está utilizando la Biblioteca MS Enterprise para acceder a la base de datos, esto explica por qué la tabla temporal no existe entre los comandos. El Enterprise Library cierra explícitamente la conexión a la base de datos (lo pone de nuevo en la piscina) cuando termina el comando. Es decir, a menos que poner los comandos en una transacción. Si utiliza ADO.NET directamente (mediante la apertura de la conexión, la construcción y ejecución de los comandos, a continuación, cerrar la conexión) no obtiene este problema (que depende de usted cuando se cierra la conexión - que es más arriesgado). Aquí hay un código escrito usando el Enterprise Library MS y una transacción (lo siento, 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 se va a sacar el ámbito de transacción, el código podría fallar en la Selección de la cuenta (*) como la tabla ya no existe. Especificando el alcance mantiene la conexión abierta entre llamadas de comandos.

Espero que esto ayude a alguien.

Neil.

Lo que falta en su pregunta es el ciclo de vida de la tabla creada. Si va a tener que quedarse allí por un tiempo, entonces no es absolutamente una tabla temporal, se trata de una mesa de trabajo que se puede rellenar y utilizar. Yo no usaría una tabla temporal en absoluto, sólo una mesa normal que se crea por el SELECT INTO y usada por todos los demás hasta que se cae (o nunca).

Una alternativa que he utilizado con éxito es la creación de una mesa de trabajo en tempdb, y utilizarlo como si se trata de una tabla temporal global (por ejemplo, "TempDb.dbo.MyTable"). Recuerde que el usuario tablas se eliminan cuando se reinicia SQL Server.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top