SQL TRANSACTION 左连接结果为空 [英] SQL TRANSACTION Left join result in null

查看:84
本文介绍了SQL TRANSACTION 左连接结果为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,我在事务中插入用户和地址,延迟 10 秒,如果在事务执行期间运行我的 select 语句,它将等待事务完成,但我将在连接中获得空值.为什么我的选择不等待提交用户/地址数据.如果我在事务完成后运行 select 语句,我将得到正确的结果.为什么会出现此错误以及使此工作正常的通用解决方案是什么

I have a problem where I insert User and Address in a transaction with a 10 second delay and if run my select statement during the execution of the transaction it will wait for transaction to finish but I will get a null on the join. Why don't my select wait for both User/Address data to be committed. If I run the select statement after the transaction is finish I will get the correct result. Why do i get this error and what is the generic solution to make this work

BEGIN TRANSACTION   
 insert into user(dummy) values('text')
 WAITFOR DELAY '00:00:10';
 insert into address(ID_FK) values((SELECT SCOPE_IDENTITY()))
COMMIT TRANSACTION

在事务期间运行导致join null

Running during transaction result in null in join

select * from user u left join address a on u.id = a.ID_FK order by id desc

| ID | dummy | ID_FK | 
| 101 | 'text' | null |

在事务后运行得到正确结果

Running after transaction result in correct result

select * from user u left join address a on u.id = a.ID_FK order by id desc

| ID | dummy |  ID_FK|
| 101 | 'text' | 101 |

推荐答案

这种类型的事情在内部部署 SQL Server 的默认读提交级别完全可能,因为它使用读提交锁定.然后执行计划取决于会发生什么.

This type of thing is entirely possible at default read committed level for on premise SQL Server as that uses read committed locking. It is then execution plan dependent what will happen.

示例如下

CREATE TABLE [user]
  (
     id    INT IDENTITY PRIMARY KEY,
     dummy VARCHAR(10)
  );

CREATE TABLE [address]
  (
     ID_FK INT REFERENCES [user](id),
     addr  VARCHAR(30)
  ); 

连接一

BEGIN TRANSACTION

INSERT INTO [user]
            (dummy)
VALUES     ('text')

WAITFOR DELAY '00:00:20';

INSERT INTO address
            (ID_FK,
             addr)
VALUES     (SCOPE_IDENTITY(),
            'Address Line 1')

COMMIT TRANSACTION

连接二(在连接一等待 20 秒时运行此程序)

SELECT *
FROM   [user] u
       LEFT JOIN [address] a
              ON u.id = a.ID_FK
ORDER  BY id DESC
OPTION (MERGE JOIN) 

退货

<头>
id虚拟ID_FK地址
1文字NULLNULL

执行计划如下

User 的扫描被连接 1 中已插入行的打开事务阻止.这必须等到该事务提交,然后最终才能读取新插入的行.

The scan on User is blocked by the open transaction in Connection 1 that has inserted the row there. This has to wait until that transaction commits and then eventually gets to read the newly inserted row.

与此同时,Sort 运算符此时已经从 address 请求了行,因为它在其 Open 方法中(即在运算符初始化期间)消耗了所有行.这不会被阻止,因为尚未向 address 插入任何行.它从解释最终结果的 address 读取 0 行.

Meanwhile the Sort operator has already requested the rows from address by this point as it consumes all its rows in its Open method (i.e. during operator initialisation). This is not blocked as no row has been inserted to address yet. It reads 0 rows from address which explains the final result.

如果您切换到使用读提交快照而不是读提交锁定,您将不会遇到此问题,因为它只会在语句的开头读取已提交的状态,因此不可能出现这种异常.

If you switch to using read committed snapshot rather than read committed locking you won't get this issue as it will only read the committed state at the start of the statement so it isn't possible to get this kind of anomaly.

这篇关于SQL TRANSACTION 左连接结果为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆