SQL Server 2016是否会重排同一事务内多条查询的执行顺序?
问题解答
核心问题1:SQL Server 2016 是否会不按提交顺序执行同一事务内的多条查询?
不会。SQL Server 所有版本的事务内语句都会严格按照提交顺序串行执行,这是事务ACID特性的基础保障,2016版本没有改动这个核心逻辑。
你遇到的随机数据丢失,更可能是升级带来的隐性变化导致的:
- 升级后数据库兼容级别未调整,旧兼容级别在新实例上的锁行为、查询优化策略出现异常
- 连接驱动的默认参数变更,比如
XACT_ABORT默认从ON变为OFF,部分语句执行出错后事务没有完全回滚,出现部分执行成功的情况 - 2016版本默认的事务隔离级别、锁升级阈值和2008有差异,并发写入时出现死锁、锁超时,导致部分语句静默失败
核心问题2:有没有更合理的事务编写方案?
你当前先删后插的逻辑本身没有问题,在没有唯一主键的场景下确实是性能最优的选择,可以做以下优化:
- 事务开头强制开启
SET XACT_ABORT ON,确保任意语句执行出错时,整个事务直接完全回滚,不会出现部分执行的情况,示例代码如下:
SET XACT_ABORT ON; BEGIN TRAN; DELETE FROM table_1 WHERE parentID = 123 AND col2 = 321; DELETE FROM table_2 WHERE parentID = 123 AND col2 = 321; -- 其他DELETE语句 INSERT INTO table_1 (parentID, col2, etc) VALUES (123, 321, 123456); INSERT INTO table_2 (parentID, col2, etc) VALUES (123, 321, 654321); -- 其他INSERT语句 COMMIT TRAN;
- 给所有DELETE语句的筛选字段(parentID、col2)建联合非聚集索引,避免DELETE时全表扫描扩大锁范围,减少并发冲突概率
- 同一个表的操作可以合并为
MERGE语句,减少语句数量和锁持有时间,进一步降低冲突可能 - 批量执行的SQL语句数量控制在合理范围,单次事务不要超过200条语句,避免事务过大导致日志写入阻塞
补充问题解答
显式写BEGIN/COMMIT TRAN后同线程后续查询卡顿的原因
大概率是以下两种情况:
- 事务过大,提交时需要写入大量事务日志,若你库的事务日志文件设置了不合理的自动增长规则(比如每次增长10G),日志扩容时会阻塞同连接的所有后续操作
- 代码分支逻辑存在遗漏,部分场景下事务没有走到COMMIT语句,未提交的事务一直持有锁,后续同线程的查询被自己的未提交事务阻塞
是否需要显式写事务语句
如果你的这组DELETE+INSERT需要保证原子性(要么全部执行成功,要么全部失败回滚),就必须显式写BEGIN TRAN和COMMIT TRAN,不要依赖连接的自动提交机制。自动提交会给每条语句单独开启事务,一旦中间某条INSERT失败,前面的DELETE已经提交成功,就会出现数据被清空却没有新数据写入的丢失问题。
内容的提问来源于stack exchange,提问作者Dan S
相关产品推荐
相关产品推荐

