Как определить уровень изоляции запроса?

Администрирование - Оптимизация БД (HighLoad)

Как с помощью Profiler определить уровень изоляции запроса и зачем это нужно

Этот вопрос возник у нас на проекте по внедрению ЗУП2.5 с численностью 20000 и максимальным количеством одновременных пользовательских сессий 200.

На этапе опытной эксплуатации при расчете зарплаты пользователи начали интенсивно работать с документами «Начисление зарплаты сотрудникам организаций». Количество строк документов доходило до 2500 строк.  У пользователей начали появляться сообщения «Конфликт блокировок при выполнении транзакции», и расчет приходилось запускать заново.

Стали разбираться. Оказалось, мы столкнулись  с эффектом «Избыточной блокировки». Обычно этот эффект появляется при параллельном проведении документов. Если объяснять по-простому, один из документов блокирует большой объем данных на все время проведения документа. Эта блокировка задерживает проведение остальных документов, которые пытаются прочитать заблокированные данные. Это мешает параллельной работе пользователей и замедляет рабочий процесс. Вообще блокировка данных при проведении документов вещь полезная, она сохраняет целостность данных и гарантирует правильность выполнения расчетных алгоритмов. Но бывает так, что либо объем заблокированных данных чрезмерен, либо время блокировки слишком велико. В результате мы имеем многопользовательскую систему, которая по сути является однопользовательской: вместо параллельного проведения документов - последовательное.

Рассмотрим два примера с необходимой блокировкой и с избыточной.

Представим такую ситуацию – есть два документа «Начисление зарплаты сотрудникам организаций», в которых указан одинаковый налоговый период, а на закладке НДФЛ указаны одинаковые физлица. Гипотетически допустим, что расчет и проведение следуют один за другим в одной транзакции. Рассмотрим случай, когда блокировка вообще отсутствует. Если последовательно запускать расчет и проведение сначала одного, а затем другого документа, то в первом сумма НДФЛ посчитается правильно, а во втором будет равна нулю, т.к. расчетный и фактически начисленный НДФЛ на момент проведения второго документа будут совпадать. Но если обрабатывать эти документы параллельно, то они одновременно начислят НДФЛ, не подозревая о существовании друг друга, и в результате налог удвоится. Но если блокировка настроена верно, то первый документ успеет раньше прочитать и заблокировать данные о фактически начисленном налоге в регистре «НДФЛ расчеты с бюджетом» по сотруднику Пушкину А.С. Из этого запроса будет видно, что фактический налог за январь пока не начислялся и значит надо его рассчитать и выполнить движение по регистру. Блокировка будет отпущена только после завершения записи в регистре. Второй документ, дойдя до запроса чтения фактически начисленного налога будет поставлен системой на ожидание до тех пор, пока первый документ не закончит транзакцию проведения, после чего он прочитает в запросе, что налог уже начислен и поймет, что расчет выполнять не надо. Это необходимая блокировка.

Конечно, этот пример притянут за уши для простоты объяснения. На самом деле логика ЗУП 2.5 такова, что для задвоения НДФЛ пользователям не нужно прикладывать особых усилий. НДФЛ рассчитывается до проведения документа, а при проведении содержимое табличной части просто заносится в регистры без всякой проверки. Пользователям между расчетом и проведением предоставляется возможность посмотреть будущий результат и при необходимости поправить руками. Конечно это большой плюс в пользу гибкости ЗУПа, но предъявляет высокие требования к профессиональному уровню расчетчиков. Поэтому вопрос предотвращения задвоения НДФЛ решается организационным путем или с помощью дополнительных проверочных отчетов. Конечно, в ЗУП2.5 есть регистры, которые рассчитываются и записываются одновременно при проведении документа, например «НДФЛ к зачету», но этот пример пришлось бы дольше объяснять ;).

А теперь представим другую ситуацию. При проведении документа выполняется запрос, который должен отобрать документы, в которых присутствуют сотрудники из этого документа. Но запрос написан так, что сервер SQL вынужден находить нужные документы методом перебора. Для эксперта по технологическим вопросам это означает, что вместо INDEX SEEK выполняется TABLE SCAN, т.е. вместо поиска по таблице индексов происходит последовательный перебор записей в самой таблице. Причем в процессе перебора блокируются все записи, к которым прикоснулся запрос, даже те, в которых отсутствуют искомые сотрудники. И эта блокировка будет действовать до конца завершения проведения документа, что будет препятствовать параллельному проведению документов с другими сотрудниками. Это избыточная блокировка.

Лечение избыточных блокировок может идти двумя путями. Первый - это оптимизация запросов, выполняемых внутри транзакций и добавление необходимых табличных индексов в конфигураторе. Второй - это перевод выполнения SQL-запросов на самый низкий уровень изоляции, когда при выполнении запросов записи в таблицах блокируются только на момент выполнения самого запроса, либо не блокируются вовсе. А необходимые блокировки устанавливаются средствами объекта «БлокировкаДанных» и выполняются на стороне сервера 1С.

Теперь немного теории про уровни изоляции на SQL сервере:

  1. В автоматическом режиме в транзакциях используется уровень изоляции SERIALIZABLE. Этот уровень накладывает на таблицы с данными блокировку типа S (запрещает запись и проверяет нет ли в этот момент параллельных записей) до конца транзакции на все данные, которых коснулись запросы, и блокировку типа X (запрещает чтение и запись)  на все данные, по которым произошла запись. На таблицы индексов также до конца транзакции накладываются блокировки типа RangeS в запросах, и RangeX при записи.
  2. В управляемом режиме в транзакциях используется уровень изоляции READ COMMITTED. Этот уровень на записанные данные также устанавливает блокировку типа X до конца транзакции. Но при выполнении запросов на данные накладывает блокировку типа S, а при завершении запроса блокировка снимается не дожидаясь завершения транзакции. На таблицы индексов никаких блокировок не накладывается.
  3. Если база данных переведена в режим READ COMMITTED SNAPSHOT, то в управляемом режиме при чтении данных не накладывается блокировка типа S, есть только блокировка типа X при записи.

Тоже самое чуть более подробно в таблице:

Транзакция

Уровень изоляции

Действие

Блокировка

Вне транзакции

READ UNCOMMITTED

Чтение

-

Управляемая транзакция

READ COMMITTED SNAPSHOT

Чтение

-

Запись

X

READ COMMITTED

Чтение

S (запрос)

Запись

X

Автоматическая транзакция

REPEATABLE READ

Чтение объектов

S

Чтение объектов «Для изменения»

U

Запись объектов

X

SERIALIZABLE

Чтение регистров

S, RangeS

Чтение регистров «Для изменения»

U, RangeU

Запись регистров

X, RangeX

Обычно лечение начинают с понижения уровня изоляции, т.к. это не особо трудозатратно и дает быстрый эффект. Достаточно перевести конфигурацию из «Автоматического» режима управления блокировкой данных в «Управляемый», и транзакции начнут выполняться на уровне изоляции типа READ COMMITTED, вместо SERIALIZABLE или REPEATABLE READ.

Чтобы переключить базу данных в режим READ COMMITTED SNAPSHOT (RCSI) необходимо в «SQL Server Management Studio» в свойствах базы данных установить параметр "Is Read Committed Snapshot On" в значение "True":

В некоторых источниках предлагают установить параметр "Allow Snapshot Isolation" в значение "True", но в этом нет необходимости, т.к. это приведет к включению другого режима изоляции SNAPSHOT, который не поддерживается платформой 1С (На момент написания статьи релиз платформы 8.3.9).

Режим управления блокировкой данных задается для неявных транзакций, которые выполняются при записи или при проведении документов, т.е. внутри  предопределенных процедур типа ПриЗаписи() или ОбработкаПроведения(). Но большинство «тяжелых» вычислений в типовой конфигурации ЗУП2.5 происходит при выполнении команды «Рассчитать». При этом в модуле объекта запускается процедура РассчитатьВсе(), внутри которой неоднократно повторяется конструкция НачатьТранзакцию() …ЗафиксироватьТранзакцию(). Это явно указанные транзакции, внутри которых происходит запись и очистка регистров, выполняются запросы. Нам необходимо убедиться, что при переключении конфигурации в управляемый режим в процедуре «РассчитатьВсе()» явно указанные транзакции также начинают выполняться на уровне READ COMMITTED.

Для этого проведем небольшой эксперимент:

  • Запустим SQL Server Profiler.
  • Запустим «NEW TRACE».
  • Выполним подключение к серверу SQL.
  • В окне «Trace Properties» на закладке «General» выберем «Use the template» = «Blank», а на закладке «Events Selections» раскроем группу «Stored Procedures» и выберем «RPC:Complited». По кнопке «Column Filters» укажем имя базы и длительность выполнения запросов более 1.

  • Кнопку RUN пока нажимать не будем, т.к. нам надо сначала запустить базу данных в режиме отладки и остановить выполнение расчета документа «Начисление зарплаты сотрудникам организаций» перед выполнением самого массивного запроса. Например, это будет команда
    «Результат = Запрос.ВыполнитьПакет();» в функции «ПолучитьДанныеНДФЛПоРегистратору» в общем модуле «ПроведениеРасчетов». Здесь происходит выполнение основного запроса для расчета НДФЛ. Поставим на ней точку останова отладчика и запустим расчет в документе.

  • После того как отладчик остановится, нажмем кнопку RUN в Профайлере.
  • Теперь сделаем один шаг в отладчике кнопкой F11. Когда запрос будет выполнен и отладчик перейдет на следующий шаг, остановим чтение Профайлера кнопкой «Pause Selected Trace».
  • Теперь найдем самый длительный запрос по колонке Duration и внимательно изучим текст запроса. Если при обращении к реальной (а не временной) таблице после слова WITH стоит SERIALIZABLE, то мы имеем дело с автоматическим режимом блокировки. Если ничего не стоит – то с управляемым.

Если в хинте запроса (Hint – это параметр после слова WITH, позволяющий влиять на план выполнения запроса) не указан уровень изоляции, то выполняется уровень изоляции, установленный по умолчанию для текущей SQL-сессии. Определить уровень изоляции, действующий по умолчанию для текущих сессий можно, например, с помощью команды в «SQL Server Management Studio»:

SELECT CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL
FROM sys.dm_exec_sessions

В управляемом режиме для всех сессий будет указан режим Read Committed.

Таким образом мы получили экспериментальное подтверждение того, что после перевода в управляемый режим всей конфигурации, в этом режиме начинают работать не только процедуры записи и проведения, но и процедуры расчета документов ЗУП. А это значит, что количество сообщений о конфликте блокировок будет существенно снижено, а параллельность работы с базой данных увеличится.

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

Настройка  управляемых блокировок – это тема для отдельной статьи. Вкратце скажу, что программно управляемые блокировки устанавливаются с помощью объекта «БлокировкаДанных». Сами управляемые блокировки работают уже не на уровне SQL сервера, как в случае с автоматическими блокировками, а на уровне сервера 1С. Для определения необходимых и достаточных управляемых блокировок надо понимать логику программы одновременно на уровне бизнес-процессов и на уровне архитектуры таблиц СУБД.

Но на мой взгляд, для таких конфигураций, как ЗУП2.5 вообще нет смысла использовать какие-либо блокировки, лучше использовать проверочные отчеты для выявления нарушения целостности данных - на практике это самый быстрый способ расчета зарплаты. Особенно на крупных предприятиях, где точно есть сотрудники с внутренним совмещением в обособленных подразделениях, а за каждым ОП закреплен отдельный расчетчик, что и является причиной задвоения НДФЛ. Какой бы не был вышколенный персонал, сама идеология конфигурации допускает возможность задвоения НДФЛ. Поэтому лучше не мешать пользователям работать параллельно во время массированных месячных расчетов, а по завершении точечно и быстро исправить небольшой процент ошибок, чем заставлять их сидеть и нервничать в очереди из-за страха допустить хотя бы одну ошибку. В этом проекте мы использовали самописный отчет «Проверка НДФЛ», который отображал сотрудников с некорректным НДФЛ.

Так же на этом проекте мы столкнулись с эффектом «Эскалация блокировок», когда SQL сервер сам принимает решение, что надо укрупнить область наложения блокировок вплоть до блокировки целиком всей таблицы. В результате работа пользователей останавливается, и все ждут завершения проведения одного документа – виновника эскалации, либо когда по таймауту снимутся взаимные блокировки, либо произойдет перезагрузка сервера. В каких случаях возникает эскалация и как с этим бороться тоже тема для отдельной статьи.

PS1. По многочисленным просьбам выложен упомянутый самописный отчет "Контроль НДФЛ" в отдельной статье.

См. также

Комментарии
1. Uladzimir - (nvv1970) 15.05.17 08:20 Сейчас в теме
200 одновременных сеансов и не нужны упр блокировки? Мне кажется такое заявление слишком самонадеянным.
Решение должно работать "нажал и забыл", а не всё сделал и сел все пересчитывать и перепроверять ((
Конечно 200 человек для зуп 2.5, и не только, в авторежиме - это капут. И такое решение - это лучше чем ничего.
Silenser; Dmitri93; matveev.andrey.v; +3 Ответить 3
2. Валерий Федоров (barelpro) 726 15.05.17 12:43 Сейчас в теме
(1) Ну что тут скажешь, да, в теории мы должны стремиться сделать идеальную систему "нажал и забыл". Но на практике за перфекционизм никто не готов переплачивать.

Плюс к этому повторюсь, из-за идеологии ЗУП2.5 "Рассчитал-поправил-провел" есть неконтролируемый временной лаг между "рассчитал" и "провел". В это время документ находится в непроведенном состоянии и параллельно с ним другой пользователь может рассчитать второй документ с такими же физлицами. А потом оба документа будут проведены без какой-либо проверки. Поэтому какие бы умные управляемые блокировки ты не сделал, нарушение целостности все равно будет. Так что пусть неизбежное будет, но с максимальной скоростью )))
3. Andrey Matveev (matveev.andrey.v) 46 15.05.17 12:45 Сейчас в теме
(1) полностью согласен, у меня около 100 пользователей и перевод на управляемые был необходимостью
4. Andrey Matveev (matveev.andrey.v) 46 15.05.17 12:49 Сейчас в теме
Есть еще одно замечание о котором мне кажется надо упомянуть в статье, что бы MS SQL использовала уровень READ COMMITTED SNAPSHOT нужно перевести платформу на 8.3 и убрать режим совместимости. Так указано в книге "Настольная книга 1С Эксперта по технологическим вопросам" стр 38
Прикрепленные файлы:
5. Uladzimir - (nvv1970) 15.05.17 13:09 Сейчас в теме
(4) Совершенно верно.
Боюсь может оказаться, что упрблокировки + совместимость 8.3 - это не то же самое что упрблокировки + совместимость 8.2 + включение снэпшотов в SQL. Я правда не проверял )) В теории, менеджер блокировок 1с может вести себя по-разному.
6. Валерий Федоров (barelpro) 726 15.05.17 13:36 Сейчас в теме
(4) Ага, мы так и делали. Позже добавлю в статью.
7. Валерий Федоров (barelpro) 726 15.05.17 13:42 Сейчас в теме
(1) (3) Парни, вдруг вы меня не так поняли- фразу "для таких конфигураций, как ЗУП2.5 вообще нет смысла использовать какие-либо блокировки" надо понимать так, что мы переводим конфигурацию в режим управляемых блокировок и не добавляем объект "БлокировкаДанных", т.е. максимально понижаем уровень изоляции на SQL сервере и так и оставляем, не используя управляемые блокировки на Сервере 1С. Чтобы у пользователей была максимальная параллельность. А потом подчищаем проверочными отчетами последствия такой максимальной параллельности.
8. Решитко Дмитрий (grumagargler) 292 15.05.17 14:42 Сейчас в теме
(7) небольшое уточнение: если вы уберете управляемые блокировки совсем, у вас могут возникнуть дедлоки в запросах на получение остатков при проведении документов (если, конечно, таковые имеются в зуп)
9. Валерий Федоров (barelpro) 726 15.05.17 15:14 Сейчас в теме
(8) Да, в ЗУПе при проведении документов есть обращение к остаткам. Но при чтении остатков дэдлоки вряд ли возникнут на RCSI, выполнению запроса может помешать X-блокировка при записи в параллельном документе, сам запрос никому не мешает, т.к. не накладывает блокировок. А вот два документа при записи теоретически могут друг друга ввести в дэдлоки, но только в режиме автоматических блокировок, когда на таблицу индексов регистров накладывается RangeX блокировка. Согласен, RangeX - сущее зло, но его нет в режиме управляемых блокировок!
10. Сергей Носков (Sergey.Noskov) 740 15.05.17 15:31 Сейчас в теме
(5)
это не то же самое что упрблокировки + совместимость 8.2 + включение снэпшотов в SQL
Это то же самое, единственное отличие, что 8.3 сама включает снепшот
11. Решитко Дмитрий (grumagargler) 292 15.05.17 16:23 Сейчас в теме
(9) Если вы не будете блокировать (БлокироватьДляИзменения) при записи регистра, у вас получится такой дедлок:
1. Пользователь1 записывает набор данных, остаток с разделителем 1.
2. Пользователь2 записывает набор по тем же измерениям, но с разделителем 2.
3. При контроле остатков (выполнение запроса к вирт.таблице) Пользователь1 будет пытаться считать все записи по этим измерениям (без учета разделителя). И запись с разделителем 2 он прочитать не может, потому что её держит Пользователь2, поэтому Пользователь1 встает в очередь.
4. При контроле остатков Пользователь2 также будет пытаться считать все записи по тем же измерениям, без учета разделителя. Запись с разделителем 1 он прочитать не может (ее держит Пользователь1) и Пользователь2 встает в очередь.
12. Uladzimir - (nvv1970) 15.05.17 16:25 Сейчас в теме
(10) Ну если рассматривать разные поколения платформ 8.2 и 8.3, то разница точно есть. )) И даже в разных версиях 8.3 были изменения...
Но в данном случае мы предполагали, что платформа одна, а "балуемся" только настройками конфы и скуля.
13. Uladzimir - (nvv1970) 15.05.17 16:27 Сейчас в теме
(11) Да. Но лучше ловить дедлоки и иметь возможность работать, чем на несколько часов намертво заблокированную базу. Ну а дедлоки можно и нужно понемногу убирать.
14. Сергей Носков (Sergey.Noskov) 740 15.05.17 16:56 Сейчас в теме
(12)касаемо включения READ COMMITTED SNAPSHOT это то же самое. Про сравнение 8.2 и 8.3 речи нет.
15. Uladzimir - (nvv1970) 15.05.17 17:16 Сейчас в теме
(14) т.е. поведение платформы в части менеджера блокировок 100% не зависит от совместимости конфигурации? А зависит только от релиза платформы?
16. Решитко Дмитрий (grumagargler) 292 15.05.17 18:12 Сейчас в теме
(13)
Да. Но лучше ловить дедлоки и иметь возможность работать, чем на несколько часов намертво заблокированную базу

Не нужно так обобщать, это самое первое правило, когда имеем дело с анализом проблем. В описанном мною случае, вместо кратковременного ожидания одного пользователя, работа обоих будет парализована.
Суть в том, что если конфликт за ресурс уже происходит, то как вы говорите "Но лучше ловить дедлоки и иметь возможность работать" - происходить не будет. Те пользователи, кому ресурс не нужен - будут и так себе работать, а все остальные или ждать или отваливаться по дедлоку.

Ну а дедлоки можно и нужно понемногу убирать.

ну так это ровно то, что я и написал выше, организация очереди, а не взаимоблокировка.
matveev.andrey.v; +1 Ответить
17. Сергей Носков (Sergey.Noskov) 740 15.05.17 18:14 Сейчас в теме
(15) Либо СУБД работает с уровнем изоляции READ COMMITTED SNAPSHOT либо просто READ COMMITTED, что должно измениться в поведении платформы? Просто в первом случае выше требования к правильности наложения упр.блокировок т.к. без оных есть риск прочитать, например, остатки, которые кто-то меняет в параллельной сессии.
matveev.andrey.v; +1 Ответить
18. Валерий Федоров (barelpro) 726 15.05.17 18:37 Сейчас в теме
(11) Согласен, если бы в ЗУПе 2.5 использовалась модная технология "сначала запись в регистр, потом контрольный запрос", тогда и на RCSI можно словить deadlock. Но в ЗУП2.5 старая технология, сначала запрос, потом запись регистра, так что пока живем без deadlock ))
19. Uladzimir - (nvv1970) 16.05.17 09:59 Сейчас в теме
В описанном мною случае, вместо кратковременного ожидания одного пользователя, работа обоих будет парализована.

Ну как сказать... Когда у клиента доходит до того, что пользователи на протяжении часа жмякают, например, проведение и 100% в течении часа получают таймаут, то чем можно помочь? Увеличение времени таймаута (как многие делаю) еще более усугубляет ситуацию. Рестарт сервера? ))) Да, админы так и делают )
А при "просто перевод в упр" влечет за собой исчезновение тысяч! таймаутов и появление десятков дедлоков. А дедлоки по ТЖ диагностируются гораздо легче, чем таймауты.
20. Владимир Литвиненко (VladimirL) 581 16.05.17 15:36 Сейчас в теме
Устанавливать настройку "Allow Snapshot Isolation" в истину нет необходимости. Сама платформа 8.3 этого не делает и ни 8.2 ни 8.3 не использует этот уровень изоляции. Достаточно ограничиться "Read Commited Snapshot". Уровень изоляции Snapshot ведет себя отлично от Read Commited Snapshot, который нужен нам при работе с 1С.
barelpro; baton_pk; Sergey.Noskov; +3 Ответить 3
21. Анатолий Бритько (headMade) 134 16.05.17 18:02 Сейчас в теме
(20)
зачем тогда Гилев предлагает это делать? (snapshot1c)
22. Руслан Бабичев (Batchir) 126 17.05.17 09:13 Сейчас в теме
(18) Отлично)))
При уровне изоляции READ COMMITTED SNAPSHOT "пишущий" не блокирует "читающего". Почему? Потому что "читающий" просматривает версию данных до начала изменения. Получаем следующую картину:

1. Т1 S (Прочитали остаток и = 1)
2. Т1 Х (Списываем остаток становится 0)
3. Т2 S (Прочитали остаток и = 1)
4. Т2 Х (Списываем остаток становится -1)
5. Фиксация транзакций Т1 Т2 (причем тут не важно в какой последовательности будет выполняться п.2 и п.3)

В вашем случае все счастливы и довольны, ожиданий нет, но программу завели в логическую ошибку, т.к. она думала что остаток есть, а в результате загнала остаток в минус.
ИМХО, это ошибка страшнее чем ожидания.

Для того что бы система корректно отработала, нужно:

1. Т1 S (Прочитали остаток и = 1) Накладываем упр. блокировку
2. Т2 S (ожидаем) ...
3. Т1 Х (Списываем остаток становится 0)
4 Фиксация транзакций Т1
5. Т2 S (дождались, получили остаток = 0) отвалились или записываем (зависит от логики, которую заложил программист)
6. Фиксация транзакций Т2
uncle_Vasya; +1 Ответить 2
23. Андрей Щеглов (Andrefan) 17.05.17 09:24 Сейчас в теме
Очень позновательная статья, спасибо. А можете поделиться этим: самописный отчет «Проверка НДФЛ»?
24. Владимир Литвиненко (VladimirL) 581 17.05.17 10:22 Сейчас в теме
(21) Подозреваю, что это ретрансляция работающей на практике инструкции, полученной в результате экспериментов или из каких-то источников. Специалисты часто находят работающую инструкцию и применяют ее целиком, не экспериментируя с отдельными частями, так как это затратно по времени и обычно не дает большой практической пользы.

Хотя возможно есть и другие причины. Если есть причина для 1С устанавливать "Allow Snapshot Isolation" в истину, то очень хотелось бы о ней знать. Но и в настольной книге эксперта по тех.платформе написано, что 1С не использует уровень изоляции Snapshot, и платформа 1С 8.3 сама не устанавливает эту опцию. Да коллеги - специалисты по MS SQL подтверждали, что разрешения на Snapshot и на Read Commited Snapshot устанавливаются независимо друг от друга.
25. Валерий Федоров (barelpro) 726 17.05.17 11:25 Сейчас в теме
(24) Кто с этим разберется, тому плюс от меня! )
26. Валерий Федоров (barelpro) 726 17.05.17 11:32 Сейчас в теме
(23) Я как раз думаю его выложить, но он использует вызовы нетиповых процедур из общих модулей, в частности под него была переписана процедура ПроведениеРасчетов.ПолучитьДанныеНДФЛПоРегистратору, а так же много внимания уделено разделителю ОКТМО/КПП. Так что его еще надо причесать, прежде чем выкладывать
27. Валерий Федоров (barelpro) 726 17.05.17 11:42 Сейчас в теме
(22) Это все понятно, я ж не спорю, но статья про проект по ЗУП2.5. Ошибка искажения остатков страшна там, где речь идет об оперативном учете товара или денег. Расчет зарплаты и налогов - это бухгалтерский "посмертный" учет. Здесь главное точность, а не скорость. Вот и коллега Uladzimir - со мной согласен, видимо у него тоже был опыт высоконагруженного ЗУПа - лучше дать расчетчикам максимальный зеленый свет, а потом точечно подчистить ошибки. Практика показывает, что таких ошибок действительно очень мало.
28. Анатолий Бритько (headMade) 134 17.05.17 13:33 Сейчас в теме
(22)
В ЗУПе как правило вся логика строится на предварительной записи данных в регистры т.е. когда бухгалтер нажимает кнопку "Рассчитать" происходит запись в регистр. На основании этих записей производится расчет сумм, которые затем возвращаются в документ.
А в момент проведения документа уже готовые суммы записываются в регистры.

Поэтому наверное такая проблема не совсем актуальна для ЗУПа.
29. Руслан Бабичев (Batchir) 126 17.05.17 14:56 Сейчас в теме
(28) Как по мне то это выливается в не корректный расчет, дальнейшую перепроверку и перерасчет на большом количестве записей. В не зависимости от конфигурации это грубая ошибка.
Сегодня рассчитали с ошибками ЗП, не заметили и завтра сдали в гос. органы.
Я не работал с высоконагруженным ЗУМом, поэтому конечно это всё ИМХО.
Но к проблеме нужно подходить корректно, если имеем проблему с блокировками на ожиданиях, то нужно решать эту проблему, а не ставить костыль, который позволяет системе некорректно работать.
30. Анатолий Бритько (headMade) 134 17.05.17 15:22 Сейчас в теме
(29)
нужно решать эту проблему, а не ставить костыль

Абсолютно с этим согласен.

Я просто хотел обратить внимание что
(28)
В ЗУПе как правило вся логика строится на предварительной записи данных в регистры

т.е. момент записи данных в регистр будет установлена управляемая блокировка, поэтому (скорее всего) и логическая ошибка, описанная Вами выше, не всплывет.
31. Dmitri Dmitrich (Dmitri93) 5 17.05.17 18:01 Сейчас в теме
А почему внедряли именно ЗУП 2.5, а не 3.1?
32. Валерий Федоров (barelpro) 726 17.05.17 19:15 Сейчас в теме
(31) Цель проекта была внедрить единую систему путем слияния двух баз: допиленный 2.5 и "известное неодинесное решение". Следующим этапом планируется 3.1. Вангую, что в 3.1 тоже придется оптимизировать блокировки )))
33. Валерий Федоров (barelpro) 726 17.05.17 23:53 Сейчас в теме
(20) Нашел интересную статью, где говорится, что RCSI и SNAPSHOT это два разных вида уровней изоляции

Получается вот что:
команда "ALT ER DATABASE SET READ_COMMITTED_SNAPSHOT ON" включает уровень изоляции RCSI
а команда "ALT ER DATABASE SET ALLOW_SNAPSHOT_ISOLATION ON" включает уровень изоляции SNAPSHOT

RCSI - это всего лишь изоляция читающих (S) блокировок одних транзакций от пишущих (X) блокировок других транзакций. При этом пишушие (X) блокировки разных транзакций продолжают влиять друг на друга.

Тогда как SNAPSHOT - это полноценная изоляция и пишуших и читающих блокировок между транзакциями. Т.е. полная анархия!!!

Судя по всему, когда конфигурация переведена в управляемый режим блокировок, то 1С-платформа для SQL-сессий устанавливает по умолчанию режим READ COMMITTED, который превращается в READ COMMITTED SNAPSHOT, если включен режим READ_COMMITTED_SNAPSHOT ON

А полноценный SNAPSHOT в 1С-базах не работает, даже если включить режим ALLOW_SNAPSHOT_ISOLATION ON, т.к. как я уже писал в статье команда

"SEL ECT CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL
FR OM sys.dm_exec_sessions"

возвращает для всех сессий режим Read Committed
34. Владимир Литвиненко (VladimirL) 581 18.05.17 00:48 Сейчас в теме
(33)
Также очень рекомендую два следующих ролика:
Read Committed Snapshot Isolation
Snapshot Isolation

Это лучшее объяснение различий между двумя уровнями изоляции из тех, что встречал в сети. У автора акцент тот еще, но понять можно. А вот иллюстрация на флипчарте - это то, ради чего стоит посмотреть. Обычно различия объясняются на примере параллельно исполняемых запросов в Management Studio. В этих роликах дается понятное объяснение на схемах, и только потом демонстрируются подтверждающие примеры в Студии.
barelpro; +1 Ответить
35. Валерий Федоров (barelpro) 726 18.05.17 12:50 Сейчас в теме
(20) Спасибо за замечание, поправил в статье!
36. Александр Хомяк (logarifm) 976 19.05.17 00:18 Сейчас в теме
еще не прочитал. + поставил и таких стотей не бывает мало )
37. Дмитрий Кирилкин (dumsik) 8 29.05.17 14:02 Сейчас в теме
В статье не точность. На уровне изоляции READ COMMITTED блокировки снимаются после выполнения запроса до окончания транзакции. Для того чтобы блокировки держались до конца транзакции используется уровень изоляции REPEATABLE READ.

Выбор между уровнем изоляции READ COMMITTED или REPEATABLE READ платформа выполняет сама в зависимости от объекта метаданных. Для объектных (все у чего есть ссылка) выбирается READ COMMITTED, для регистров REPEATABLE READ.

Источник "Настольная книга 1с эксперта по технологическим вопросам"
38. Валерий Федоров (barelpro) 726 29.05.17 14:21 Сейчас в теме
(37) Интересно! Назовите номер издания книги и номер страницы, посмотрим
39. Валерий Федоров (barelpro) 726 29.05.17 16:39 Сейчас в теме
(37) Вот что пишет сам Филиппов Женя по поводу первого издания: "Во втором издании скорректированы неточности в теоретической части" http://1c.ru/news/info.jsp?id=20028. Так я ничему не удивляюсь ;)
40. John Irwin (Irwin) 60 02.08.17 13:42 Сейчас в теме
У вас стоит режим совместимости в 8.2.13 (если правильно помню). И основные проблемы параллельности при расчете зарплаты в том, что при записи в регистр расчета ОсновныеНачисления происходит сканирование таблицы. Происходит это при расчете фактического периода действия. Получается ситуация, что при расчете в документе до 150 сотрудников параллельность высокая (порядка 200-250 записей в документе). При большем количестве план запроса становится неоптимален - появляется скан, ставятся лишние X-блокировки. При этом появляются взаимоблокировки, таймауты.

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

Про это также есть в статье у Бурмистрова: https://infostart.ru/public/629017/. Раздел "Ошибка платформы – скан индекса регистра расчета".

Варианты решения:
1) попробовать снять режим совместимости (частично переписать конфу), чтобы добавился кластерный индекс на регистр расчета.
2) попробовать самим добавить индекс
3) попробовать документ начисления зарплаты рассчитывать порциями по 150 сотрудников. Можно параллельно, в этом случае может еще и время расчета сократиться.

В любом случае эффект не гарантирован, надо пробовать.
barelpro; +1 Ответить
41. John Irwin (Irwin) 60 02.08.17 13:55 Сейчас в теме
В этой же конфе был еще один интересный случай. Есть отчет "Неиспользованные отпуска МСФО", который рассчитывает средний заработок. Создается документ "Увольнение", рассчитывается, результат среднего запоминается. И так для каждого сотрудника. Отчет рассчитывался в разрезе организаций. В самой крупной из них на тот момент было порядка 8 тыс. (могу соврать, не помню уже). Расчет шел порядка 6-7 часов. Иногда прерывался из-за какого-нибудь таймаута. Приходилось заново запускать.

В итоге решили считать в фоне в несколько потоков. При этом каждый поток должен считать не по одному сотруднику, а сразу пачками. В итоге расчет пачками дал прирост скорости в 30%. А 20 фоновых заданий все это дело рассчитывали за 40 минут.

Но самое интересное было, когда первый раз запустили параллельный расчет. Фоновые задания начали друг другу мешать. Каждая пачка рассчитывалась в отдельной транзакции - создавался документа, рассчитывался, все записи удалялись. При чем в ТЖ отслеживались ожидания на управляемых блокировках на регистре расчет "СреднийЗаработок". ТЖ показал, что при записи в регистр данных даже по одному сотруднику устанавливалась исключительная блокировка на всю таблицу. При этом если писать обработкой какие-нибудь записи в регистр - все хорошо, ставятся только необходимые блокировки. Если при расчете документа увольненеия - вся таблица. Оказалось, что если писать в этот регистр набор записей, у которого в записях стоит Активность = Ложь, то ставится исключительная управляемая блокировка на всю таблицу.

Пробовал создать в пустой базе аналогичный регистр и записывать в него - такого поведения добиться не удалось. Что это было - остается загадкой.
barelpro; +1 Ответить
Оставьте свое сообщение