在数据库表中使用 SPID(而不是表变量)

out*_*jet 8 sql-server stored-procedures sql-server-2016 enterprise-edition table-variable

用于预订事物的事务性数据库...

我们的供应商被要求用@tablevariables 替换#temptables(因为编译锁很重),但他们用一个实际的表来替换,该表将SPID 添加为一列,以确保存储过程只作用于适用的行。

您认为这种操作方法有什么风险吗?在所有事务都被隔离在他们自己的事务中之前......我担心我们最终可能会锁定这个表,但他们的意见是 SQL 使用行级锁定,这不会创建更多的锁。

SQL Server 版本:2016 企业版 - 13.0.5216.0


CREATE TABLE dbo.qryTransactions (
    ID int IDENTITY (0,1) NOT NULL CONSTRAINT pk_qryTransactions PRIMARY KEY CLUSTERED,
    spid int NOT NULL,
    OrderID int,
    ItemID int,
    TimeTransactionStart datetime,
    TimeTransactionEnd datetime,
...other fields
    )

CREATE INDEX idx_qryTransactions_spidID ON qryTransactions (spid, ID) INCLUDE (ItemID, OrderID, TimeTransactionStart, TimeTransactionEnd)

Run Code Online (Sandbox Code Playgroud)

Han*_*non 8

在我看来,使用@@SPID类似的方法是在自找麻烦。

会话 ID 经常被重用;一旦用户连接注销,该会话 ID 就可以再次使用,并且很可能被下一个尝试连接的会话使用。

为了使其至少半可靠地工作,您需要一个登录触发器来清除表中具有相同@@SPID. 如果这样做,您可能会看到使用该@@SPID列对表进行了大量锁定。

SQL Server 确实使用行锁定,但它也使用页锁定和表锁定。当然,您可以通过良好的索引来缓解这种情况,但这对我来说仍然是一种反模式。

如果存储过程是用于访问受影响表的唯一方法,您可以调查使用应用程序锁,通过sp_getapplock基本上序列化对相关部分的访问。sp_getapplock 的文档在这里Erik Darling有一篇关于它的有趣帖子在这里


mar*_*uso 5

比评论块更杂乱无章......并且想要突出显示OP针对Ray的回答所做的评论:

  • parent proc (Common_InsertOrders_1) 创建临时表
  • 子 proc (InsertOrders) 查询临时表
  • 正在看到子 proc 的编译锁(InsertOrders)

稍微切线一分钟......在这种情况下会发生什么是Sybase ASE......

  • 每个临时表都有一个唯一的对象 id(当然,对象 id 可以在某个时候重新使用,但这种情况很少见,而且对于并发会话肯定不会发生)
  • Sybase ASE 通常会在每次执行子进程时强制重新编译,因为临时表的对象 ID发生了变化
  • 如果 Sybase ASE 发现临时表的结构在存储的 proc 调用之间发生了变化(例如,不同的列数、不同的列名/数据类型/可空性),它也会强制重新编译子 proc
  • 较新版本的 Sybase ASE 有一个配置(有效地)告诉编译器忽略临时表对象 ID 的更改,从而消除子 proc 的重新编译(注意:如果表结构更改,重新编译仍将发生)

回到OP的问题(子进程上的编译锁)......

  • Sybase ASE 行为的一些痕迹是否有可能仍然存在于 SQL Server 中(从这两个产品是豆荚中的豌豆开始)?
  • 是否有任何 SQL Server 配置可以减少(消除?)子进程的重新编译(如果由于对象 ID 的变化)?
  • OP 可以验证父进程是否每次都创建具有相同结构/DDL 的临时表吗?

至于使用带有@@SPID 的单个永久表来区分会话之间的行的想法......去过那里,看到...... yuck ; 反复出现的问题:

  • 如何/何时清理孤立行
  • 如果存在孤立数据(或在清理孤立数据期间,例如,删除 @@SPID=10 但存在与 @ 的新/当前/活动会话),则数据库引擎重新使用 @@SPID 可能会导致数据准确性问题@SPID=10 => 清理删除了太多数据)
  • 从行锁升级到页/表锁的可能性
  • 如果表有索引,则在更新索引时可能会 (b) 锁定
  • 根据表所在的数据库,您可能会查看更多写入日志设备的活动(在 Sybase ASE 中,可以有效地禁用 tempdb 中的日志记录)
  • 甚至行级(独占)锁也可以阻塞其他会话(取决于隔离级别以及会话是否可以扫描过去/跳过所述独占锁)

我想回去(重新)调查根本问题(子进程上的重新编译锁),看看是否有办法减少(消除?)所说的编译锁。[不幸的是,我在这些问题上的 SQL Server 知识是...... NULL ...所以会对一些 SQL Server 编译器专家的输入感兴趣。]