SQL 临时表在不同的 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
I am trying to do many different queries on a result set which has a very large creation time. To get performance gains I wish to use a temp table and just do many queries on this temp table.
Seems pretty standard. Yet I am struggling to share this temp table in dynamic SQL. As I understand it, each SqlCommand object executes in its own thread and so the temp table is in a different scope - thus making it inaccessible from the query thread.
I tried using a global temporary table and that works great, but not ideal?
How can I share a local temporary table between dynamic SQL queries?
My intent:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我知道这篇文章发布已经有一段时间了,但我相信答案很简单。
我猜测您正在使用 MS Enterprise Library 来访问数据库,这解释了为什么命令之间不存在临时表。 当命令完成时,企业库明确关闭与数据库的连接(将其放回到池中)。 也就是说,除非您将命令放入事务中。
如果您直接使用 ADO.NET(通过打开连接、构建并执行命令,然后关闭连接),则不会出现此问题(由您决定连接何时关闭 - 这风险更大)。
以下是使用 MS 企业库和事务(抱歉,VB.NET)编写的一些代码:
如果要删除事务范围,则代码将在 Select count(*) 上失败,因为表不再存在。 指定范围使命令调用之间的连接保持打开状态。
我希望这可以帮助别人。
尼尔.
I know it's a while since this one was posted but the answer, I believe, is quite simple.
I surmise you are using the MS Enterprise Library to access the database, this explains why the temp table doesn’t exist between commands. The Enterprise Library EXPLICITLY closes the connection to the DB (puts it back in the pool) when the command finishes. That is, UNLESS you put the commands into a transaction.
If you use ADO.NET directly (by opening the connection, building and executing the commands, then closing the connection) you do not get this problem (it’s up to you when the connection closes – which is more risky).
Here is some code written using the MS Enterprise Library and a transaction (sorry, VB.NET):
If you were to take out the transaction scope, the code would fail on the Select count(*) as the table no longer exists. Specifying the scope keeps the connection open between command calls.
I hope this helps someone.
Neil.
您可以尝试使用全局临时表(即,在查询中使用
##MyTemp
而不是#MyTemp
),有此警告:编辑:糟糕,错过了您已经尝试过全局临时表的事实。
如何将所有逻辑移至单个存储过程中,该存储过程创建/填充临时表,然后运行查询并向客户端代码返回多个结果集?
You could try using a global temporary table (ie, use
##MyTemp
rather than#MyTemp
in your queries), with this caveat:EDIT: Oops, missed the fact that you've already tried global temp tables.
How about moving all of your logic into a single stored procedure which creates/populates the temp table and then runs the queries and returns multiple resultsets to the client code?
您的问题缺少的是创建的表的生命周期。 如果您将其保留一段时间,那么它不完全是临时表,而是您填充和使用的工作表。 我根本不会使用临时表,只是一个由 SELECT INTO 创建并由其他人使用的常规表,直到它被删除(如果有的话)。
What is missing from your question is the lifecycle of the created table. If you will have it sticking around for a while, then it is not quite a temp table, it is a work table that you populate and use. I would not use a temp table at all, just a regular table that gets created by the SELECT INTO and used by everyone else until it gets dropped (if ever).
我成功使用的另一种方法是在 TempDb 中创建一个工作表,并像使用全局临时表一样使用它(例如“TempDb.dbo.MyTable”)。 请记住,当 SQL Server 重新启动时,用户表将被删除。
An alternative that I've used successfully is to create a work table in TempDb, and use it as if it is a global temp table (e.g., "TempDb.dbo.MyTable"). Remember that user tables are dropped when SQL Server reboots.