Авторы

Работа выполнена студентом Государственного автономного профессионального образовательного учреждения «Международный центр компетенций — Казанский техникум информационных технологий и связи» Емельяновым Всеволодом Салаватовичем под руководством преподавателя, кандидата экономических наук Маннаповой Диляры Фирнадовны.

В данной статье мы разберем немаловажные регистры бухгалтерии и способы оптимизации запросов к СУБД при работе с ними для решения реальных задач.

На данный момент множество предприятий предпочитают использование прикладного решения фирмы 1С — 1С:Бухгалтерия. Не все специалисты знакомы с тем, как те или иные действия приводят к торможению работы предприятия при маленькой модификации. Примером может является изменение порядка субконто. В этой статье мы подробно разберем разворот регистров бухгалтерии (далее РБ) на стороне СУБД и моменты по улучшению плана запросов к СУБД и общих оптимизационных моментов.

Общая информация

Сами по себе записи РБ предоставляют схожие записи с регистром РН (накопления), они также имеют измерения, ресурсы, реквизиты, но пара отличий все же есть, они зависят от настроек РБ в платформе.

Здесь внимательные заметят, что появилось поле для ввода плана счетов и корреспонденции.

Поле «план счетов» отвечает за простую связь РБ с планом счетов, благодаря которому к каждой записи можно добавить в разрезе счетов свои «разрезы» субконто, а также признаки учета субконто и обычные признаки учета.

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

Разберем сам план счетов.

План счетов, по сути своей, это тот же справочник, только имеет несколько иные настройки для предопределенных элементов, а также возможность указать ПВХ (план видов характеристик) для субконто и их количество (максимальное количество может составлять 50, но рекомендуемое — 3). Заглянем в предопределенные данные плана счетов и увидим следующую картину.

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

Есть простой пример: проводка дебет Товары, кредит Поставщики, и мы хотим оприходовать партию. Обычная проводка должна содержать в себе разрезы на номенклатуру, партию, склад. То есть, здесь будет 3 субконто, а также важно понимать, что если мы укажаем в качестве ресурса количество в РБ, то мы обнаружим, что со счета «Поставщики» идет какое‑то количество. Эта аналитика будет неправильной, соответственно, для этого мы добавляем признак учета Количественный, а также снимаем флаг балансовый с ресурса, чтобы можно было указать в проводке количество отдельно для счетов Дт и Кт.

Плюс‑минус с тем, как настроить РБ и как определить состав признаков учета и субконто, мы определились, перейдем к развороту картины на СУБД.

РБ на стороне СУБД

Всем прекрасно знакома обработка структуры конфигурации (кому нет — эта обработка позволяет просмотреть, какие таблицы как называются на стороне СУБД при создании объектов метаданных на стороне платформы). В этой обработке и в принципе на стороне СУБД все таблицы не называются именами из конфигурации, даже поля называются по-другому. Рассмотрим, как выглядит сама таблица в СУБД.

Основная таблица

Таблица РБ на стороне СУБД имеет название по шаблону AccRg + внутренняя нумерация. Здесь отражена структура таблицы в СУБД по статье с Infostart. Здесь у нас нет ничего особенного, кроме отсутствия самих субконто в основной таблице (они хранятся в отдельной).

Таблица с субконто

Таблица с субконто имеет название по шаблону AccRgED + внутренний номер и хранит все тот же стандартный набор атрибутов, но в дополнении имеет поля для указания значения субконто.

Остальные таблицы

Существуют также немаловажные остальные таблицы: Остатки, Обороты и таблицы итогов субконто.

Про них описано более подробно в упомянутой выше статье, лучше перейдем по рекомендациям к оптимизации запросов к таблицам СУБД.

Оптимизация

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

Перейдем для начала к более востребованным таблицам на практике — Остатки.

Ускорение получение остатков

Разберем данную задачу на примере задач от УЦ № 1 фирмы 1С.

На примере УЦ ускорило данный запрос с 9 секунд в целых 3 раза, что является не десятыми долями секунды, а чем-то большим, что является превосх��дным результатом.

Рассмотрим поэтапно, что оказало такое влияние.

  1. Разворачивание выражения «В»

В данном запросе в параметрах виртуальной таблицы можно увидеть выражение Субконто1 В (&МассивНоменклатуры), платформа по умолчанию при построении запроса к СУБД при проверке вхождения значения в коллекцию, превышающую по размеру 128 элементов, преобразует во вложенный запрос, соответственно, на стороне СУБД это будет выглядеть вот так:

...AND T.FieldName IN (
    SELECT
        T.VALUE
    FROM
        #TABLE AS T
    WHERE T.VALUE IS NOT NULL)

Названия таблиц и полей здесь описаны несколько иначе, если нужна конкретика по СУБД см. скрин ниже:

Эта проблема посредством сбора консилиума умов решилась следующим образом: они выяснили, что при обращении к большой коллекции и передачи ее в качестве параметров при размере более чем 128 запрос выполняется быстрее с использованием подзапроса, нежели с полной коллекцией, и данный момент в целом решается предельно просто, после анализа ТЖ можно найти этот участок, при этом удостовериться, что коллекция зачастую превышает 128 и лучше разбить её на 2. Соответственно, на стороне 1С данный запрос будет выглядеть так:

... Субконто1 В (&МассивНоменклатуры1) ИЛИ Субконто1 В (&МассивНоменклатуры2)

Данное действие здесь предотвратило выборку из подзапроса и разбило коллекцию, что не дало платформе преобразовать в подзапрос.

Соответственно, у нас идет уже не выборка из таблицы, как говорилось ранее, а порции из параметров коллекции.

При этом важно заметить, что не только время выполнения запроса на СУБД уменьшилось, также есть еще немаловажный аспект деградации системы.

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

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

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

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

Ускоряем запись

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

Самый базовый случай — проведение документов. Да, мы будем ускорять именно запись набора записей в РБ, и какие же моменты чаще всего тормозят систему? Ответ — довольно примитивные:

  • Ожидание на блокировках

    • Излишние блокировки по времени

    • Эскалация блокировок

    • Не используется разделение итогов

  • Ошибки при массовой модификации данных

    • Не используется отключение итогов

    • Не используется запись в транзакции

  • Проблемы с дисками

  • Ошибка проектирования

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

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

Ожидание на блокировках

Здесь довольно просто, есть два режима: монопольный и многопользовательский, и в целом некоторые разработчики не думают о том, что их чудо-творением будет кто‑то пользоваться, и благополучно забывают про многопользовательский режим, при этом проблема раскрывается с ожиданием исключительно в нем. Т.к. один сеанс благополучно перерезал получение данных из СУБД по всему регистру, а остальные пользователи ждут, пока чудо-блокировка закончится. Это довольно базовый пример, поэтому лучше мы углубимся все-таки в причины, которые могут провоцировать другие случае ожидания.

Излишние блокировки по времени

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

Для тех же самых регистров накопления и контроля остатков относительно давно появилось разделение методик проведений на «Новую» и «Старую», и соответственно, вспомним, чем они отличались.

  1. Писала набор записей, а только потом вешала блокировку и проводила сверку.

  2. Блокировала регистр по определенным измерениям и проводила сбор данных и запись.

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

Эскалация блокировок

Что же такое эскалация блокировок? Представим, что для записи одного набора записей необходимо заблокировать на стороне СУБД несколько десятков тысяч строк, а у заказчика не супер‑компьютер как у программиста, а картошка, то есть оперативной памяти не так много и ресурсов в принципе мало.

Что же тогда предпринимает СУБД?

СУБД радикальна, она поняла, что блокировать десятки тысяч строк — это гиблое дело и компьютер, скорее всего, зависнет, и решает заблокировать таблицу ЦЕЛИКОМ, причем реально целиком, почему? Потому что хранить данные о десятках тысяч блокировок затратнее, чем хранить данные об 1 блокировке.

А как же тогда предотвратить эскалацию?

Порционная запись набора решит проблему, то есть мы разделим наши блокировки на порции и, соответственно, СУБД поймет, что мы, в целом-то, можем эту тысячу заблокировать и все будет хорошо.

В версии платформы 8.2 эскалация происходит при достижении числа 20.000, а в версии 8.3 — при достижении 100.000

А что происходило бы при эскалации на предприятии?

Один сотрудник решил провести какой нибудь документ с многочисленными ТЧ (табличными частями) и навесил эскалацию по всем складам и номенклатуре, хотя записи исключительно по Складу №1 и №2, а другой сотрудник хотел провести маленький документ всего с одной номенклатурой и вообще по Складу №3, а получил ожидание.

Не используется разделение итогов

В типовых решениях всегда есть флаг «Контролировать остатки», а если его выключить, к примеру когда розничная продажа на очень большое количество клиентов, то без этого флага поведение будет следующее:

  1. Иванов записал продажу и заблокировал записи.

  2. Сидоров пытается записать, но попал в ожидание.

  3. Иванов закончил запись.

  4. Сидоров записал.

И это возникло без включения флага «Разделение итогов», а что он из себя представляет? Разделение итогов — добавление Splitter в СУБД и разрешение на параллельную запись, то есть у нас добавится номер сеанса, и для них будут свои итоги. Удобно, не правда ли?

По умолчанию, конечно, если замечали, то при создании объекта метаданных, у которого есть это свойство (РН или РБ), оно уже включено по умолчанию, но некоторые индивидуумы его выключают или по мере перехода с более старых конфигураций эта галка не была включена.

Ошибки при массовой модификации данных

Довольно часто при работе на проектах встречается такая ситуация, когда один программист, делая задачу, решил потерять половину полушария мозга и забыть, что не все процессы крутятся на его доработках и, соответственно, испоганил достаточно большое количество записей на тестовом контуре, или контуре предпродакшена. А съем.dt, который нужен нескольким другим разрабам, невозможен из‑за веса информационной базы в несколько ТБ. Ну или когда заказчику необходим инструмент по корректировке тысяч документов.

Довольно частая практика, не так ли? Давайте разберем, как оптимизировать такие моменты.

Не используется отключение итогов

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

А как же решить проблему?

У регистра есть метод УстановитьИспользованиеИтогов, и он может предотвратить вычисление данных для таблиц итогов при записи. То есть обычно на практике, если сравнить запись без использования метода и установки использования итогов в Ложь может повлечь сокращение по времени в 2 раза, ну или чуть меньше, но тогда вытекает проблема: таблицы итогов будут недоступны, и что тогда делать? Ответ простой — включить. Ну это вопрос несколько тривиальный. Иногда запись и расчет итогов вместе занимают меньше, чем отключение итогов запись и включение, но зачастую второй подход минимизирует время и расчет произойдет за несколько секунд или десятков секунд (в случае если уж очень много всего), и в совокупности это все равно будет быстрее в 1.5 или 2 раза, чем просто запись.

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

Предыдущий результат, конечно, хорош, но что делает СУБД во время записи? Она естественным образом на каждый модифицируемый объект открывает и закрывает транзакцию. И возникает вопрос: удобнее, когда дали выполнять одну задачу, рутинную и объемную, или когда каждые 5 минут пилят с новым заданием, которое ОЧЕНЬ‑ОЧЕНЬ нужно сейчас и здесь. Наверное, все-таки когда дали список, и ты делаешь их поэтапно, а не дергаешься.

Здесь подход, в целом, такой же. Перед началом обработки данных мы должны использовать механизм транзакций.

По рекомендациям ИТС обработка транзакции должна выглядеть вот так:

НачатьТранзакцию()
Попытка

    .... обход объектов и модификация
    
    ЗафиксироватьТранзакцию()

Исключение
    
    Если ТранзакцияАктивна() Тогда
        ОтменитьТранакзцию()
    КонецЕсли;
    
КонецПопытки

И тут тоже стоит понимать, как мы пишем объекты: если это загрузка, которая должна либо произойти полностью, либо не происходить совсем, или это загрузка, которая должна обработать все объекты несмотря на отсутствие некоторых?

Если это первый случай, то открытие явной транзакции поможет ускорить работу программы.

Проблемы с дисками

В целом, если рассматривать аппаратный уровень, все довольно знакомы с установкой Windows на HDD c 5200 оборотом и 7200, и там, и там ад, только для 5200 это просто невыносимо долго.

Тут, в целом, такая же ситуация: толкать что‑то кодом будет довольно бессмысленно, если у заказчика на предприятии стоят ящики мандаринов, а не рабочие ПК.

Но если все-таки с оборудованием все ок, то также следует обратить внимание на расположение файла данных и файла транзакций. Если их разнести по разным накопителям, то один не будет отвлекать другой во время записи, что также повлияет положительно на записи в БД.

Ошибка проектирования

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

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

Заключение

В этой статье мы рассмотрели некоторые моменты по работе с СУБД и построению запросов, довольно простые вещи, связанные с архитектурой решения, а также общие понятия по работе с регистрами бухгалтерии и планами счетов. Данные статьи помогут в разработке новых решений на базе 1С:Бухгалтерия или по сопровождению высоконагруженных решений. Можно сказать, что данный материал можно применить в более широком спектре задач, а не только на регистрах бухгалтерии.