Значение SQL MIN_ACTIVE_ROWVERSION() не изменяется в течение длительного времени

Мы устраняем неполадки своего рода Sync Framework между двумя базами данных SQL Server на отдельных серверах (как SQL Server 2008 Enterprise 64 бит SP2 - 10.0.4000.0), так и через связанные соединения с сервером, и мы достигли точки, в которой мы "как бы застрял.

Логика для определения записей, которые ожидаются для синхронизации, конечно, основана на значениях ROWVERSION, включая использование MIN_ACTIVE_ROWVERSION(), чтобы избежать грязных чтений.

Все операции SELECT инкапсулируются в SP на каждой стороне "источника". Это схематический пример одного SP:

    PROCEDURE LoaderRetrieve(@LastStamp bigint, @Rows int)
    BEGIN
    ...
    (vars handling)
    ...

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT

    Select TOP (@Rows) Field1, Field2, Field3
    FROM Table
    WHERE [RowVersion] > @LastStampAsRowVersionDataType    
    AND [RowVersion] < @MinActiveVersion  
    Order by [RowVersion] 

    END

Подход работает очень хорошо, мы обычно синхронизируем записи с ожидаемой скоростью 600k/час (работа каждые 30 секунд, размер партии = 5k), но в какой-то момент процесс синхронизации не находит ни одной записи, которая будет передана, хотя имеется несколько тысяч записей с величиной ROWVERSION, превышающей параметр @LastStamp.

При проверке причины мы обнаружили, что значение MIN_ACTIVE_ROWVERSION() имеет значение меньше (или немного больше, всего 5 или 10 приращений) при поиске @LastStamp. Это, конечно, не должно быть проблемой, поскольку был введен подход MIN_ACTIVE_ROWVERSION(), чтобы избежать грязных чтений и задних проблем, НО:

Проблема, которую мы видим в некоторых случаях во время вышеприведенного сценария, заключается в том, что значение для MIN_ACTIVE_ROWVERSION() не изменяется в течение длительного (очень длительного) периода времени, например 30/40 минут, иногда более одного часа, И это значение намного меньше значения @@DBTS.

Мы сначала подумали, что это связано с ожидающей транзакции БД, еще не совершенной. В соответствии с определением MSDN о MIN_ACTIVE_ROWVERSION() (ссылка):

Возвращает самое низкое активное значение rowversion в текущей базе данных. Значение rowversion является активным, если оно используется в транзакции, которая еще не была совершена.

Но при проверке сеансов (sys.sysprocesses) с open_tran > 0 в течение продолжительности этой проблемы мы не смогли найти какой-либо сеанс с ожиданием больше нескольких секунд, только одно или два появления +/- 5 минут сеансы waittime.

Итак, на данный момент мы пытаемся понять ситуацию: MIN_ACTIVE_ROWVERSION() не меняется в течение огромного периода времени, и в течение этого периода времени не обнаружены незавершенные транзакции с длинными ожиданиями.

Я не администратор базы данных, и может случиться так, что нам не хватает чего-то на картинке, чтобы проанализировать эту проблему, сделав некоторые исследования на форумах, и блоги не смогли найти никакой другой подсказки. До сих пор open_tran > 0 была веской причиной, но в сложившихся обстоятельствах я понял, что есть что-то еще и не знаю почему.

Любая обратная связь приветствуется.

Ответы

Ответ 1

Хорошо, я наконец нашел решение после копания немного больше.

Проблема в том, что мы искали сеансы долгое время, но реальная сделка заключалась в том, чтобы находить сеансы, которые имеют активную партию с течением времени.

Если есть сеанс, где open_tran = 1, чтобы получить точно с того момента, когда эта транзакция открыта (и, конечно, все еще активна, еще не зафиксирована), должно быть проверено поле last_batch из sys.sysprocesses.

Используя этот запрос:

    select 
    batchDurationMin= DATEDIFF(second,last_batch,getutcdate())/60.0,
    batchDurationSecs= DATEDIFF(second,last_batch,getutcdate()),
    hostname,open_tran,* from sys.sysprocesses a
    where spid > 50
    and a.open_tran >0  
    order by last_batch asc

мы могли бы идентифицировать сеанс с активным 30-минутным открытием. И с помощью значений имени хоста и некоторых проверок внутри веб-служб (а также с помощью dbcc inputbuffer) мы обнаружили ответственный процесс.

Итак, последний вопрос на самом деле - "действительно активный сеанс с незафиксированной транзакцией", поэтому MIN_ACTIVE_ROWVERSION() не изменяется. Мы просто смотрели процессы с неправильными критериями.

Теперь, когда мы знаем, какой процесс ведет себя следующим образом, следующим шагом будет его улучшение.

Надеюсь, что это принесет пользу кому-то другому.