我在SQL Server 2008 R2中有一个存储过程,如下所示;
DECLARE @uniqueId BIGINT
DECLARE TestCursor CURSOR FOR
SELECT em.uniqueId
FROM EMPLYEE_MASTER em WITH (NOLOCK)
INNER JOIN EMP_DETAILS edt WITH (NOLOCK) ON em.uniqueId = edt.uniqueId
INNER JOIN EMP_ATTENDANCE ea WITH (NOLOCK) ON em.uniqueId = ea.uniqueId
OPEN TestCursor
FETCH NEXT FROM TestCursor INTO @uniqueId
WHILE @@fetch_status = 0
BEGIN
BEGIN TRANSACTION purge
DELETE FROM EMPLYEE_MASTER where uniqueId = @uniqueId
DELETE FROM EMP_DETAILS where uniqueId = @uniqueId
DELETE FROM EMP_ATTENDANCE where uniqueId = @uniqueId
DELETE FROM EMP_ADDRESS where uniqueId = @uniqueId
DELETE FROM EMP_APPRAISALS where uniqueId = @uniqueId
COMMIT TRANSACTION purge
FETCH NEXT FROM TestCursor INTO @uniqueId
END
CLOSE TestCursor
DEALLOCATE TestCursor
此存储过程在开始运行时会挂起并阻止运行其他查询(没有参照完整性问题)。我怀疑问题的原因是由于(正如你所看到的)SELECT
语句中的语句使用WITH (NOLOCK)
提示脏提取。然后删除已在select语句中使用的表中的数据,并在游标中使用WITH (NOLOCK)
语句。因为一旦我在游标中的select语句中注释了与WITH (NOLOCK)
一起使用的删除语句,那么存储过程运行没有任何问题。
有人可以解释一下:
WITH (NOLOCK)
在游标内的语句中使用并锁定DELETE的记录(在事务中运行)WITH (NOLOCK)
?答案 0 :(得分:3)
删除绝对不必要的光标,删除无意义的NOLOCK。
action="<?php echo esc_url( home_url( '/' ) ); ?>"
等等
关于光标的附注
DECLARE @del TABLE (uniqueId BIGINT NOT NULL PRIMARY KEY)
DELETE em
OUTPUT DELETED.uniqueId
INTO @del(uniqueId)
FROM EMPLYEE_MASTER em
WHERE EXISTS(SELECT 1 FROM EMP_DETAILS edt WHERE em.uniqueId = edt.uniqueId)
AND EXISTS(SELECT 1 FROM EMP_ATTENDANCE ea WHERE em.uniqueId = ea.uniqueId)
DELETE t
FROM EMP_DETAILS t
WHERE EXISTS(SELECT 1 FROM @del d WHERE d.uniqueId = t.uniqueId)
DECLARE TestCursor CURSOR STATIC FOR
SELECT DISTINCT em.uniqueId
FROM EMPLYEE_MASTER em
INNER JOIN EMP_DETAILS edt ON em.uniqueId = edt.uniqueId
INNER JOIN EMP_ATTENDANCE ea ON em.uniqueId = ea.uniqueId
- 您正在加入DETAILS,因此行数将乘以详细信息数量,这意味着您将尝试多次删除相同的uniqueId
DISTINCT
- 而不是 nolocking 你可以这样做:使用此选项服务器将创建临时表并在其中存储选定的值。
答案 1 :(得分:0)
想到三件事: 游标,显式事务和DELETE语句。
默认情况下,除非行数超过n行或x大小,否则游标将使用行级别锁定。其中(n行或x大小)>默认值,请使用表锁!
无论哪种方式,因为delete语句都试图删除被光标锁定的行!与您在光标的选择部分中指定的锁定无关。
回答您的问题:
1)不。
2)不完全是。将语句中的“ WITH(NOLOCK)”替换为“相同表”:
此问题的原因是由于在游标内的语句中使用了[相同表] 并锁定DELETE(在事务内运行)的记录
3)参见伊万·斯塔诺斯汀的回答!
OR
--DECLARE @uniqueId BIGINT
DECLARE @uniqueIds TABLE (uniqueId BIGINT NOT NULL PRIMARY KEY)
--DECLARE TestCursor CURSOR FOR
INSERT INTO @uniqueIds
SELECT em.uniqueId
FROM EMPLYEE_MASTER em WITH (NOLOCK)
INNER JOIN EMP_DETAILS edt WITH (NOLOCK) ON em.uniqueId = edt.uniqueId
INNER JOIN EMP_ATTENDANCE ea WITH (NOLOCK) ON em.uniqueId = ea.uniqueId
--If the above insert fails, this is due to uniqueId NOT being unique!!
--OPEN TestCursor
--FETCH NEXT FROM TestCursor INTO @uniqueId
--WHILE @@fetch_status = 0
--BEGIN
BEGIN TRANSACTION purge
DELETE FROM EMPLYEE_MASTER where uniqueId --= @uniqueId
in (select uniqueId FROM @uniqueIds);
DELETE FROM EMP_DETAILS where uniqueId --= @uniqueId
in (select uniqueId FROM @uniqueIds);
DELETE FROM EMP_ATTENDANCE where uniqueId --= @uniqueId
in (select uniqueId FROM @uniqueIds);
DELETE FROM EMP_ADDRESS where uniqueId --= @uniqueId
in (select uniqueId FROM @uniqueIds);
DELETE FROM EMP_APPRAISALS where uniqueId --= @uniqueId
in (select uniqueId FROM @uniqueIds);
COMMIT TRANSACTION purge
--ROLLBACK?
-- FETCH NEXT FROM TestCursor INTO @uniqueId
END
--CLOSE TestCursor
--DEALLOCATE TestCursor