【发布时间】:2021-11-27 22:14:04
【问题描述】:
我遇到了与多查询事务有关的非常奇怪的事件。在 SQL Server 从 2008 年更新到 2016 年之后(我们的主机没有发出警告),我们在数据发布到 API 后开始删除数据。奇怪的是,有些数据到了,有些没有。
为了保护完整性,所有查询都连接在一个事务中。可以创建记录,然后在以后更新。它们的格式类似于:
DELETE FROM table_1 WHERE parentID = 123 AND col2 = 321;
DELETE FROM table_2 WHERE parentID = 123 AND col2 = 321;
-- etc
INSERT INTO table_1 (parentID, col2, etc) VALUES (123, 321, 123456);
INSERT INTO table_2 (parentID, col2, etc) VALUES (123, 321, 654321);
-- etc
可能有数百行正在执行。由于设计原因,相关记录没有唯一 ID,因此执行查询的最高效方式是首先删除匹配的记录,然后重新插入它们。循环遍历记录并检查是否存在是唯一的其他选择(据我所知),而且有这么多的记录会很昂贵。
无论如何,我一直在努力寻找这种数据丢失的原因,这似乎是随机的。我有 sql 查询的日志,所以我知道它们的格式正确并且所有数据都完好无损。最后,我唯一能想到的就是将 DELETE 查询分离到一个单独的事务中并首先执行*。这似乎解决了问题。
问。有谁知道这些查询是否可以按照它们出现的顺序执行?你有没有更好的方法来编写这些交易?
* 我不一定喜欢这个解决方案,因为删除查询是我想要交易的主要原因。如果在第二个事务期间发生错误,则所有较旧的匹配记录都已删除,但永远不会保存较新的版本。生活在边缘......
附:我遇到的另一个问题,这可能是由于我对平台的无知,当我试图用BEGIN TRAN; 和COMMIT TRAN; 将这些查询括起来时,在此脚本完成后立即,同一线程中的任何后续查询都挂了大约20-30秒左右。我究竟做错了什么?如果一次执行所有查询,我真的需要这些动词吗?
【问题讨论】:
-
您可能希望在
(parentID, col2)上建立一个聚集索引,此外,您应该考虑将所有更改转储到一个临时表或表值参数中,并执行单个连接delete和连接update。是的,如果您没有事务,那么每个批次都可能相互干扰,事务会创建锁以防止这种情况发生,从而导致阻塞 -
谢谢,聚集索引是个好主意(该应用程序是旧的,用 ASP Classic 编写,在生产大约 7 年后即将停产)。就 TSQL 而言,TVP 可能高于我的薪酬等级,但我一定会调查一下。
-
TVP 非常简单且非常有用,但您无法强迫经典 ASP 了解它们是什么。
-
再次考虑使用聚集索引时,拥有它们会很棒,但在 MSN 文档中,有几个非常严重的警告要在已经包含大量数据的表上创建它们。他们文档中的这一行总结了这一点:在大型表上构建索引的首选方法是从聚集索引开始,然后构建任何非聚集索引。
-
那是因为聚集键是每个非聚集索引的一部分,所以非聚集索引也必须重建;这是一次性操作,因此请计划在非工作时间或低使用时间进行,如果您使用的是企业版,则可以在线重建(尽管名称有点误导)。这也是一种快速(相对)整理索引和更新统计信息的方法。
标签: sql-server tsql sql-server-2016