Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
valv
Member

Откуда:
Сообщений: 122
добрый день,
вопрос про MIN_ACTIVE_ROWVERSION() на зеркальной secondary DB в технологии AlwaysOn, asynchronous commit.
есть таблица с полем типа [RowVersion], в которую добавляются строки.
раз в 5 минут ХП отлавливает все новые строки. важно не потерять ни одной, для этого используем простой запрос:
declare @LastRowVersion binary(8) = (select max(RowVersion) from [tb] where RowVersion < MIN_ACTIVE_ROWVERSION())
declare @PrevLastRowVersion binary(8) = ... /* last handled RowVersion */
select * from [tb] where [RowVersion] > @PrevLastRowVersion and [RowVersion] <= @LastRowVersion
это работало без проблем на основой БД;
теперь перешли на AlwaysOn технологию, перенесли ХП без изменений в БД на сервере, где находится AlwaysOn зеркало.
и вдруг начали теряться строки. вроде бы, строка с меньшим RowVersion оказывается на зеркале позже, чем строка с большим RowVersion, и MIN_ACTIVE_ROWVERSION почему-то не решает проблемы.
вопрос: MIN_ACTIVE_ROWVERSION обязано работать на AlwaysOn зеркале? если обязано, в чём может быть проблема?
спасибо.
27 фев 14, 14:01    [15639621]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Crimean
Member

Откуда:
Сообщений: 13147
по-моему, первый запрос не имеет смысла
но проблем добавлять все равно не должен
а по теме - скорее всего, "накосячено" таки в always on с этими стэмпами
не должно бы терять
p.s.
а RCSI включен для базы? просто интересно
без него надо бы уровень изоляции поднимать, а то действительно можно терять записи даже и без зеркал всяких
27 фев 14, 14:42    [15640016]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
valv
Member

Откуда:
Сообщений: 122
Crimean
по-моему, первый запрос не имеет смысла
запрос нужен чтобы получить последний [RowVersion] и дальше работать только с ним, так как в процессе работы ХП MIN_ACTIVE_ROWVERSION может возвращать разные значения.
Crimean
а RCSI включен для базы? просто интересно
включен
27 фев 14, 14:51    [15640103]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Crimean
Member

Откуда:
Сообщений: 13147
первый запрос *не нужен* :) инфа 146%
а по остальному - таки похоже на косяк
27 фев 14, 15:38    [15640650]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
valv
declare @LastRowVersion binary(8) = (select max(RowVersion) from [tb] where RowVersion < MIN_ACTIVE_ROWVERSION())
declare @PrevLastRowVersion binary(8) = ... /* last handled RowVersion */
select * from [tb] where [RowVersion] > @PrevLastRowVersion and [RowVersion] <= @LastRowVersion
Может я что-то непонимаю?

MIN_ACTIVE_ROWVERSION() - вещь понятная и правильная, особенно когда надо несколько таблиц перенести. НО

1. Зачем искать max(RowVersion) в таблице? Просто:
declare @LastRowVersion binary(8) = MIN_ACTIVE_ROWVERSION()

2. А как вы гарантируете что пока делается считывание данных из таблиц, уже не будет параллельного изменения строк из диапазона { @PrevLastRowVersion, @LastRowVersion }.
Вот вы эти строки и потеряете.
Нужно как-то запретить изменения. TableLock перед всем этим ?
27 фев 14, 19:56    [15642648]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
valv
Member

Откуда:
Сообщений: 122
Mnior
valv
declare @LastRowVersion binary(8) = (select max(RowVersion) from [tb] where RowVersion < MIN_ACTIVE_ROWVERSION())
declare @PrevLastRowVersion binary(8) = ... /* last handled RowVersion */
select * from [tb] where [RowVersion] > @PrevLastRowVersion and [RowVersion] <= @LastRowVersion

Может я что-то непонимаю?

MIN_ACTIVE_ROWVERSION() - вещь понятная и правильная, особенно когда надо несколько таблиц перенести. НО

1. Зачем искать max(RowVersion) в таблице? Просто:
declare @LastRowVersion binary(8) = MIN_ACTIVE_ROWVERSION()
хорошо, согласен, можно и так. мелкий ньюанс в логиге ХП, ищется предпоследняя строка. на работу никак не влияет.
Mnior
2. А как вы гарантируете что пока делается считывание данных из таблиц, уже не будет параллельного изменения строк из диапазона { @PrevLastRowVersion, @LastRowVersion }.
Вот вы эти строки и потеряете.
строки только добавляются и не меняются, только inserts.
Mnior
Нужно как-то запретить изменения. TableLock перед всем этим ?

в любом случае, на зеркале AlwaysOn невозможно запретить изменения.
проблема в том, что система больше года работала на основном сервере, потерянные строки появились при переходе на работу с зеркалом AlwaysOn.
более того: в тестовых целях включили логирование на основном сервере и на реплике параллельно с такой же системой на зеркале AlwaysOn, и получили: строка потеряна на зеркале, однако поймана и и на основном сервере, и на реплике.
27 фев 14, 21:08    [15642980]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Crimean
Member

Откуда:
Сообщений: 13147
2 Mnior

> declare @LastRowVersion binary(8) = MIN_ACTIVE_ROWVERSION()

я об этом и говорил. только или делать -1 или работать не по <= а по <, но это не суть

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

а это как раз и решает MIN_ACTIVE_ROWVERSION. и решает эффективно. я так же работаю по timestamp и до RCSI были потери данных, приходилось уровень изоляции поднимать. с RCSI вообще все шоколадно стало

а вот на зеркале похоже именно проблема именно в кореляции timestamp / rowversion строк данных и MIN_ACTIVE_ROWVERSION. и с always я вполне допускаю провтыки в логике MIN_ACTIVE_ROWVERSION
27 фев 14, 21:29    [15643070]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
valv
строки только добавляются и не меняются, только inserts.
Теперь понятно.
valv
вроде бы, строка с меньшим RowVersion оказывается на зеркале позже, чем строка с большим RowVersion, и MIN_ACTIVE_ROWVERSION почему-то не решает проблемы.
вопрос: MIN_ACTIVE_ROWVERSION обязано работать на AlwaysOn зеркале? если обязано, в чём может быть проблема?
Я уже было накатал "ответ" и понял что не всё тут просто.
Типа легко было допустить ошибку так как этот счётчик завязан на дофига процессов в базе и сама работа базы задевает его.
Но подумав о природе транзакционности понял что выкусить RowVersion из лога нельзя. Если конечно не делать полную симуляцию.
Есть подозрения что RowVersion в логе не идут всего чётко последовательно. Некоторые вещи могут идти с некоторыми девиациями, которые не влияют на общий процесс (иногда не важно как строки меняются внутри одной микро-транзакции, и в принципе и иногда между ними).

Просто это нормально когда данные с меньшим RowVersion появляются позже чем с большим.
Перед тем как закоментить решил пойти покурить, но параллельно то вставка же идёт.
И почему тогда оно фунчиклирует на главном сервере?

А кто сказал что фунчиклирует? Оно может на любом не работать! Нужно выполнять ещё одно требование:
Чтение данных обязано быть Serialized или последовательным.
В принципе так оно и происходит в реальном - читая к примеру по индексу [RowVersion] процесс чтения будет локироваться пока все транзакции занявшие версии строк из диапазона не "докурят".

Я конечно не трогал в руках этот AlwaysOn, но не уверен что помимо эмуляции применения транзакций (коих можно напридумать много вариантов) эмулируются и локировки.
Crimean
я об этом и говорил. только или делать -1
В много-табличном варианте это не подходит. Линия среза должна быть чёткой. Да и с одной тоже есть косяк "остановки".
Crimean
> как вы гарантируете что пока делается считывание данных из таблиц,
> уже не будет параллельного изменения строк из диапазона
а это как раз и решает MIN_ACTIVE_ROWVERSION
Блин, я только сейчас понял что MinActive же означает минимальный RowVersion, который и ниже оного уже не участвует ни в одной транзакции. Тогда понятно.
Тогда неважно какой даже уровень сериализации транзакций - транзакций то уже нет.
Crimean
с RCSI вообще все шоколадно стало
Снапшот не локируется, но и не видит тех строк которые ещё не применены (т.к. сам считывает предыдущие версии - отсутствия строк).
Но как помогает он от завышенного RowVersion? - непонятно

А баг надо найти (или зарегать) в connect.microsoft.com
Я не нашёл, так что вам регать. И я жду чтоб заплюсовать.
28 фев 14, 04:14    [15643920]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Crimean
Member

Откуда:
Сообщений: 13147
Mnior,

да ничего там не теряется. в блогах есть пара толковых статей про min_active
а вот обычный shared / read_committed не катит - с ним теряются строки как раз, повышать приходилось. в сложных раскладах теряются, не без того, но кому от этого легче + оно было таки воспроизводимо
28 фев 14, 12:08    [15645195]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Crimean
в блогах есть пара толковых статей про min_active
"в блогах" подразумевается "те самые о которых знают все" и только я не понял или вообще.
Может укажете.
И там что-то большее чем понятие что "не используемое в транзакциях"?
Crimean
а вот обычный shared / read_committed не катит - с ним теряются строки как раз, повышать приходилось. в сложных раскладах теряются, не без того, но кому от этого легче + оно было таки воспроизводимо
Мне понимать надо, а не просто наличие по ХЗ почему (реальность мира, особенность частного (M$) решения, баг, неправильные тесты, использование не по назначению).

Т.е. не вижу корреляции вашего ответа к тому что я написал выше.
28 фев 14, 14:52    [15646874]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
valv
Member

Откуда:
Сообщений: 122
решение проблемы:
функция MIN_ACTIVE_ROWVERSION() работает некорректно в secondary реплике при availability mode = asynchronous commit. возможно, тоже и в других режимах.
результат функции это varbinary всегда больше настоящего на 1000-2000.
решение: в БД добавляем таблицу, в которую N раз в секунду записываем MIN_ACTIVE_ROWVERSION().
на secondary реплике это значение читаем.
8 июн 14, 11:45    [16138450]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Prolog
Member

Откуда: Москва
Сообщений: 2793
Crimean
> как вы гарантируете что пока делается считывание данных из таблиц,
> уже не будет параллельного изменения строк из диапазона

а это как раз и решает MIN_ACTIVE_ROWVERSION. и решает эффективно. я так же работаю по timestamp и до RCSI были потери данных, приходилось уровень изоляции поднимать. с RCSI вообще все шоколадно стало

Если используется RCSI какая разница между

select * from [tb] where [RowVersion] > @PrevLastRowVersion and [RowVersion] < MIN_ACTIVE_ROWVERSION()
и
select * from [tb] where [RowVersion] > @PrevLastRowVersion

Т.е. нужна ли вообще MIN_ACTIVE_ROWVERSION?
4 фев 15, 12:04    [17216262]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Crimean
Member

Откуда:
Сообщений: 13147
Prolog,

уже оффтоп, но
http://blogs.msdn.com/b/synchronizer/archive/2008/02/06/sql-server-change-tracking-vs-min-active-rowversion.aspx

пропускаете вы записи, пропускаете, без этой функции, даже с RCSI
вопрос в том, что:
- вы знаете "последнее обработанное" значение rowversion (после которого изменений не было)
- началась транзакция (ID#1)
- изменилась другая запись (ID#2)
- вы прочитали изменения (ID#2)
- вы обработали изменения (ID#2)
- вы сохранили последнее обработанное значение для rowversion (для ID#2)
- транзакцию закоммитили (ID#1)
- вы по факту уже не получите запись (ID#1), которая была изменена в той самой долгоиграющей транзакции, ибо она получила rowversion меньше, чем (ID#2)

все это время min_active содержит выданное для транзакции (ID#1) значение
что не позволит вам прочитать (ID#2)
и только после коммита (или отката) ID#1 - вы получите обе записи
4 фев 15, 12:22    [17216417]     Ответить | Цитировать Сообщить модератору
 Re: как MIN_ACTIVE_ROWVERSION() работает на AlwaysOn ?  [new]
Prolog
Member

Откуда: Москва
Сообщений: 2793
Спасибо, посмотрю.
4 фев 15, 13:29    [17216936]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить