Lly*_*yle 2 .net sql ado.net sql-server-2005 dynamic-sql
我正在尝试对创建时间非常长的结果集执行许多不同的查询。为了获得性能提升,我希望使用一个临时表并且只在这个临时表上做很多查询。
看起来很标准。然而,我正在努力在动态 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
Run Code Online (Sandbox Code Playgroud)
小智 6
我知道这个帖子发布已经有一段时间了,但我相信答案很简单。
我推测您正在使用 MS Enterprise Library 访问数据库,这解释了为什么命令之间不存在临时表。当命令完成时,企业库明确关闭与数据库的连接(将其放回池中)。也就是说,除非您将命令放入事务中。如果您直接使用 ADO.NET(通过打开连接、构建和执行命令,然后关闭连接),您不会遇到这个问题(连接关闭时由您决定——这更危险)。下面是一些使用 MS 企业库和事务编写的代码(对不起,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.
Run Code Online (Sandbox Code Playgroud)
如果您要删除事务范围,则代码将在 Select count(*) 上失败,因为该表不再存在。指定范围保持命令调用之间的连接打开。
我希望这可以帮助别人。
尼尔。