4

로컬 데이터베이스의 레코드를 사용하여 원격 서버의 많은 항목을 업데이트하는 절차를 진행하고 있습니다. 다음은 의사 코드입니다. 아무리 우리가 그것을 최적화 얼마나 저장 프로 시저 내의 루프 내의 트랜잭션

CREATE PROCEDURE UpdateRemoteServer 
    pre-processing 
    get cursor with ID's of records to be updated 
    while on cursor 
     process the item 

는 일상적인 시간이 걸릴 것입니다, 그래서 우리는 모든 것이 하나의 트랜잭션으로 처리하고 싶지 않아요. 항목은 처리 된 후 플래그가 지정되므로 프로세스가 중단되면 중단 된 부분을 다시 가져올 수 있어야합니다.

에서 ("항목을 처리") 루프의 내용을 포장 A /는 전체 문

EXEC UpdateRemoteServer 

가 단일 트랜잭션으로 처리됩니다 것 같다 ... 트란이 트릭을하지 않습니다 커밋 시작 . 각 품목 프로세스를 완전하고 별도의 거래로 만들려면 어떻게해야합니까?

나는 "비 트랜잭션 업데이트"이러한 실행 싶지만 참고하지만 옵션은 2008 년

답변

1

아래의 Remus가 지적한 EDIT :과 같이 커서는 기본적으로 트랜잭션을 열지 않습니다. 따라서 이것은 OP가 제기 한 질문에 대한 대답이 아닙니다. 나는 여전히 커서보다 더 나은 옵션이 있다고 생각하지만, 그 질문에는 대답하지 않는다.

스투

ORIGINAL 답변 :

당신이 설명하는 특정 증상 때문에 상관없이 당신이 그것을 어떻게 작동하는지, 당신이 가지고있는거야없는, 커서는 기본적으로 트랜잭션을 여는 때문이다 커서를 사용하는 한 오래 실행되는 트랜잭션 (잠금을 피하지 않는 한 다른 나쁜 아이디어 임).

다른 사람이 지적한 것처럼 커서는 SUCK입니다. 당신은 99.9999 %의 시간 동안 그것들을 필요로하지 않습니다.

당신은 SQL 서버와 데이터베이스 레벨에서이 작업을 수행하려는 경우 당신은 정말 두 가지 옵션이 있습니다

  1. 사용 SSIS이 작업을 수행 할 수있는; 매우 빠르지 만 특정 SQL Server 버전에서는 사용할 수 없을 수도 있습니다.

  2. 원격 서버를 다루고 있고 연결에 대해 걱정하기 때문에 루핑 메커니즘을 사용해야 할 수 있으므로 대신 WHILE을 사용하고 한 번에 배치를 완료하십시오. WHILE은 커서와 같은 많은 문제를 가지고 있지만 (SQL에서 여전히 반복적 인 루핑) 외부 트랜잭션을 작성하지 않아도됩니다.

스투

+0

정보를 제공해 주셔서 감사합니다. 이것은 실제로 질문에 대답합니다. 그것과는 별개로, 나는 커서가 빨려 있다는 것을 안다. 이 경우 커서가 성능 문제 *를 일으키는 것이 아니라 루프 내부에서 수행되는 작업입니다. 그러나 그것은 별개의 질문입니다. – harpo

+0

"cursors suck"에 동의하지 않지만 다른 논의입니다. – Thorsten

+0

@IronGoofy : 네 말이 맞아. 커서는 특별한 상황에서 사용해야하는 전문 도구입니다 (스크류 추출기와 같으며, 매일 필요하지 않습니다. "그들이 빨아"라고 말하는 것이 더 쉽습니다. :) –

0

요는 SQL 서버 내에서이를 실행에 (내가 아는 지금까지로) 만 사용할 수 있습니다, 또는 앱에서? 그렇다면 처리 할 목록을 가져온 다음 필요에 따라 하위 집합 만 처리하도록 앱을 루프합니다.

그런 다음 거래는 귀하의 응용 프로그램에 의해 처리되어야하고, 항목 만이/페이지 항목이에 있습니다. 당신이 트랜잭션 작업을 수행 할 때

+0

불행하게도,이 전적으로 SQL 서버 내에서 수행되고, 그 요구 사항은 내 통제 할 수없는 것입니다. – harpo

+0

그것을 암탉 아직 처리 당신이 sp보다는 오히려 단순한 tsql에서 실행하지 않는다면 sigle 트랜잭션으로?spa를 avaoid하고 트랜잭션을 tsql 세션에 바인드하여 inners를 사용 하시겠습니까? –

+0

우리는 비슷하게 생각합니다 ... 문제는 프로세스가 자동화되어야하므로 단일 명령으로 실행 가능해야한다는 것입니다. – harpo

0

는 루프에서 한 번에 하나 개의 항목을 처리 할 것은 없습니다 업데이트되고 고정한다. 레코드 그룹을 처리하는 레코드를 반복 할 수 있지만 한 번에 하나의 레코드를 절대 수행 할 수는 없습니다. 대신에 세트 기반 삽입을 수행하면 성능이 시간에서 분 또는 초 단위로 변경됩니다. 커서를 사용하여 갱신 또는 삭제를 삽입하고 각 명령문 (atime에 하나도 포함하지 않음)에서 적어도 1000 개의 rowa를 처리하지 않으면 잘못된 일을합니다. 커서는 그런 일에 대해 극도로 빈약 한 습관입니다.

+2

물론 가능하다면 나는 set-based inserts를 사용할 것입니다. 각 항목에는 업데이트해야하는 여러 관련 하위 테이블이 있으므로 한 번에 하나의 항목 만 처리합니다. 따라서 각 반복은 수십 개의 레코드를 처리해야하며 실제로 전체 업데이트를 즉시 처리 할 수는 없습니다. 나는 지금까지 매우 일반적인 유형의 무응답을 downvoting하는 방침에 반대 해왔다. (즉, "당신의 전체 전제가 잘못되었으므로,이 일을해서는 안된다.") 그러나 그들의 저자가 대신에 그것들을 논평에 넣지 않는지 궁금하다. . – harpo

3

EXEC 절차가 수행 아니요 트랜잭션을 만듭니다. 아주 간단한 테스트이 표시됩니다 : usp_foo 내부

create procedure usp_foo 
as 
begin 
    select @@trancount; 
end 
go 

exec usp_foo; 

@@ TRANCOUNT가 0의 EXEC 문이 암시 적 트랜잭션을 시작하지 않도록. UpdateRemoteServer를 시작할 때 트랜잭션이 시작되었다는 것은 누군가 그 트랜잭션을 시작했음을 의미합니다.

즉, 원격 서버와 DTC를 사용하여 항목을 업데이트하면 성능이 크게 떨어집니다. 다른 서버도 SQL Server 2005 이상입니까? 아마도 업데이트 요청을 큐에 넣고 messaging을 로컬 서버와 원격 서버간에 사용하고 원격 서버가 메시지의 정보를 기반으로 업데이트를 수행하게 할 수 있습니다. 두 서버 모두 로컬 트랜잭션 만 처리해야하기 때문에 성능이 크게 향상되며 대기중인 메시징이 느슨하게 결합되어 가용성이 훨씬 향상됩니다.

커서 실제로 트랜잭션을 시작하지 않는 업데이트되었습니다. 일반적인 커서 기반 일괄 처리는 일반적으로 커서를 기반으로하고 일정 크기의 트랜잭션으로 일괄 업데이트합니다. 이것은 더 나은 성능 (더 큰 트랜잭션 크기로 인한 로그 플러시 처리량)을 허용하고, 작업이 중단 될지도 모르고 일주일에 한 번씩 일하는 동안 꽤 자주 일어납니다.일괄 처리 루프의 단순화 된 버전은 다음과 같이 일반적으로 : 나는 (/ 시도를 시작 잡기 시작)과 공상 @@ FETCH_STATUS 검사 (정적 커서 실제로 그들을 어쨌든 필요하지 않은 부분을 처리하는 오류를 ommitted

create procedure usp_UpdateRemoteServer 
as 
begin 
    declare @id int, @batch int; 
    set nocount on; 
    set @batch = 0; 

    declare crsFoo cursor 
    forward_only static read_only 
    for 
    select object_id 
    from sys.objects; 

    open crsFoo; 

    begin transaction 
    fetch next from crsFoo into @id ; 
    while @@fetch_status = 0 
    begin 

    -- process here 

    declare @transactionId int; 
    SELECT @transactionId = transaction_id 
     FROM sys.dm_tran_current_transaction; 
    print @transactionId; 

    set @batch = @batch + 1 
    if @batch > 10 
    begin 
     commit; 
     print @@trancount; 
     set @batch = 0; 
     begin transaction; 
    end 
    fetch next from crsFoo into @id ; 
    end 
    commit; 
    close crsFoo; 

    deallocate crsFoo; 
end 
go 

exec usp_UpdateRemoteServer; 

). 이 데모 코드는 실행 중에 몇 가지 다른 트랜잭션 (다른 트랜잭션 ID)이 시작되었음을 보여줍니다. 여러 번 일괄 처리를 수행하면 deploy transaction savepoints at each item이 처리되므로 내 링크와 비슷한 패턴을 사용하여 예외가 발생하는 항목을 안전하게 건너 뛸 수 있지만 저장 점과 DTC가 섞이지 않기 때문에 분산 트랜잭션에는 적용되지 않습니다.

+0

당신은 그 성능에 대해 옳았습니다 ... 우리가이 기술을 선택할 때 그것을 알고 싶었습니다. 그럼에도 불구하고 현재 우리가 모든 것을 다시 쓸 수있는 곳이 아니므로이 문제를 해결하면 현재 루틴을 잠시 허용 할 수 있습니다. – harpo

+0

테스트 프로 시저를 실행 했으므로 동의해야합니다. 커서는 전체적으로 트랜잭션을 유지하지 않습니다. 동적 업데이트 가능한 커서를 가져 오기 위해 지정된 옵션을 제거하고 트랜잭션이 여전히 변경되었습니다. 내 대답을 취소합니다 (커서 사용에 대한 내 입장이 아닌 경우). –

+0

Remus, 내가 틀렸다면 나에게 맞춰라. 그러나 서버간에 (링크 된 서버를 통해) 데이터를 수정하기 시작하면 암시 적 분산 트랜잭션이 SQL Server에서 자동으로 시작되지 않으므로 원격 시스템에 대한 변경이 실패 할 경우 실패 할 수 있습니다. 제대로 호출 SQL Server로 다시 보냈습니까? – mrdenny

0

그냥 생각 ..

  • 절차가 호출 될 때 단지 몇 항목을 처리 (예를 들어에만 TOP 10 항목을 처리 할 수)
  • 프로세스들

트랜잭션이 끝나기를 바랍니다.

더 많은 작업이있는 한 프로 시저를 호출하는 래퍼를 작성합니다 (간단한 카운트 (..)를 사용하여 항목이 있는지 확인하거나 프로 시저를 가지고 있으면 더 많은 작업이 있음을 나타냅니다. 이 작동하는지 모르겠어요.

을,하지만 어쩌면 생각이 도움이됩니다.