Hare.ru @ Коллективный разум / Hare.ru @ Дикое место

Архив hare.ru 
Мысли, конвертированные в текст

Концептуальные работы


Все статьи раздела

Альтернатива Последовательности документов. Письма читателей.

Никита Зайцев (WildHare) (где-то в 2001)

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

Саму проблему я второй раз описывать не буду, предполагая, что все интересующиеся предметом уже ознакомились с первой статьёй. Итак, кто и каким образом решает проблему “уплывания” итогов при нарушении хронологической последовательности событий в базе данных 1С?

Начнем с наиболее простых способов. Сергей Зима a.k.a. Winter использует вот такой метод:

  • Используется штатная последовательность документов.
  • В конфигурации создается специальный контрольный справочник.
  • При проведении документа задним числом создается новый элемент этого справочника, в реквизиты которого записываются ссылка на документ, дата и время перепроведения, имя пользователя, и вообще любая потребная администратору информация
  • Периодически (ночью) запускается служебная обработка, которая анализирует созданные за день элементы контрольного справочника и “интеллектуально” восстанавливает последовательность только по тем элементам “ключевого” справочника (в данном случае — контрагентов), документы по которым были “тронуты”.
Подобную методику, с небольшими различиями, используют многие. В данном случае объем служебных данных сравнительно невелик (контрольный справочник очищается после восстановления последовательности), никаких дополнительных вычислений в момент проведения документа не производится — как следствие, производительность системы не страдает. Принципиальный недостаток такой схемы (на мой взгляд) состоит в следующем: моменты нарушения и восстановления логической целостности данных разнесены во времени как минимум на один рабочий день (а может так получиться, что и больше). И если проведение документа задним числом вызывает сбой в партионном учете, то в течении некоторого времени система будет выдавать пользователям неверные отчеты. Что, согласитесь, не есть хорошо.

Михаил Савин и Михаил Чуриков предлагают воспользоваться методом “красного сторно” (автором метода, по всей видимости, является Лука Паччоли, но за давностью лет точно установить вряд ли возможно ;-). Суть решения такова (цитирую Михаила Савина):

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

    Как это выглядит в отчетах. Если в первой версии док-та было указано, скажем, 10 единиц, а во второй исправлено на 12, то в отчете это будет выглядеть как две строчки: +10 (первая версия) +2 (вторая версия).

    Тонкости: нумерация документов должна учитывать версии, отбор в журналах только последней версии (в т.ч. отбор по двум признакам: значение отбора+признак последней версии), сохранение истории версий, выбор даты внесения изменений (даты документа новой версии) — либо только текущим числом, либо только числом первой версии.

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

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

    Возможные проблемы. Если расчет себестоимости осуществляется в момент списания товара, то использование этого метода нарушит принципы FIFO, LIFO. Изложенное выше не теория: у меня есть своя реализация этой технологии, у Михаила Чурикова — своя (разница в принципе сохранения истории версий документов). У Михаила работает более 1,5 лет (БД >8Gb), у меня чуть больше полугода (БД >1Gb).

Что можно сказать по этому поводу? Очень грамотное и технологичное решение. Но, к сожалению, оно подойдет не каждому — реализация потребует больших трудозатрат и высокой квалификации. Да и расчет себестоимости в момент списания по алгоритмам FIFO/LIFO (с учетом данных партионного учета) используется практически повсеместно, во всяком случае, в торговле. Поэтому применять описанную методику имеет с мысл в мощных и уникальных конфигурациях, но на роль “народного решения” она не подходит.

Интересное решение придумал Дмитрий Малюгин — он предложил для хранения контрольных данных воспользоваться служебным регистром. Механизм контроля работает следующим образом:

  • Для хранения контрольных данных используется регистр вида

    Измерения
    Тип последовательности Строка/Перечисление/etc.
    Уровень 1 Справочник
    Уровень 2 Справочник
    ...... ......
    Документ движения Документ
    Ресурсы
    Граница последовательности Число
    где:
    • Тип — некий идентификатор последовательности (несколько последовательностей можно хранить в одном регистре).
    • Уровень 1, Уровень 2 и т.д. обеспечивают необходимую детализацию последовательности (например, Товар и Склад, Клиент и Фирма, и т.д.)
    • Документ — понятно что
    • Граница используется для отображения статуса и позиции документа в последовательности.
  • Любой документ, входящий в последовательность, двигает контрольный регистр по следующему алгоритму (само собой, соблюдая детализацию по нужным измерениям):
    • Проводим анализ текущих итогов регистра и находим документ, стоящий в последовательности перед текущим.
    • NB! временный расчет контрольного регистра при проведении документа задним числом не производится.
    • Сторнируем итог по прошлому документу (делаем такое движение, чтобы Граница по нему стала равной нулю).
    • Сторнируем итог по текущему документу (если он есть).
    • Приходуем по текущему документу единицу.
    В результате после проведения документа итог по нему становится равным единице, а итог по предыдущему документу обращается в ноль.
  • Каким образом осуществляется контроль за последовательность? Вот таким:
    • Единичный остаток на каком-либо документе означает границу последовательности.
    • Если документ, на котором есть единичный остаток, не является последним по времени из всех документов, двигавших регистр по конкретному набору измерений — последовательность нарушена.
    • Если по регистру (с учетом детализации) есть больше одного ненулевого итога — последовательность нарушена.
  • Информации, хранящейся в контрольном регистре вполне хватает для “умного” восстановления последовательности. Восстановление производится так:
    • Анализируем итоги контрольного регистра и находим “сбойный” документ. Это будет самый ранний по времени документ, по которому существует ненулевой остаток.
    • Последовательно перепроводим все документы последовательности, начиная со сбойного. Состав последовательности мы получаем, анализируя движения контрольного регистра (не забывая предварительно установить нужные фильтры).
    • NB! в этом случае алгоритм проведения документа меняется: необходимо проверить актуальность итогов для документа, и, если итоги не актуальны, сначала сделать временный расчет контрольного регистра, а уже потом анализировать итоги и делать движения. Зачем это нужно? Затем, что иначе все будет криво ;-). Объяснять это долго, легче показать на примере.

      Допустим, у нас есть три последовательно проведенных документа:

      Документ последовательности Граница
      Документ #1 0
      Документ #2 0
      Документ #3 1

      Отменяем проведение второго:

      Документ последовательности Граница
      Документ #1 1
      Документ #2 -1
      Документ #3 1

      Проводим задним числом первый, а потом третий:

      Документ последовательности Граница
      Документ #1 0
      Документ #3 1

      Снова проводим второй, задним числом:

      Документ последовательности Граница
      Документ #1 0
      Документ #2 1
      Документ #3 1

      Если теперь последовательно перепровести первый, второй и третий (не делая временного расчета итогов контрольного регистра), то будет вот что:

      Документ последовательности Граница
      Документ #1 1
      Документ #2 0
      Документ #3 1

      Согласитесь, это мало похоже на восстановленную последовательность. Почему так произошло? Потому, что когда после отмены проведения второго был проведен третий, он сделал движение для погашения первого. Когда повторно был проведен второй, он не сделал никаких “гасящих” движений — ведь все документы до него уже имели нулевые итоги. Когда же после этого был проведен первый (начало восстановления последовательности), он записал на себя двойку (сторнировав последнее движение третьего и добавив единицу). Потом снова был проведен второй, и он сторнировал первый единицей (опять-таки исходя из актуального итога). Самым последним был проведен третий, и вот он-то удалил свое прошлое движение по сторнированию первого, поскольку ему по алгоритму положено сторнировать второй. Ну и получилось, что итог, на основании которого первый делал свое движение, ушел в /dev/null/, а движение осталось — вот откуда в первой строчке эта лишняя единица.

      Если же иметь в виду, что производится восстановление последовательности, и не принимать во внимание движения документов, стоящих дальше на временной оси (т.е. сделать временный расчет регистра), то в итоге получим то, что нужно:

      Документ последовательности Граница
      Документ #1 0
      Документ #2 0
      Документ #3 1

Я понимаю, что эти дикие выкладки мало приспособлены для восприятия нормальным человеком, но это наиболее внятное изложение, которое я смог из себя выдавить. Если Вы возьмёте приложенный пример и посвятите полдня перепроведению этих несчастных трех документов во всех мыслымых сочетаниях (чем я и занмался во время написания статьи), то увидите, что так оно и есть. А может, найдете еще пару ускользнувших от меня дырок в алгоритме. В принципе, застраховаться от возможных проблем с “умным” восстановлением последовательности можно довольно просто — сделать его тупее ;-), т.е. перепроводить в случае нарушения вообще все документы микропоследовательности. Это немного увеличит время восстановления, но зато даст полную уверенность в корректности результата.

Чем хороша такая методика?

  • Во-первых, она позволяет хранить массив служебных данных именно там, где хранить их лучше всего — в регистре. Даже если служебных данных будет много, это не сильно скажется на производительности системы.
  • Во-вторых, она наглядна, проста в реализации и масштабируема — создание новых типов микропоследовательностей не требует вообще никакого вмешательства в конфигурацию (если процедуры контроля и восстановления изначально сделать универсальными и управляемыми через внешние обработки).
  • В-третьих, это очень гибкое решение. Для разных типов микропоследовательностей можно задавать разную логику поведения — для одних можно вообще запретить проведения задним числом, для других разрешить, но выставить ограничение, скажем, на максимальное количество “нарушающих” документов или на количество перепроведений одного и того же документа, для третьих можно разрешить любые действия. Опять-таки, анализируя остатки и обороты контрольного регистра можно получить массу статистической информации, не всегда бесполезной — все зависит от фантазии и квалификации программиста.
  • В-четвертых, такая технология без проблем прикручивается на любую типовую конфигурацию. Более того, при обновлении версии типовой конфигурации повторное прикручивание также особых проблем не вызовет.
Но и недостатки у решения имеются:
  • Проведение документа, помимо основной работы, содержит некоторый объём чисто служебных вычислений. Причем этот объем напрямую зависит от корректности последовательности — чем больше документов проводится задним числом, тем больше служебных вычислений производится каждым из них.
  • Полного “самоконтроля” достичь не удается, требуется периодический запуск механизма восстановления последовательностей.
  • Мне кажется, что методика не подойдет в случае тотальной работы задним числом — объем служебных данных и служебных вычислений будет слишком велик и отнимет слишком много ресурсов. Но, как и всякое “кажется”, это следует тщательно проверить на реальных данных, а потом уже делать выводы.
В любом случае, решение очень изящное. Я не могу сказать, что произвел всесторонее тестирование и что никаких подводных камней технология не содержит.. но, на мой взгляд, она вполне жизнеспособна и нет никаких причин её не использовать.

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

Партнеры:


Также может быть интересно:

Канал Россия 1 на http://spbtvonline.ru/
   
 Сайт поддерживается за счет партнеров:
:::... Сайт содержит архив двух версий hare.ru Карта сайта