Совместное использование временной таблицы SQL различными средствами чтения SQL

StackOverflow https://stackoverflow.com/questions/551915

Вопрос

Я пытаюсь выполнить много различных запросов к результирующему набору, который имеет очень большое время создания.Чтобы получить прирост производительности, я хочу использовать временную таблицу и просто выполнять множество запросов к этой временной таблице.

Кажется довольно стандартным.Тем не менее, я изо всех сил пытаюсь поделиться этой временной таблицей в динамическом SQL.Насколько я понимаю, каждый объект SqlCommand выполняется в своем собственном потоке, и поэтому временная таблица находится в другой области видимости, что делает ее недоступной из потока запросов.

Я пробовал использовать глобальную временную таблицу, и это отлично работает, но не идеально?

Как я могу совместно использовать локальную временную таблицу между динамическими SQL-запросами?

Мое намерение:

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
Это было полезно?

Решение

Вы могли бы попробовать использовать глобальную временную таблицу (т. Е. Использовать ##MyTemp вместо того , чтобы #MyTemp в ваших запросах), с этим предостережением:

Глобальные временные таблицы автоматически удаляются при завершении сеанса , который создал таблицу, и все другие задачи перестали ссылаться на них.Связь между задачей и таблицей поддерживается только в течение срока службы одного оператора Transact-SQL .Это означает, что глобальная временная таблица удаляется при завершении последнего оператора Transact-SQL , который активно ссылался на таблицу, когда закончился сеанс создания. Это означает, что глобальная временная таблица удаляется при завершении последнего оператора Transact-SQL, который активно ссылался на таблицу, когда закончился сеанс создания.


Редактировать: Упс, пропустил тот факт, что вы уже пробовали глобальные временные таблицы.

Как насчет переноса всей вашей логики в единую хранимую процедуру, которая создает / заполняет временную таблицу, а затем выполняет запросы и возвращает несколько наборов результатов в клиентский код?

Другие советы

Я знаю, что прошло много времени с тех пор, как это сообщение было опубликовано, но ответ, я полагаю, довольно прост.

Я предполагаю, что вы используете библиотеку MS Enterprise для доступа к базе данных, это объясняет, почему временная таблица не существует между командами.Корпоративная библиотека ЯВНО закрывает соединение с базой данных (помещает его обратно в пул) после завершения выполнения команды.То есть, ЕСЛИ ТОЛЬКО вы не вставите команды в транзакцию.Если вы используете ADO.NET напрямую (открывая соединение, создавая и выполняя команды, затем закрывая соединение), вы не сталкиваетесь с этой проблемой (это зависит от вас, когда соединение закрывается, что более рискованно).Вот некоторый код, написанный с использованием библиотеки MS Enterprise и транзакции (извините, 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.

Если бы вы удалили область транзакции, код потерпел бы неудачу при подсчете выбора (*), поскольку таблица больше не существует.Указание области сохраняет соединение открытым между вызовами команд.

Я надеюсь, что это кому-то поможет.

Нил.

Чего не хватает в вашем вопросе, так это жизненного цикла созданной таблицы.Если она останется у вас на некоторое время, то это не совсем временная таблица, это рабочая таблица, которую вы заполняете и используете.Я бы вообще не использовал временную таблицу, просто обычную таблицу, которая создается SELECT INTO и используется всеми остальными до тех пор, пока она не будет удалена (если вообще когда-либо).

Альтернативой, которую я успешно использовал, является создание рабочей таблицы в базе данных TempDb и использование ее как глобальной временной таблицы (например, "TempDb.dbo.MyTable").Помните, что пользовательские таблицы удаляются при перезагрузке SQL Server.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top