Chr*_*row 9 sql-server concurrency ado.net connections temporary-tables
假设我们有 2 个完全不同的查询,它们引用了一个同名的临时表:
查询一 .... 操作:#tempTableName
查询二 .... 操作:#tempTableName
我对此进行了研究,发现“#temp 是一个本地临时表,因此对其他连接不可见”,但是我不确定连接在 SQL 查询上下文中的真正含义。SQL 是否认为每个运行的单独查询都有一个单独的“连接”,或者连接是否以某种方式共享?
具体来说,我的问题是“如果我的场景中的两个查询被同一个登录名访问会发生什么”,例如多个 .NET 应用程序使用相同的 .NET 连接字符串并同时访问数据库。如果我的场景中的两个查询同时运行,他们是否会潜在地访问同一个临时表?锁呢?我是否需要采取任何措施来防止在桌子上操作期间发生不必要的访问?
我看过这个答案,/sf/ask/32686321/,但是我真的需要像“假装我 6 岁”这样的解释,以便我我非常清楚在我的假设场景中发生了什么,就 SQL 查询究竟如何利用连接和确定独占访问等而言。任何可以让我完全掌握这一点的图表或资源指针都会很棒!
Sol*_*zky 13
本地临时对象由 Session 分隔。如果您同时运行两个查询,那么它们显然是两个完全独立的会话,您无需担心。登录无关紧要。如果您使用连接池,那也无所谓。本地临时对象(最常见的是表,还有存储过程)不会被其他会话看到。
虽然您的代码具有用于本地临时对象的单一通用名称,但 SQL Server 会在每个会话(以及如果需要,每个子进程)的每个对象名称后附加一个唯一字符串,以将它们分开。您可以通过在 SSMS 中运行以下查询来查看这一点:
CREATE TABLE #T (Col1 INT)
SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';
Run Code Online (Sandbox Code Playgroud)
您将看到类似于以下名称的内容(我从名称中间删除了大部分下划线以防止需要在此处滚动):
#T_______________00000000001F
Run Code Online (Sandbox Code Playgroud)
然后,在不关闭该查询选项卡的情况下,打开一个新的查询选项卡并粘贴相同的 2 个查询并执行它们。您现在应该会看到如下内容:
#T_______________00000000001F
#T_______________000000000020
Run Code Online (Sandbox Code Playgroud)
因此,每次您的代码引用 时#T,SQL Server 都会根据会话将其转换为正确的名称。这一切都是自动处理的:-)。
为了说明这一点。我曾在高度事务性(每秒数以千计的事务)并且是 SaaS(软件即服务)Web 应用程序上运行 24 / 7 的系统上工作。所有 T-SQL 代码都在存储过程中(意思是:相同的本地临时表名称每次执行该代码),我们很好地利用了本地临时表。作为一个 Web 应用程序,几乎所有连接的登录都是相同的,我们肯定使用了连接池。我们从来没有遇到任何问题,表明同名本地临时对象的任何跨会话访问。坦率地说,如果发生这种情况,我们会感到震惊并利用我们与 Microsoft 的支持合同来修复它。
关于本地临时表的其他注意事项:
虽然它们的名称是唯一的,但它们的依赖对象不是。您不能在临时表上创建触发器或外键,所以这实际上是关于主键、检查约束和默认约束。这意味着命名主键#PK_#T不会使其成为唯一名称,并在名称后附加一个幕后唯一 ID。如果您尝试此操作,您将收到“无法创建对象。对象已存在”。错误(好吧,假设多个并发执行相同的代码)。因此,如果本地临时表需要这 3 种对象类型中的任何一种,请内联创建依赖对象,以便它/它们将获得系统生成的名称,这些名称将是唯一的并且不会在会话之间发生冲突。
您无需担心索引名称,因为它们已经按[object_id].
鉴于您得到“无法创建对象。对象已存在。” 创建命名依赖对象时出现错误,这提出了一个好点,这个问题最常被忽视,关于“每个会话是否完全隔离本地临时对象”这个问题:如果其他会话可以看到本地临时表,那么该CREATE TABLE语句将得到错误,对吗?
本地临时表的一个细微差别(这也是上面#2 的一个松散的对立点)是,如果您在EXEC子进程启动之前创建的子进程(即)中引用本地临时表,它将能够看到(甚至修改)那个本地临时表。但是,如果该子进程创建另一个具有相同名称的临时表,则将有两个对象,末尾附加单独的唯一 ID,可通过短名称访问。我记得在某处读到没有保证引用#name在子流程中将始终解析为在子流程中创建的该对象的版本。因此,最好在有可能在嵌套存储过程调用链中执行的存储过程之间具有某些本地临时表名称的唯一性。