表架构 (SQL Server 2012)
Create Table InterestBuffer
(
AccountNo CHAR(17) PRIMARY KEY,
CalculatedInterest MONEY,
ProvisionedInterest MONEY,
AccomodatedInterest MONEY,
)
Create Table #tempInterestCalc
(
AccountNo CHAR(17) PRIMARY KEY,
CalculatedInterest MONEY
)
我正在做一个 upsert。更新已存在的行并插入其他行。
UPDATE A
SET A.CalculatedInterest = A.CalculatedInterest + B.CalculatedInterest
FROM InterestBuffer A
INNER JOIN #tempInterestCalc B ON A.AccountNo = B.AccountNo
INSERT INTO InterestBuffer
SELECT A.AccountNo, A.CalculatedInterest, 0, 0
FROM #tempInterestCalc A
LEFT JOIN InterestBuffer B ON A.AccountNo = B.AccountNo
WHERE B.AccountNo IS NULL
一切正常。并发执行时出现问题。我正在将数据插入#tempInterestCalc
通过连接其他各种表,包括与左连接InterestBuffer
表和不同的数据集被插入到#tempInterestCalc
对于每个并发执行。
我的问题是,有时执行会被另一个执行锁定,直到我串行提交它们。
我的问题是,因为我提供了不同的数据集,所以它不应该对其他并发操作产生行锁的任何影响。任何建议将不胜感激。
更新1:我用过SP_LOCK
对于 InterestBuffer 表。它说IndId = 1, Type = KEY, Mode = X, Status = GRANT
.
我认为更新和插入会阻止其他事务进行幻读。
更新2:对不起!之前我说过更新没问题。但现在我意识到第一个事务写入正在阻止第二个事务写入。在第一个事务中,我运行更新并插入。在第二个事务中,在 #tempInterestCalc 表中插入数据后,我只需按以下步骤操作,它就可以正常工作。
--INSERT DATA INTO #tempInterestCalc
SELECT * FROM #tempInterestCalc
RETURN
--UPDATE InterestBuffer
--INSERT InterestBuffer
更新3:我认为我的问题是在更新期间从 InterestBuffer 读取数据并将其插入到 InterestBuffer 中。
更新4:我下面的答案有时会起作用,如果我REBUILD INDEX
InterestBuffer 表中的 BranchCode。批量插入/更新是否会导致索引出现问题???
更新5:我读过,如果需要锁定页面的最大行数以进行批量更新,那么 SQL Server 可能会锁定该页面。有什么方法可以查看哪一行包含哪一页或哪一页将在执行期间锁定和释放?
更新6:我正在提供我的场景。
CREATE TABLE [dbo].[Account](
[AccountNo] [char](17) NOT NULL,
[BranchCode] [char](4) NOT NULL,
CONSTRAINT [PK_Account] PRIMARY KEY CLUSTERED
(
[AccountNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[InterestBuffer](
[AccountNo] [char](17) NOT NULL,
[BranchCode] [char](4) NOT NULL,
[CalculatedInterest] [money] NOT NULL,
CONSTRAINT [PK_Buffer] PRIMARY KEY CLUSTERED
(
[AccountNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
查询分支 0001:
BEGIN TRAN
Declare @BranchCode AS Char(4) = '0001'
Declare @CalculatedInterestNew MONEY = 10
CREATE TABLE #tempInterestCalc
(
AccountNo Char(17),
BranchCode Char(4),
CalculatedInterestNew MONEY,
CalculatedInterestOld MONEY
)
INSERT INTO #tempInterestCalc
SELECT A.AccountNo, A.BranchCode, ISNULL(B.CalculatedInterest, 0), B.CalculatedInterest
FROM Account A
LEFT JOIN InterestBuffer B ON A.AccountNo = B.AccountNo AND A.BranchCode = B.BranchCode
WHERE A.BranchCode = @BranchCode
UPDATE A
SET A.CalculatedInterest = B.CalculatedInterestNew + @CalculatedInterestNew
FROM InterestBuffer A
INNER JOIN #tempInterestCalc B ON A.AccountNo = B.AccountNo AND A.BranchCode = B.BranchCode
WHERE A.BranchCode = @BranchCode
INSERT INTO InterestBuffer
SELECT A.AccountNo, A.BranchCode, A.CalculatedInterestNew + @CalculatedInterestNew
FROM #tempInterestCalc A
WHERE A.CalculatedInterestOld IS NULL
DROP TABLE #tempInterestCalc
--ROLLBACK
--COMMIT TRAN
For Branch 0002, 0003 just change the @BranchCode variable value to 0002 &0003 and Run them simultaneously.