2017-04-11 3 views
0

간단한 문제 - SQL Server 테이블에 300k 개의 작업이 있으며 여러 프로세스가 하나씩 선택하여 처리하고 결과를 저장합니다.XLOCK ROWLOCK을 사용하여 선택시 TSQL 데드락

그리고 때때로 수확과 저장에 교착 상태가 발생합니다.

두 프로세스가 동일한 작업을 선택하지 않도록해야합니다. 그래서 XLOCK을 사용하고 있으며, 작업이 완료되면 상태가 1- Created에서 Started로 변경되며 이후에는 3-Completed로 처리됩니다.

또한 내 작업 (tblTasksSets)는 일대일 tblGeneralSets에 (문의 바랍니다) 참조) 및 tblGeneralSets 대일 tblContainers에 참조됩니다. 완료로 작업을 표시하는

DECLARE @SetIds AS TABLE(Id INT)  
-- Updating status 
;WITH innerTable AS 
(
    SELECT TOP 1 taskSets.* 
    FROM tblTasksSets taskSets WITH (XLOCK ROWLOCK) 
    INNER JOIN tblGeneralSets generalSets WITH(XLOCK ROWLOCK) ON generalSets.TaskSetId = taskSets.Id 
    WHERE generalSets.ContainerId = @ContainerId 
     AND taskSets.ParameterSetStatusId = 1 --CREATED 
) 
UPDATE innerTable 
SET ParameterSetStatusId = 2 -- STARTED 
OUTPUT INSERTED.Id INTO @SetIds 

-- Here are some unrelated updates on log history tables 

-- And returning result 
SELECT 
    taskSets.*, containers.* 
FROM 
    tblTasksSets taskSets 
INNER JOIN 
    tblGeneralSets generalSets ON generalSets.TaskSetId = taskSets.Id 
INNER JOIN 
    tblContainers containers ON containers.Id = generalSets.ContainerId 
WHERE 
    taskSets.Id = (SELECT TOP 1 Id FROM @SetIds) 

와 두 번째 :

UPDATE tblTasksSets 
SET 
.... 
WHERE Id = @Id 

어떤 아이디어가 왜 교착 상태를 받고 있어요

그래서 나는 업데이트 집어 작업을 선택하려면이 개 절차의 하나가? 한 프로세스가 다른 프로세스가 업데이트를 완료 할 때까지 기다리면됩니다.

System.Data.SqlClient.SqlException (0x80131904) 트랜잭션 (프로세스 ID 53) 잠금 리소스를 다른 프로세스에 교착시키고, 교착 상태로 선택되었다. 트랜잭션을 재실행하십시오.

테스트 당시이 db에 대해 실행 된 다른 쿼리는 없었습니다. 리소스에 대한 액세스를 직렬화하기 위해 무력 방법이 어쩌면

sp_lock shows something like this

Deadlock Graph

+0

그 동안 'sp_lock'을 실행하면 하나의 연결 만 차단하려는 경우 많은 행을 차단한다는 것을 알 수 있습니다. 이는 적절한 색인의 조인 및/또는 부족 때문일 것입니다. 그렇지 않은 경우에도 다른 연결은 현재 잠긴 행이'where'를 만족하지 못하도록 기다려야하므로 동시성이 0이됩니다. – GSerg

+0

아마 당신은'update top (1) ... from ... (rowlock, holdlock, readpast) where ...'를 원할 것입니다. [readpast 힌트] (https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table). – GSerg

+0

교착 상태 그래프를 게시 할 수 있습니까? http://sqlmag.com/database-performance-tuning/gathering-deadlock-information-deadlock-graph – Shaulinator

답변

1

이 두 가지 저장 프로 시저 몇 초마다 호출 그냥 50 처리합니다. SQL 서버의 내장 된 잠금 기능을 사용하면 SP_GETAPPLOCK()으로 작업에 대한 액세스를 대기열에 넣을 수 있습니다. 예를 들면 다음과 같습니다.

+0

로스 부시 덕분에 그 기능을 알지 못했습니다. 나는 다른 질문에 대한 의견을 제시하는 사람들이 제공하는 다른 옵션을 계속 찾고 있습니다. 그러나 반드시 귀하의 접근 방식을 최후의 수단으로 사용하겠습니다. 어떤 사람은 그 사람에게 몇 가지 포인트를 준다;) 나는 1h 이전 사용자가 될 수 없다. –

+0

이것은 모든 호출을 직렬화하고 동시성이 없음을 확인합니다. 나는 OP의 아이디어가 다른 연결이 동시에 작동 할 수 있다고 믿습니다. – GSerg

+0

내 주요 목표는 두 개의 연결이 동일한 작업을 처리하지 않도록하는 것입니다. Ross가 제공하는 솔루션은 실제로 중요한 테이블을 업데이트하는 모든 장소에서 구현해야한다는 단점을 보장합니다. 차라리 테이블 힌트 기반 솔루션을 사용하고 싶지만, 하나도 찾지 못하면 Ross에서 제공하는 솔루션을 사용합니다. –