Совместное использование временной таблицы SQL для разных читателей SQL - PullRequest
1 голос
/ 16 февраля 2009

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

Кажется довольно стандартным. Тем не менее, я изо всех сил пытаюсь использовать эту временную таблицу в динамическом 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

Ответы [ 4 ]

4 голосов
/ 02 сентября 2010

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

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

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

Надеюсь, это кому-нибудь поможет.

Нил.

2 голосов
/ 16 февраля 2009

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

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


РЕДАКТИРОВАТЬ: Упс, пропустил тот факт, что вы уже пробовали глобальные временные таблицы.

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

1 голос
/ 16 февраля 2009

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

0 голосов
/ 16 июня 2009

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

...