gifts2017

Технология внешнего сохранения расчетов

Опубликовал Осипов Сергей (fixin) в раздел Программирование - Инструментарий

Довольно длительное время я сопровождал расчет бонусов в одной организации. Нюанс заключался в том, что алгоритмы и сами структуры данных для расчета постоянно менялись, порой кардинально.  Чтобы анализировать данные за период, нужно было сохранять данные расчетов, т.к. воспроизвести их было не реально. Однако возник вопрос: в каком формате сохранять, если в таблицах постоянно добавлялись и удалялись колонки, кроме ключевых?
Решено было сохранять таблицы расчетов во внешние файлы, а затем их восстанавливать при необходимости.
Технология оказалась удачной, хочу поделиться опытом.
Формальная постановка задачи

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

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

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

Первая попытка

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

Что-то вроде таблицы с полями: IDТаблицы, IDПоля, Значение.

Но не получилось, возникли проблемы:

  1. База слишком быстро выросла в объеме, что сказалось на размерах бэкапа.
  2. Сохранение в таблицу и получение информации работало крайне медленно.

Такая методика не годилась.

Использование внешних данных

Все таблицы расчетов решено было сохранить в каталог на сервере в виде отдельных файлов.

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

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

Вот пример файлов в каталоге:

В каждый файл сохраняется таблица через функцию ЗначениеВСтрокуВнутр, обратно разворачивается через ЗначениеИзСтрокиВнутр.

Статистика

Один расчет по 40 подразделениям за полмесяца занимает 150 Мб:

Все расчеты за полгода занимают 7 Гб:

Вот как выглядит каталог с расчетами Sequoia View с расчетами за полгода:

Бэкапить такие файлы удобно, не нужно хранить лишнюю информацию в базе.

Образцы кода

В разделе собран полезный для организации таких хранилищ код.

Библиотека для работа с Расчетами:

Функция ПолучитьКаталогСохраненияРасчетов(Дата) Экспорт

       БазовыйКаталог = СокрЛП(Справочники.САПКонстантыЛокальные.КаталогСохраненияРасчетов.Значение);

       Если БазовыйКаталог = "" Тогда

             Возврат БазовыйКаталог;

       КонецЕсли;

      

       ПодКаталог = Формат(Дата, "ДФ=yyyyMMdd");

      

       Возврат САП.СоздатьКаталогЛога(БазовыйКаталог, ПодКаталог, ложь);

КонецФункции

 

Функция ПолучитьИмяФайлаРасчетов(Магазин, Интервал, ИмяТаблицы) Экспорт

       ИмяФайла = СокрЛП(Магазин.Код) + "_" + Формат(Интервал.ДатаНачала, "ДФ=dd_MM_yyyy") + "_" + Формат(Интервал.НомерПериода, "ЧН=0; ЧГ=") + "_" + ИмяТаблицы+".txt";

       Возврат ИмяФайла;

КонецФункции

 

Функция ПолучитьИмяФайлаРасчетовПолное(Магазин, Интервал, ИмяТаблицы) Экспорт

       Каталог = ПолучитьКаталогСохраненияРасчетов(Интервал.ДатаНачала);

       Если НЕ ЗначениеЗаполнено(Каталог) Тогда

             Возврат Неопределено;

       КонецЕсли;

       ИмяФайлаРасчетов = ПолучитьИмяФайлаРасчетов(Магазин, Интервал, ИмяТаблицы);

       ИмяФайлаПолное = Каталог + "\" + ИмяФайлаРасчетов;

      

       Возврат ИмяФайлаПолное;

      

КонецФункции

 

 

Функция СохранитьРасчет(Магазин, Интервал, ИмяТаблицы, Таблица) Экспорт

       ИмяФайла = ПолучитьИмяФайлаРасчетовПолное(Магазин, Интервал, ИмяТаблицы);

       Если ИмяФайла = Неопределено Тогда

             Возврат Неопределено;

       КонецЕсли;

      

       Попытка

             Значение = ЗначениеВСтрокуВнутр(Таблица);

             Т = Новый ТекстовыйДокумент();

             Т.УстановитьТекст(Значение);

             Т.Записать(ИмяФайла, "UTF-8");

            

             Возврат ИмяФайла;

       Исключение

             ОписаниеОшибки = ОписаниеОшибки();

            

             //Если Найти(";ТЗСебестоимость;", ";" + ИмяТаблицы + ";") <> 0 Тогда

             //     Сообщить("Не смогли преобразовать таблицу для сохранения в файл: " + ИмяФайла +  "  " + ОписаниеОшибки, СтатусСообщения.Важное);

             //Иначе

             ВызватьИсключение "Не смогли преобразовать таблицу для сохранения в файл: " + ИмяФайла +  "  " + ОписаниеОшибки;

             //КонецЕсли;

       КонецПопытки;

      

КонецФункции

 

Функция ВосстановитьРасчет(Магазин, Интервал, ИмяТаблицы) Экспорт

       ИмяФайла = ПолучитьИмяФайлаРасчетовПолное(Магазин, Интервал, ИмяТаблицы);

       Если ИмяФайла = Неопределено Тогда

             Возврат Неопределено;

       КонецЕсли;

      

       Попытка

              Т = Новый ТекстовыйДокумент();

             Т.Прочитать(ИмяФайла, "UTF-8");

             Текст = Т.ПолучитьТекст();

             Значение = ЗначениеИзСтрокиВнутр(Текст);

       Исключение

             Возврат Неопределено;

       КонецПопытки;

       Возврат Значение;

      

КонецФункции

 

Пример использования в расчетах:

       Для Каждого Магазин из ВыбМагазины Цикл

             Для Каждого Интервал Из ВыбИнтервалы Цикл

                    #Если Клиент Тогда

                           Состояние("Бонусы. Магазин: " + Магазин + "Интервал: " + Интервал);

                    #КонецЕсли

                   

                    ТЗСтавки = ВосстановитьРасчет(Магазин, Интервал, "ТЗСтавки");

                    Если ТЗСтавки = Неопределено Тогда

                           Сообщить("Не найден расчет ТЗСтавки: " + " Магазин: " + Магазин + "Интервал: " + Интервал);

                           Продолжить;

                    КонецЕсли;

                   

                   

                    Для Каждого Стр ИЗ ТЗСтавки Цикл

                    КонецЦикла;

                   

                   

                    ТЗПозиции = ВосстановитьРасчет(Магазин, Интервал, "ТЗПозиции");

                    Если ТЗПозиции = Неопределено Тогда

                           Сообщить("Не найден расчет ТЗПозиции: " + " Магазин: " + Магазин + "Интервал: " + Интервал);

                           Продолжить;

                    КонецЕсли;

                   

                   

                   

                    Для Каждого Стр ИЗ ТЗПозиции Цикл

                          

                    КонецЦикла;

                   

 

                   

             КонецЦикла;

            

       КонецЦикла;

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Ловыгин Антон (wunderland) 20.09.12 15:23
Специфическая технология, но как вариант... Sequoia View - порадовала, старенькая программка, молодеж и не знает наверно...
2. Осипов Сергей (fixin) 20.09.12 15:54
(1) а что же юзает молодеж? гыгыгы. Чтобы заценить свободное место на диске?
3. г. Казань Рустем Гумеров (Rustig) 20.09.12 19:59
(0) плюс за повод обсудить...
мое: я развернул дополнительно три файловые базы 1С (первые две уже заполнились до 4 Гб, теперь третья юзается), через ComСоединение из основной рабочей базы происходит чтение/запись информации в/из внешних баз 1С, написал алгоритм рекурсивного получения данных из баз, то есть если в первой базе нет значений, смотрим во вторую, если во второй нет, смотрим в третью, и так до последней, на любое количество баз рассчитано, через константу установил ограничение в три базы.
Использовал примерно ту же суть - вынес хранение информации за пределы основной рабочей базы. На вопрос сисадмина, почему не храню в каталогах? - ответил, что в этих дополнительных базах я могу управлять данными на своем родном языке 1С. :)
Программу Sequoia View не знаю, я из молодежи, и больше внедренец, чем железячник :)
4. Александр Зубцов (iov) 20.09.12 22:15
(0)(1)(2)
http://www.4shared.com/photo/E9mLDQVk/Scanner.html вот такое вам знакомо?
http://www.steffengerlach.de/freeware/ вот сайт - все бесплатно как вы любите...
5. Ловыгин Антон (wunderland) 21.09.12 09:38
(3)<и больше внедренец, чем железячник :)>
железячник, тут ни при чем, прога позволяет быстро оценить, кто все место на диске съел... а в своё время использовалась для быстрого поиска э ... интересного видео на чужом винте. Винты были маленькие, а видеофайлы - большие. Запустил прогу, и сразу видно где лежит...
6. Осипов Сергей (fixin) 21.09.12 10:33
(3) я тоже мог бы через COM, но таблицы нерегулярной структуры все равно пришлось бы универсализировать и терять на времени.
Если бы 1с давала на лету менять состав колонок, тогда да, можно было бы. А так проще в ТЗ.
(4) в прямоугольнике информации больше помещается, чем на круге. компактнее
7. Александр Зубцов (iov) 21.09.12 12:58
(6) не отказывайте себе в удовольствии - поюзайте + там есть интеграция в проводник... Это не реклама. Я сам на эту программку подсел когда активно серверами занимался... очень быстро находились профили наглых пользователей... Хотя нет - звучит как реклама... пойду к автору возьму процент от стоимости программы... ;)
8. Осипов Сергей (fixin) 21.09.12 13:26
(7) я ж говорю - мне круги не нравятся. чисто из-за того, что неэффективно место визуализации расходуется.
9. Александр Зубцов (iov) 21.09.12 13:33
(8) То есть вас тоже бесит круглая кнопка пуск ? :) ненавижу заразу :)
P.Sы - шутк.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа