문제

Stack Overflow SQL Server 2005 데이터베이스에서 일부 유해하지만 드물게 교착 상태가 발생하는 것을 확인했습니다.

프로파일러를 연결하고 다음을 사용하여 추적 프로필을 설정했습니다. 교착 상태 문제 해결에 관한 훌륭한 기사, 그리고 많은 예시를 포착했습니다.이상한 점은 교착 상태의 쓰기는 언제나 똑같다:

UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0

다른 교착 상태 진술은 다양하지만 일반적으로 일종의 사소하고 단순한 것입니다. 읽다 게시물 테이블의이 사람은 항상 교착 상태에서 죽습니다.여기에 예가 있습니다

SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount], 
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId], 
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0

완전히 명확하게 말하면 쓰기/쓰기 교착 상태가 표시되지 않고 읽기/쓰기가 표시됩니다.

현재 LINQ와 매개변수화된 SQL 쿼리가 혼합되어 있습니다.우리는 추가했습니다 with (nolock) 모든 SQL 쿼리에 적용됩니다.이것이 일부 도움이 되었을 수도 있습니다.또한 어제 수정한 (매우) 잘못 작성된 배지 쿼리가 하나 있었는데, 매번 실행하는 데 20초 이상이 걸리고 게다가 1분마다 실행되었습니다.나는 이것이 일부 잠금 문제의 원인이기를 바랐습니다!

불행하게도 약 2시간 전에 또 다른 교착 상태 오류가 발생했습니다.똑같은 증상, 똑같은 범인이 쓰네요.

정말 이상한 점은 위에서 본 잠금 쓰기 SQL 문이 매우 구체적인 코드 경로의 일부라는 것입니다.그것은 오직 질문에 새 답변이 추가되면 실행됩니다. 새 답변 수와 마지막 날짜/사용자로 상위 질문을 업데이트합니다.이는 분명히 우리가 수행하는 엄청난 수의 읽기에 비해 흔하지 않습니다!내가 알 수 있는 한, 우리는 앱 어디에서나 엄청난 양의 쓰기 작업을 수행하지 않습니다.

나는 NOLOCK이 일종의 거대한 망치라는 것을 알고 있지만 여기서 실행하는 대부분의 쿼리는 그렇게 정확할 필요는 없습니다.귀하의 사용자 프로필이 몇 초 정도 오래된 경우에도 신경쓰시겠습니까?

Linq와 함께 NOLOCK을 사용하는 것은 다음과 같이 조금 더 어렵습니다. Scott Hanselman이 여기서 논의합니다..

우리는 사용하려는 아이디어를 유혹하고 있습니다

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

모든 LINQ 쿼리에 이 세트가 포함되도록 기본 데이터베이스 컨텍스트에 있습니다.그렇지 않으면 우리가 수행하는 모든 LINQ 호출(음, 간단한 읽기 호출, 대부분이 이에 해당함)을 3~4줄의 트랜잭션 코드 블록으로 묶어야 하는데 이는 보기 흉합니다.

SQL 2005에서 사소한 읽기 작업으로 인해 쓰기 작업이 교착 상태에 빠질 수 있다는 점에 조금 실망한 것 같습니다.쓰기/쓰기 교착 상태가 큰 문제라는 것을 알 수 있었지만 읽나요? 여기서는 은행 사이트를 운영하는 것이 아니므로 매번 완벽한 정확성이 필요하지 않습니다.

아이디어?생각?


모든 작업에 대해 새로운 LINQ to SQL DataContext 개체를 인스턴스화하고 있습니까? 아니면 모든 호출에 대해 동일한 정적 컨텍스트를 공유하고 있습니까?

Jeremy, 우리는 대부분 기본 컨트롤러에서 하나의 정적 데이터 컨텍스트를 공유하고 있습니다.

private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
    get
    {
        if (_db == null)
        {
            _db = new DBContext() { SessionName = GetType().Name };
            //_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
        }
        return _db;
    }
}

모든 컨트롤러에 대해, 또는 페이지별로 또는 ..에 대해 새 컨텍스트를 생성하는 것이 좋습니다.더 자주?

도움이 되었습니까?

해결책

MSDN에 따르면:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

Commited Snapshot 또는 Snapshot 격리 허용 데이터베이스 옵션이 켜져 있으면 데이터베이스에서 수행되는 모든 데이터 수정에 대해 논리 사본 (버전)이 유지됩니다.특정 트랜잭션에 의해 행이 수정 될 때마다 데이터베이스 엔진의 인스턴스는 Tempdb에서 이전에 커밋 된 행 이미지의 버전을 저장합니다.각 버전에는 거래를 변경 한 트랜잭션의 트랜잭션 시퀀스 번호가 표시됩니다.수정 된 행의 버전은 링크 목록을 사용하여 연결됩니다.최신 행 값은 항상 현재 데이터베이스에 저장되며 TempDB에 저장된 버전의 행에 묶여 있습니다.

단기 트랜잭션의 경우 수정 된 행 버전이 Tempdb 데이터베이스의 디스크 파일에 쓰지 않고 버퍼 풀에 캐시 될 수 있습니다.버전의 행의 필요성이 수명이 짧은 경우 버퍼 풀에서 단순히 떨어지고 반드시 I/O 오버 헤드가 발생할 필요는 없습니다.

추가 오버헤드로 인해 약간의 성능 저하가 있는 것처럼 보이지만 무시할 수 있습니다.확인하기 위해 테스트를 해야 합니다.

이 옵션을 설정하고 꼭 필요한 경우가 아니면 코드 쿼리에서 모든 NOLOCK을 제거해 보세요.NOLOCK을 사용하거나 데이터베이스 컨텍스트 처리기에서 전역 메서드를 사용하여 데이터베이스 트랜잭션 격리 수준을 해결하는 것은 문제에 대한 반창고입니다.NOLOCKS는 데이터 계층의 근본적인 문제를 가려서 신뢰할 수 없는 데이터를 선택하게 할 수 있으며, 여기서 자동 선택/업데이트 행 버전 관리가 솔루션으로 보입니다.

ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON

다른 팁

NOLOCK 그리고 커밋되지 않은 읽기 미끄러운 경사면이에요.교착 상태가 먼저 발생하는 이유를 이해하지 않는 한 절대 사용해서는 안 됩니다."우리는 모든 SQL 쿼리에 (nolock)을 추가했습니다"라고 말하면 걱정될 것입니다.추가가 필요함 NOLOCK 포함 어디에서나 데이터 영역에 문제가 있다는 확실한 신호입니다.

업데이트 문 자체는 약간 문제가 있는 것 같습니다.트랜잭션 초기에 개수를 결정합니까, 아니면 객체에서 가져오나요? AnswerCount = AnswerCount+1 질문을 추가하는 것이 아마도 이 문제를 처리하는 더 좋은 방법일 것입니다.그러면 올바른 개수를 얻기 위해 트랜잭션이 필요하지 않으며 잠재적으로 노출될 수 있는 동시성 문제에 대해 걱정할 필요가 없습니다.

많은 작업을 수행하지 않고 더티 읽기를 활성화하지 않고 이러한 유형의 교착 상태 문제를 해결하는 한 가지 쉬운 방법은 다음을 사용하는 것입니다. "Snapshot Isolation Mode" (SQL 2005의 새로운 기능) 항상 수정되지 않은 마지막 데이터를 깨끗하게 읽을 수 있습니다.교착 상태 문을 정상적으로 처리하려는 경우 교착 상태 문을 상당히 쉽게 포착하고 재시도할 수도 있습니다.

OP 질문은 왜 이 문제가 발생했는지 묻는 것이었습니다.이 게시물은 가능한 해결책을 다른 사람들이 해결하도록 남겨두고 그에 대한 답변을 제공하기를 희망합니다.

이는 아마도 인덱스 관련 문제일 수 있습니다.예를 들어 Posts 테이블에 ParentID와 업데이트되는 하나 이상의 필드(AnswerCount, LastActivityDate, LastActivityUserId)를 포함하는 비클러스터형 인덱스 X가 있다고 가정해 보겠습니다.

SELECT cmd가 ParentId로 검색하기 위해 인덱스 X에서 공유 읽기 잠금을 수행한 다음 UPDATE cmd가 쓰기 독점을 수행하는 동안 나머지 열을 가져오기 위해 클러스터형 인덱스에서 공유 읽기 잠금을 수행해야 하는 경우 교착 상태가 발생합니다. 클러스터형 인덱스를 잠그고 이를 업데이트하려면 인덱스 X에 쓰기 전용 잠금을 가져와야 합니다.

이제 A가 X를 잠그고 Y를 얻으려고 하는 반면 B는 Y를 잠그고 X를 얻으려고 하는 상황이 있습니다.

물론 이것이 실제로 원인인지 확인하기 위해 어떤 인덱스가 사용되고 있는지에 대한 추가 정보로 그의 게시물을 업데이트하려면 OP가 필요합니다.

나는 이 질문에 대해 매우 불편하며 수행원이 대답합니다."이 마법의 가루를 사용해 보세요!"라는 말이 많이 있습니다.아니 그 마법의 가루!"

나는 당신이 취해진 잠금을 분석하고 교착 상태에 빠진 정확한 잠금 유형을 결정한 곳을 어디에서도 볼 수 없습니다.

당신이 지적한 것은 교착 상태가 아닌 일부 잠금이 발생한다는 것입니다.

SQL 2005에서는 다음을 사용하여 어떤 잠금이 해제되는지에 대한 자세한 정보를 얻을 수 있습니다.

DBCC TRACEON (1222, -1)

교착 상태가 발생할 때 더 나은 진단을 얻을 수 있습니다.

모든 작업에 대해 새로운 LINQ to SQL DataContext 개체를 인스턴스화하고 있습니까? 아니면 모든 호출에 대해 동일한 정적 컨텍스트를 공유하고 있습니까?나는 원래 후자의 접근 방식을 시도했는데, 내가 기억하는 바에 따르면 DB에서 원치 않는 잠금이 발생했습니다.이제 모든 원자 작업에 대해 새로운 컨텍스트를 만듭니다.

NOLOCK으로 파리를 잡기 위해 집을 불태우기 전에 프로파일러로 캡처했어야 하는 교착 상태 그래프를 살펴보는 것이 좋습니다.

교착 상태에는 (적어도) 2개의 잠금이 필요하다는 점을 기억하세요.연결 1에는 잠금 A가 있고 잠금 B를 원하며 연결 ​​2에는 그 반대의 경우도 마찬가지입니다.이것은 해결할 수 없는 상황이고 누군가는 주어야 합니다.

지금까지 살펴본 내용은 SQL Server가 하루 종일 기꺼이 수행하는 간단한 잠금을 통해 해결되었습니다.

귀하(또는 LINQ)가 해당 UPDATE 문을 사용하여 트랜잭션을 시작하고 미리 다른 정보를 선택하고 있는 것 같습니다.그러나 잠금을 찾으려면 교착 상태 그래프를 역추적해야 합니다. 유지된 그런 다음 프로파일러를 통해 역추적하여 해당 잠금을 부여한 명령문을 찾습니다.

이 퍼즐을 완성하려면 최소한 4개의 문(또는 여러 잠금을 사용하는 문 - 아마도 Posts 테이블에 트리거가 있을까요?)이 있을 것으로 예상됩니다.

귀하의 사용자 프로필이 몇 초 정도 오래된 경우에도 신경쓰시겠습니까?

아뇨 - 그건 완전히 받아들일 수 있는 일이에요.기본 트랜잭션 격리 수준을 설정하는 것이 아마도 가장 좋고 깨끗한 방법일 것입니다.

일반적인 읽기/쓰기 교착 상태는 인덱스 순서 액세스로 인해 발생합니다.읽기(T1)는 인덱스 A에서 행을 찾은 다음 인덱스 B(일반적으로 클러스터형)에서 프로젝션 열을 조회합니다.쓰기(T2)는 인덱스 B(클러스터)를 변경한 다음 인덱스 A를 업데이트해야 합니다.T1은 A에 S-Lck가 있고, B에 S-Lck가 있고, T2가 B에 X-Lck가 있고, A에 U-Lck가 있습니다.교착 상태, 퍼프.T1이 사망했습니다.이는 OLTP 트래픽이 많고 인덱스가 너무 많은 환경에서 흔히 발생합니다. :).해결책은 읽기가 A에서 B로 점프할 필요가 없도록 만드는 것입니다(예:A에 열을 포함하거나 프로젝션된 목록에서 열을 제거) 또는 T2는 B에서 A로 이동할 필요가 없습니다(인덱싱된 열을 업데이트하지 않음).불행히도 linq는 여기서 당신의 친구가 아닙니다 ...

@Jeff - 저는 확실히 이 분야의 전문가는 아니지만 거의 모든 호출에서 새로운 컨텍스트를 인스턴스화하여 좋은 결과를 얻었습니다.나는 이것이 ADO를 호출할 때마다 새로운 Connection 객체를 생성하는 것과 비슷하다고 생각합니다.어쨌든 연결 풀링이 계속 사용되므로 오버헤드는 생각만큼 나쁘지 않습니다.

저는 다음과 같은 전역 정적 도우미를 사용합니다.

public static class AppData
{
    /// <summary>
    /// Gets a new database context
    /// </summary>
    public static CoreDataContext DB
    {
        get
        {
            var dataContext = new CoreDataContext
            {
                DeferredLoadingEnabled = true
            };
            return dataContext;
        }
    }
}

그런 다음 다음과 같이 합니다.

var db = AppData.DB;

var results = from p in db.Posts where p.ID = id select p;

업데이트에 대해서도 동일한 작업을 수행합니다.어쨌든 나는 당신만큼 트래픽이 많지는 않지만 초기에 소수의 사용자와 공유 DataContext를 사용할 때 약간의 잠금이 발생했습니다.보장할 수는 없지만 시도해 볼 가치가 있습니다.

업데이트:그런 다음 다시 코드를 살펴보면 특정 컨트롤러 인스턴스의 수명 동안만 데이터 컨텍스트를 공유하고 있습니다. 이는 컨트롤러 내의 여러 호출에 의해 동시에 사용되지 않는 한 기본적으로 괜찮아 보입니다.이 주제에 대한 스레드에서 ScottGu는 다음과 같이 말했습니다.

컨트롤러는 단일 요청에 대해서만 작동하므로 요청 처리가 끝나면 가비지 수집됩니다(DataContext가 수집됨을 의미).

어쨌든, 그렇지 않을 수도 있지만, 아마도 부하 테스트와 함께 시도해 볼 가치가 있을 것입니다.

큐.왜 저장해? AnswerCount 에서 Posts 테이블이 먼저야?

또 다른 접근 방식은 "다시 쓰기"를 제거하는 것입니다. Posts 테이블을 저장하지 않음으로써 AnswerCount 필요에 따라 게시물에 대한 답변 수를 동적으로 계산합니다.

예, 이는 추가 쿼리를 실행하고 있음을 의미합니다.

SELECT COUNT(*) FROM Answers WHERE post_id = @id

또는 더 일반적으로(홈 페이지에 표시하는 경우):

SELECT p.post_id, 
     p.<additional post fields>,
     a.AnswerCount
FROM Posts p
    INNER JOIN AnswersCount_view a
    ON <join criteria>
WHERE <home page criteria>

하지만 이로 인해 일반적으로 INDEX SCAN 자원을 사용하는 것보다 자원을 사용하는 것이 더 효율적일 수 있습니다. READ ISOLATION.

고양이의 가죽을 벗기는 방법에는 여러 가지가 있습니다.데이터베이스 스키마의 조기 비정규화로 인해 확장성 문제가 발생할 수 있습니다.

READ_COMMITTED_SNAPSHOT을 켜기로 설정하기를 원하지만 기본적으로는 그렇지 않습니다.이는 MVCC 의미를 제공합니다.Oracle이 기본적으로 사용하는 것과 동일합니다.MVCC 데이터베이스를 갖는 것은 매우 유용하며, 이를 사용하지 않는 것은 미친 짓입니다.이를 통해 트랜잭션 내에서 다음을 실행할 수 있습니다.

사용자 업데이트 FirstName = 'foobar';//1년 동안 잠을 자기로 결정합니다.

그 사이에 위의 내용을 커밋하지 않고도 모든 사람이 계속해서 해당 테이블에서 문제 없이 선택할 수 있습니다.MVCC에 익숙하지 않다면, MVCC 없이도 살 수 있었다는 사실에 충격을 받을 것입니다.진지하게.

커밋되지 않은 읽기로 기본값을 설정하는 것은 좋은 생각이 아닙니다.당신은 의심할 바 없이 불일치를 야기하고 결국 당신이 현재 겪고 있는 것보다 더 나쁜 문제에 직면하게 될 것입니다.스냅샷 격리는 잘 작동할 수 있지만 SQL Server가 작동하고 거대한 tempdb에 로드합니다.

당신이 해야 할 일은 다음과 같습니다:T-SQL에서 try-catch를 사용하여 교착 상태 조건을 검색합니다.이런 일이 발생하면 쿼리를 다시 실행하세요.이는 표준 데이터베이스 프로그래밍 방식입니다.

Paul Nielson의 책에는 이 기술의 좋은 예가 있습니다. SQL Server 2005 성경.

내가 사용하는 빠른 템플릿은 다음과 같습니다.

-- Deadlock retry template

declare @lastError int;
declare @numErrors int;

set @numErrors = 0;

LockTimeoutRetry:

begin try;

-- The query goes here

return; -- this is the normal end of the procedure

end try begin catch
    set @lastError=@@error
    if @lastError = 1222 or @lastError = 1205 -- Lock timeout or deadlock
    begin;
        if @numErrors >= 3 -- We hit the retry limit
        begin;
            raiserror('Could not get a lock after 3 attempts', 16, 1);
            return -100;
        end;

        -- Wait and then try the transaction again
        waitfor delay '00:00:00.25';
        set @numErrors = @numErrors + 1;
        goto LockTimeoutRetry;

    end;

    -- Some other error occurred
    declare @errorMessage nvarchar(4000), @errorSeverity int
    select    @errorMessage = error_message(),
            @errorSeverity = error_severity()

    raiserror(@errorMessage, @errorSeverity, 1)

    return -100
end catch;    

과거에 저에게 효과적이었던 한 가지는 모든 쿼리와 업데이트가 동일한 순서로 리소스(테이블)에 액세스하도록 하는 것이었습니다.

즉, 한 쿼리가 Table1, Table2 순서로 업데이트되고 다른 쿼리가 Table2, Table1 순서로 업데이트되면 교착 상태가 발생할 수 있습니다.

LINQ를 사용하고 있으므로 업데이트 순서를 변경할 수 있는지 확실하지 않습니다.그러나 그것은 볼만한 것입니다.

귀하의 사용자 프로필이 몇 초 정도 오래된 경우에도 신경쓰시겠습니까?

몇 초 정도는 확실히 허용될 것입니다.어쨌든, 엄청난 수의 사람들이 동시에 답변을 제출하지 않는 한, 그렇게 길지는 않을 것 같습니다.

나는 이것에 대해 Jeremy의 의견에 동의합니다.각 컨트롤러 또는 페이지별로 새 데이터 컨텍스트를 만들어야 하는지 묻는 질문이 있습니다. 저는 모든 독립 쿼리에 대해 새 데이터 컨텍스트를 만드는 경향이 있습니다.

나는 현재 당신처럼 정적 컨텍스트를 구현하는 데 사용되는 솔루션을 구축 중이며 스트레스 테스트 중에 서버의 짐승(수백만 개 이상)에 수많은 요청을 던졌을 때 무작위로 읽기/쓰기 잠금도 얻고 있었습니다.

쿼리당 LINQ 수준에서 다른 데이터 컨텍스트를 사용하도록 전략을 변경하고 SQL Server가 연결 풀링 마법을 작동할 수 있다고 신뢰하자마자 잠금이 사라지는 것처럼 보였습니다.

물론 시간적 압박이 있어서 동시에 여러 가지를 시도했기 때문에 문제가 해결되었는지 100% 확신할 수는 없지만 높은 수준의 자신감을 가지고 있습니다. 그렇게 표현하겠습니다. .

더티 읽기를 구현해야 합니다.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

쿼리에 완벽한 트랜잭션 무결성이 절대적으로 필요하지 않은 경우 동시성이 높은 테이블에 액세스할 때 더티 읽기를 사용해야 합니다.나는 귀하의 Posts 테이블이 그 중 하나라고 가정합니다.

이로 인해 쿼리가 커밋되지 않은 트랜잭션의 데이터에 대해 작동하는 소위 "팬텀 읽기"가 발생할 수 있습니다.

여기서는 은행 사이트를 운영하는 것이 아니기 때문에 매번 완벽한 정확성이 필요하지 않습니다.

더티 읽기를 사용하세요.완벽한 정확성을 제공하지는 못하지만 교착 상태 문제를 해결해야 한다는 점에서는 맞습니다.

그렇지 않으면 우리가 하는 모든 LINQ 호출(글쎄, 단순 읽기 호출, 대부분은 대부분)을 3~4줄의 트랜잭션 코드 블록으로 묶어야 하는데, 이는 보기 흉합니다.

"기본 데이터베이스 컨텍스트"에서 더티 읽기를 구현하는 경우 트랜잭션 무결성이 필요한 경우 언제든지 더 높은 격리 수준을 사용하여 개별 호출을 래핑할 수 있습니다.

그렇다면 재시도 메커니즘을 구현할 때의 문제점은 무엇입니까?교착 상태가 발생할 가능성은 항상 존재하므로 이를 식별하고 다시 시도할 수 있는 논리를 갖추는 것은 어떨까요?

최소한 다른 옵션 중 일부는 재시도 시스템이 거의 시작되지 않을 때 항상 발생하는 성능 저하를 도입하지 않습니까?

또한 재시도가 발생할 때 일종의 로깅을 잊지 않도록 하여 레어가 자주 발생하는 상황에 빠지지 않도록 하세요.

Jeremy의 답변을 보니 각 데이터 작업에 새 DataContext를 사용하는 것이 가장 좋은 방법이라는 말을 들었던 기억이 납니다.Rob Conery는 DataContext에 대한 여러 게시물을 작성했으며 싱글톤을 사용하는 대신 항상 이에 대한 소식을 전합니다.

Video.Show에 사용한 패턴은 다음과 같습니다(CodePlex의 소스 보기 링크):

using System.Configuration;
namespace VideoShow.Data
{
  public class DataContextFactory
  {
    public static VideoShowDataContext DataContext()
    {
        return new VideoShowDataContext(ConfigurationManager.ConnectionStrings["VideoShowConnectionString"].ConnectionString);
    }
    public static VideoShowDataContext DataContext(string connectionString)
    {
        return new VideoShowDataContext(connectionString);
    }
  }
}

그런 다음 서비스 수준에서(또는 업데이트의 경우 더욱 세부적으로) 다음을 수행합니다.

private VideoShowDataContext dataContext = DataContextFactory.DataContext();

public VideoSearchResult GetVideos(int pageSize, int pageNumber, string sortType)
{
  var videos =
  from video in DataContext.Videos
  where video.StatusId == (int)VideoServices.VideoStatus.Complete
  orderby video.DatePublished descending
  select video;
  return GetSearchResult(videos, pageSize, pageNumber);
}

커밋되지 않은 읽기로 격리 수준을 설정하는 것이 다른 쿼리에 부정적인 영향을 미치지 않는 한 Greg의 의견에 동의해야 합니다.

Jeff, 데이터베이스 수준에서 설정하면 다음과 같은 쿼리에 어떤 영향을 미치는지 알고 싶습니다.

Begin Tran
Insert into Table (Columns) Values (Values)
Select Max(ID) From Table
Commit Tran

내 프로필이 몇 분이라도 오래되어도 괜찮습니다.

읽기가 실패한 후 다시 시도하고 있습니까?수많은 무작위 읽기를 실행할 때 읽을 수 없을 때 일부가 적중하는 것은 확실히 가능합니다.제가 작업하는 대부분의 응용 프로그램은 읽기 횟수에 비해 쓰기 횟수가 매우 적으며 읽기 횟수는 현재 얻는 숫자에 미치지 못할 것이라고 확신합니다.

"READ UNCOMMITTED"를 구현해도 문제가 해결되지 않으면 처리에 대해 더 많이 알지 못하면 도움을 주기가 어렵습니다.이 동작에 도움이 되는 다른 조정 옵션이 있을 수 있습니다.일부 MSSQL 전문가가 구조에 나서지 않는 한 문제를 공급업체에 제출하는 것이 좋습니다.

나는 계속해서 모든 것을 조정할 것입니다.디스크 하위 시스템의 성능은 어떻습니까?평균 디스크 큐 길이는 얼마입니까?I/O가 백업되는 경우 실제 문제는 교착 상태에 빠지는 두 쿼리가 아니라 시스템에 병목 현상을 일으키는 또 다른 쿼리일 수 있습니다.조정된 20초 소요 쿼리에 대해 언급하셨는데, 다른 쿼리도 있나요?

장기 실행 쿼리를 줄이는 데 집중하면 교착 상태 문제가 사라질 것이라고 확신합니다.

동일한 문제가 있었고 서버에 DTS가 활성화되어 있지 않기 때문에(!) TransactionScope에서 "IsolationLevel = IsolationLevel.ReadUncommitted"를 사용할 수 없습니다.

그게 내가 확장 방법으로 한 일입니다.

public static void SetNoLock(this MyDataContext myDS)
{
    myDS.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

따라서 중요한 동시성 테이블을 사용하는 선택을 위해 다음과 같이 "nolock"을 활성화합니다.

using (MyDataContext myDS = new MyDataContext())
{
   myDS.SetNoLock();

   //  var query = from ...my dirty querys here...
}

제안을 환영합니다!

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