Значение 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()
не изменяется. Мы просто смотрели процессы с неправильными критериями.
Теперь, когда мы знаем, какой процесс ведет себя следующим образом, следующим шагом будет его улучшение.
Надеюсь, что это принесет пользу кому-то другому.