SQL Server 2005에서 테이블을 잠그는 방법은 무엇이며, 그렇게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/57625

  •  09-06-2019
  •  | 
  •  

문제

이것은 약간의 설명이 필요할 것입니다.내가 한 일은 SQL Server 2005에서 특정 사용자 지정 메시지 대기열을 만드는 것입니다.승인 및 완료에 대한 타임스탬프가 포함된 메시지가 포함된 테이블이 있습니다.호출자가 대기열의 다음 메시지를 얻기 위해 실행하는 저장 프로시저도 메시지를 확인합니다.여태까지는 그런대로 잘됐다.글쎄요, 시스템에서 엄청난 양의 트랜잭션(분당 수천 건)이 발생하는 경우 저장 프로시저의 다른 실행이 메시지를 승인하는 동안 다른 저장 프로시저가 자체적으로 메시지를 승인하는 것이 가능하지 않습니까?저장된 proc에 내 SQL 코드를 표시하여 도와드리겠습니다.

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

--Select the entire message
...
...

위 코드에서 동시에 실행 중인 다른 저장 프로시저가 동일한 ID를 획득하고 동시에 이를 승인하려고 시도할 수는 없나요?다른 저장 프로시저가 쿼리하는 메시지를 다른 저장 프로시저가 승인하지 못하도록 일종의 잠금을 구현할 수 있습니까(또는 구현해야 합니까)?

와, 이게 말이 됩니까?말로 표현하기가 좀 어렵네요..

도움이 되었습니까?

해결책

이 같은

--Grab the next message id
begin tran
declare @MessageId uniqueidentifier
select top 1 @MessageId =   ActionMessageId from UnacknowledgedDemands with(holdlock, updlock);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

-- some error checking
commit tran

--Select the entire message
...
...

다른 팁

이런 상황인거 같네요 OUTPUT 유용할 수 있습니다:

-- Acknowledge and grab the next message
declare @message table (
    -- ...your `ActionMessages` columns here...
)
update ActionMessages
set    AcknowledgedTime = getdate()
output INSERTED.* into @message
where  ActionMessageId in (select top(1) ActionMessageId from UnacknowledgedDemands)
  and  AcknowledgedTime is null

-- Use the data in @message, which will have zero or one rows assuming
-- `ActionMessageId` uniquely identifies a row (strongly implied in your question)
...
...

거기에서 동일한 작업으로 행을 업데이트하고 가져옵니다. 이는 쿼리 최적화 프로그램에 알려줍니다. 정확히 우리가 하고 있는 일을 통해 가능한 가장 세부적인 잠금을 선택하고 가능한 한 가장 짧은 시간 동안 유지 관리할 수 있습니다.(열 접두사는 INSERTED, OUTPUT 트리거와 유사하며 다음과 같이 표현됩니다. UPDATE 행을 삭제하고 새 행을 삽입하는 것과 같습니다.)

당신에 대한 더 많은 정보가 필요해요 ActionMessages 그리고 UnacknowledgedDemands SQL Server의 자동 잠금에 대한 더 많은 지식은 말할 것도 없고 테이블(뷰/TVF/무엇이든) and AcknowledgedTime is null 조항이 필요합니다.하위 선택과 업데이트 사이의 경쟁 조건을 방어하기 위해 존재합니다.우리가 다음 중 하나를 선택한다면 필요하지 않을 것이라고 확신합니다. ActionMessages 자체(예: where AcknowledgedTime is nulltopupdate, 하위 선택 대신 UnacknowledgedDemands).불필요하더라도 무해하다고 생각합니다.

참고하세요 OUTPUT SQL Server 2005 이상에 있습니다.이것이 당신이 사용하고 있다고 말한 것이지만 노인 SQL Server 2000 설치와의 호환성이 필요하다면 다른 방법을 사용하고 싶을 것입니다.

@킬호퍼:

전체 SQL 배치는 실행 전에 구문 분석되므로 SQL은 사용자가 테이블을 업데이트하고 테이블에서 선택할 것임을 알고 있습니다.

편집하다:또한 SQL은 전체 테이블을 반드시 잠글 필요는 없으며 필요한 행만 잠글 수도 있습니다.보다 여기 SQL Server의 잠금 개요를 참조하세요.

SQL Server에서 원하는 것보다 더 높은 세분성으로 확대하는 경우가 많은 명시적 잠금 대신 다음 접근 방식을 시도해 보는 것은 어떨까요?

declare @MessageId uniqueidentifier
select top 1 @MessageId = ActionMessageId from UnacknowledgedDemands

update ActionMessages
  set AcknowledgedTime = getdate()
  where ActionMessageId = @MessageId and AcknowledgedTime is null

if @@rowcount > 0
  /* acknoweldge succeeded */
else
  /* concurrent query acknowledged message before us,
     go back and try another one */

잠그는 횟수가 적을수록 동시성이 높아집니다.

정말로 일을 하나씩 처리해야 합니까?SQL Server에서 오늘 날짜가 포함된 확인되지 않은 모든 메시지를 확인하고 반환하도록 하면 안 되나요?(물론 거래에서도 모두)

SQL Server 선택 잠금에 대해 자세히 알아보세요. 여기 그리고 여기.SQL Server에는 선택 시 테이블 잠금을 호출하는 기능이 있습니다.트랜잭션 중에는 테이블에 아무 일도 일어나지 않습니다.트랜잭션이 완료되면 삽입이나 업데이트가 자동으로 해결됩니다.

코드를 트랜잭션으로 래핑하려는 경우 SQL Server가 해당 행이나 테이블 잠금을 처리합니다.

begin transaction

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

commit transaction

--Select the entire message
...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top