You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure SQL不同查询返回同一条记录新旧值的原因及排查方式

问题原因分析
  • 事务隔离级别差异:Azure SQL默认启用读已提交快照隔离(RCSI),如果两条查询运行在不同的事务隔离级别下,会出现读取结果不一致的情况。比如其中一个查询会话使用快照隔离级别,在更新事务提交前就开启了快照读,会读取行版本存储中的旧数据;另一个查询使用默认的读已提交级别,会读取已经提交的最新数据。
  • 未提交的更新事务:如果更新操作所在的事务还没有完成提交,其中一条查询使用了读未提交(READ UNCOMMITTED)/无锁查询(比如加了WITH(NOLOCK)提示),会读取到未提交的脏数据;另一条查询不使用脏读配置,会读取到上一次提交的旧值,也会出现结果不一致。
  • 长查询执行时序差:如果其中一条查询运行耗时较长,在更新事务提交前就已经启动执行,另一条查询在更新提交完成后才启动,也会出现两条查询返回结果不一致的情况。
  • 查询逻辑差异:两条查询的过滤、关联逻辑存在区别,看似查询同一数据集,实际命中的是不同的行数据,或者存在计算逻辑导致返回值差异。
  • 只读副本路由:如果你的Azure SQL配置了只读副本、并且开启了读路由,有可能其中一条查询被路由到了存在同步延迟的只读副本,读取到旧数据,另一条查询命中主库读取最新数据。
  • 行版本存储异常:极少情况下Azure SQL的行版本存储清理不及时,会导致快照读持续读取到过期的行版本数据。
排查步骤
  • 先验证两条查询的逻辑一致性,确认过滤条件、关联表、计算逻辑完全一致,可以将两条查询的结果按主键关联对比,排除逻辑差异导致的结果不同。
  • 确认两条查询的实际执行时间,对比更新事务的提交时间,排查是否存在时序差导致的结果差异。
  • 检查两个查询会话的事务隔离级别,执行以下命令查看当前会话的隔离级别:
    SELECT transaction_isolation_level FROM sys.dm_exec_sessions WHERE session_id = @@SPID;
    同时检查查询语句中是否自带隔离级别提示,比如WITH(SNAPSHOT)、WITH(NOLOCK)等配置。
  • 检查是否存在未提交的事务,执行DBCC OPENTRAN查看当前数据库是否有长时间运行的活动事务,确认更新操作是否已经正常提交。
  • 检查Azure SQL的只读副本配置与读路由状态,确认两条查询是否都路由到主库执行,可以在查询中加入OPTION (ROUTE TO PRIMARY)提示强制路由到主库,再验证结果是否一致。
  • 查看行版本存储的使用情况,执行以下命令查看版本存储的清理状态:
    SELECT * FROM sys.dm_tran_version_store_space_usage;
    如果版本存储占用异常高,可以手动触发一次检查点或者等待系统自动清理后再验证查询结果。

内容的提问来源于stack exchange,提问作者Le-roy Staines

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 21:39:01