1С:Предприятие 7.7. Оптимизация.
База данных - HighLoad оптимизация
Хочу сразу оговориться (уточнить), что в статье описаны приемы, которые позволяют на моем домашнем компьютере рассчитывать 11000 абонентов и при этом формировать и рассчитывать 60000 записей в журнал расчетов за 26 секунд в монопольном режиме в DBF версии 1С:Предприятия 7.70.025 на компоненте 1С:Расчет (ОС Windows XP). Объем базы данных около 350 Mb.
Постараюсь наиболее полно отразить замечания из комментариев к статье...
| Только качественный контент |
Мысль написать статью у меня появилась после того, как был задан вопрос в процессе обсуждения конфигурации для Абонентского отдела водоканала. Вопрос был прост: «Какие проблемы встречались, и какие методы использовались для повышения производительности».
Ответить на этот вопрос односложно не представляется возможным, т.к. было применено множество различных приемов. В этой статье описаны лишь некоторые из них. Начнем с того, что мне известно только два способа, которые позволяют поднять производительность вычислительной системы:
- Увеличить вычислительные мощности (железо)
- Сократить количество выполняемых действий (программа)
С первым способом все просто. Основной прирост производительности достигается заменой существующей вычислительной системы на более современную. Достаточно мощную и сбалансированную по производительности между основными компонентами: дисковой подсистемой, памятью и процессором. Также не стоит забывать о сетевом оборудовании и ОС.
По подбору оборудования есть достаточно много статей, поэтому на этом без сомнения важном способе повышения производительности задерживаться не будем, а рассмотрим поподробнее второй способ. Разумеется в свете примененных приемов в конфигурации Абонентский отдел водоканала.
Начнем с простого и очевидного. Первый прием. Использование библиотек turbobl.dll, автор Александр Орефков или 1cpp.dll. Если рассматривать типовые конфигурации фирмы 1С для 1С:Предприятия 7.7, то наиболее заметный эффект использования данных библиотек проявляется в конфигурациях «1С:Зарплата и кадры 7.7» и «1С:Комплексная конфигурация 7.7». В данном случае для использования этих библиотек не требуется значительная модификация кода конфигурации. Эффект наступает сразу после загрузки библиотек даже в типовых конфигурациях, т.к. рост производительности происходит на уровне платформы 1С:Предприятия 7.7. В базовых версиях можно воспользоваться обработкой, которая загрузит одну из библиотек.
Например, для загрузки библиотеки можно вставить в конец глобального модуля следующий код:
ИмяБиблиотеки = КаталогПрограммы() + "TurboBL.dll";
Если ФС.СуществуетФайл(ИмяБиблиотеки) = 1 Тогда
ЗагрузитьВнешнююКомпоненту(ИмяБиблиотеки);
Иначе
ИмяБиблиотеки = КаталогИБ() + "TurboBL.dll";
Если ФС.СуществуетФайл(ИмяБиблиотеки) = 1 Тогда
ЗагрузитьВнешнююКомпоненту(ИмяБиблиотеки);
КонецЕсли;
КонецЕсли;
Остальные приемы потребовали более значительной модификации программного кода конфигурации.
Второй прием связан с сокращением общего количества точек (разыменований) при выполнении кода. Этот прием является продолжением или частной модификацией первого приема. Т.е. рост производительности достигается за счет сокращения количества операций разыменования.
Например:
Форма.Закладки.Добавить("Общий,Кнопки", "Общий");
Форма.Закладки.Добавить("Льготы,Кнопки", "Льготы");
Форма.Закладки.Добавить("Объекты,Кнопки", "Объекты");
Заменяем на
СписокЗакладок = Форма.Закладки;
СписокЗакладок.Добавить("Общий,Кнопки", "Общий");
СписокЗакладок.Добавить("Льготы,Кнопки", "Льготы");
СписокЗакладок.Добавить("Объекты,Кнопки", "Объекты");
В данном случае удалось избавиться от двух точек и, несмотря на одну лишнюю команду, получить некоторый рост производительности. Этот пример демонстрирует лишь общий принцип, а не частный случай. Сравнить результат выполнения блоков команд можно, используя в отладчике замер производительности.
Результат применения второго приема можно посмотреть здесь: Дополнительные материалы к статье.
Третий прием связан с сокращением количества используемых в конфигурации команд СоздатьОбъект(). В конфигурации для Абонентского отдела водоканала команды СоздатьОбъект("СписокЗначений") и СоздатьОбъект("ТаблицаЗначений") встречаются 1 раз только в глобальном модуле конфигурации. Например:
Перем глПустаяТаблицаЗначений Экспорт;
//*******************************************************
// глТипТаблицаЗначений()
//
// Параметры:
// нет
//
// Возвращаемое значение:
// Пустая таблица значений
//
// Описание:
// Возвращает объект типа "ТаблицаЗначений"
// Работает в 5-6 раз быстрее чем использование
// конструкции СоздатьОбъект("ТаблицаЗначений")
//
Функция глТипТаблицаЗначений() Экспорт
Перем ТаблицаЗначений;
глПустаяТаблицаЗначений.Выгрузить(ТаблицаЗначений);
Возврат ТаблицаЗначений;
КонецФункции // глТипТаблицаЗначений
глПустаяТаблицаЗначений = СоздатьОбъект("ТаблицаЗначений");
Далее по тексту всех модулей использование вызовов может быть следующим:
Процедура ПроцедураСозданияТаблиц()
Перем Таблица1, Таблица2, Таблица3;
глПустаяТаблицаЗначений.Выгрузить(Таблица1);
Таблица1.НоваяКолонка("ТекущийЭлемент");
Таблица1.НоваяКолонка("ТЗ");
Пока <УсловиеЦикла> Цикл
// Запишем таблицу в таблицу таблиц
Таблица1.НоваяСтрока();
Таблица1.ТекущийЭлемент = ТекущийЭлемент;
Таблица1.ТЗ = глТипТаблицаЗначений();
КонецЦикла;
КонецПроцедуры //глИнициализацияВидовТарифов
Замеры производительности показали, что в случае использования библиотек turbobl.dll или 1cpp.dll наибольшее ускорение дают команды глПустаяТаблицаЗначений.Выгрузить() и глПустойСписокЗначений.Выгрузить(). При этом может быть ускорение в 50-55 раз. Если библиотеки не используются, то ускорение только в 5-6 раз - тоже неплохо. Но есть прием описанный в 7 посте этой статьи, который при работе со СпискомЗначений дает ускорение в 15 раз и это без использования библиотек: ЗначениеИзСтрокиВнутр("{""VL"",{}}").
Результат применения третьего приема можно посмотреть здесь: Дополнительные материалы к статье.
Четвертый прием связан с использованием разных объектов одного типа для чтения и для записи. Например, для работы с журналом расчетов один объект используется для расчета начального сальдо (чтение), а второй для записи результатов расчетов.
ЖУ = СоздатьОбъект("ЖурналРасчетов.Учет");
ЖР = СоздатьОбъект("ЖурналРасчетов.Учет");
Данная оптимизация связана с особенностями работы некоторых команд с журналом расчетов. В частности в связи со сбросом кэша. Подробно данная особенность и рекомендации по ее преодолению описаны на диске ИТС. Предлагаю рассмотреть этот способ как альтернативный вариант предложенному на диске ИТС.
Результат применения четвертого приема можно посмотреть здесь: Дополнительные материалы к статье.
Пятый прием связан с использованием эффективных порций обрабатываемой информации. Эффективные порции могут измеряться в строках документов, количестве записей или количестве сотрудников. Эти порции чтения-записи обрабатываются в транзакции. Следует отметить, что размер эффективных порций зависит от режима работы 1С:Предприятия 7.7. В монопольном режиме работы размер эффективных порций может быть в 2-4 раза больше, чем в разделенном режиме. Это связано с обработкой блокировок, которые создают дополнительный трафик в разделенном режиме.
В этом приеме есть некоторое противоречие, потому что транзакции призваны обеспечить целостность выполняемых изменений в информационной базе. А при использовании данного приема документ проводится несколькими транзакциями. Сбой при проведении в одной из транзакций может привести к частичному проведению документа, что, конечно же, исказит картину целостности информации. К счастью таких проблем за 12 лет не возникало.
Для определения размера эффективных порций можно воспользоваться счетчиками диспетчера задач «Прочитано байт» и «Записано байт». При подборе эффективной порции уменьшение значения этих показателей чаще всего дает наибольший рост производительности.
Рассмотрим возможную реализацию данного приема чуть подробнее.
- Отключается автоматическое удаление движений документа
- В форме документа создается процедура, которая запускает на проведение документ блоками
- В модуле документа процедура проведения изменяется на работу с блоками данных
- В модуле документа добавляется процедура отмены проведения
- В глобальном модуле добавляются процедуры на события пометки на удаление и отмены проведения документов с "особой" обработкой документов без автоматического удаления движений
- Изменяется групповая обработка документов, которая для документов без автоматического удаления движений открывает форму с передачей параметра запускающего документ на проведение
Блоки могут формироваться в виде списка (списка значений, массива и т.д.) или в виде указателя: номер строки, позиция в выборке по справочнику и т.д.
Примеры реализации можно посмотреть в типовых конфигурациях 1С или здесь http://www.infostart.ru/public/18657/
Пример обработки блоков с передачей указателя строки документа.
Текст в модуле формы документа
//*******************************************************
// __Провести()
//
// Параметры:
// Нет
//
// Описание:
// Сохраняет и проводит документ. При этом делит процесс проведения на
// несколько транзакций, что значительно сокращает общее время
// проведения документа.
//
Процедура __Провести()
ПриЗаписи();
Если СтатусВозврата() = 0 Тогда
Возврат;
ИначеЕсли Модифицированность() = 1 Тогда
Записать();
ИначеЕсли Выбран() = 0 Тогда
Записать();
КонецЕсли;
Если глУдалитьДвиженияДокумента(ТекущийДокумент()) = 0 Тогда
Возврат
КонецЕсли;
ФлагПроведения = 1;
Сч = 1; КоличествоСтрок = КоличествоСтрок();
Пока Сч <= КоличествоСтрок Цикл
ФлагПроведения = Провести(,Сч);
Если ФлагПроведения = 0 Тогда
Прервать
КонецЕсли;
Сч = Сч + 500;
КонецЦикла;
Если ФлагПроведения = 0 Тогда
глУдалитьДвиженияДокумента(ТекущийДокумент());
СделатьНеПроведенным();
КонецЕсли;
КонецПроцедуры //__Провести
Текст в модуле документа
//*******************************************************
Процедура ОбработкаПроведения(Режим = 0)
// Режим = 0 - провести документ без формирования движений по документу
// Режим > 0 - допроведение документа
Если ГрупповаяОбработка() = 1 Тогда
глСообщениеГрупповойОбработки(ТекущийДокумент);
СтатусВозврата(0); Возврат;
ИначеЕсли Режим = 0 Тогда
Возврат;
КонецЕсли;
Для Сч = Режим По Мин(Режим + 499, КоличествоСтрок()) Цикл
ПолучитьСтрокуПоНомеру(Сч);
// Текст обработки строк документа
КонецЦикла;
КонецПроцедуры //ОбработкаПроведения
Шестой прием связан с заменой использования для объектов типа СписокЗначений метода Принадлежит() на метод НайтиЗначение(). Это связано с особенностями данных методов. Вот описание из метода Принадлежит():
Если на принадлежность проверяется значение типа элемент справочника, то проверка выполняется с учетом его возможного вхождения в группы справочников, которые являются значениями списка значений. Данный метод оптимизирует проверку принадлежности при массовых последовательных сравнениях, если между сравнениями сам список значений не меняется.
Как показали замеры (в том числе и в отладчике) в большинстве случаев заявленная оптимизация не работает. Из около 100 проверенных строк кода оптимизация отработала только в 2-х. Во всех остальных случаях получалось ускорение в 2-3 раза на замененной команде. При сотнях тысяч повторений эффект получается довольно значительный. К сожалению мне не удалось определить точно по какому принципу определяется "массовое последовательное сравнение" и включается оптимизация, поэтому предлагаю протестировать конкретный кусок кода до и после применения данного приема.
Результат применения шестого приема можно посмотреть здесь: Дополнительные материалы к статье.
Седьмой прием касается передачи параметров между функциями в модуле. Довольно часто математика конфигурации развалена по функциям и процедурам. При этом одни и те же переменные передаются между функциями и процедурами по ссылкам. На передачу и прием параметров также тратится некоторое время. Эти переменные можно объявить глобальными, если обработка происходит в глобальном модуле или объявить переменными модуля, если обработка происходит в модуле формы или модуле объекта.
Результат применения седьмого приема можно посмотреть здесь: Дополнительные материалы к статье.
Восьмой прием связан с сокращением повторных обращений к базе данных в рамках, например, проведения документа. Т.к. операции чтения из базы данных являются более медленными, чем, например, из ТаблицыЗначений.
Пример использования данного приема применительно к конфигурациям «1С:Торговля и склад 7.7» и «1С:Комплексная 7.7» можно посмотреть здесь Распределение суммы по таблице значений
Разумеется, в конфигурации Абонентский отдел водоканала применяется еще множество других приемов. Но это касается в большей степени рефакторинга.
Да, еще про печать. Тема от ineoosaki. Вот несколько приемов. При выводе печатных форм оптимизировать можно код и таблицу.
Девятый прием. Выражения, выводимые при печати лучше рассчитывать в модуле, а не в таблице использующейся в качестве шаблона. Данная рекомендация есть на диске ИТС. А также при заполнении данных в областях использовать поименнованые секции.
Результат применения девятого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.
Десятый прием. Шаблон печатной формы. Чем меньше ячеек содержит результирующая таблица, тем меньше памяти потребуется для ее отображения, тем быстрее будет выполняться навигация по таблице. Также при формировании таблиц большого объема нужно стараться избегать использования картинок и объединенных ячеек. Последние в некоторой степени можно заменить, указав свойство «По выделенным столбцам».
Результат применения десятого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.
Одиннадцатый прием. Для больших таблиц также применим метод определения эффективной порции. Т.е. большой отчет может быть разбит на несколько небольших отчетов. Это тоже позволит поднять производительность печати.
Результат применения одиннадцатого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.
Двенадцатый прием. Кроме этого можно значительно сэкономить ресурсы ПК, если отправлять отчеты непосредственно на печать без вывода на экран. При этом таблицы MXL можно предварительно сохранить на жестком диске и отправлять на печать по очереди с диска, а не держать в оперативной памяти. Также можно повысить и скорость печати, если организовать печать одновременно на несколько принтеров.
Это к 1С не имеет прямого отношения, но все-таки. Так как большинство принтеров имеют встроенные шрифты, то для повышения скорости печати можно уменьшить "качество" печати до 150 dpi. Буквы останутся в идеальном состоянии, а при печати таблиц для вертикальных и горизонтальных линий такой точности более чем достаточно. С учетом того, что MXL это таблица, то ускорение будет, даже если в печатной форме нет рамок.
Не стоит забывать о регламентных операциях с базой данных: переиндексация, пересчет итогов и ссылок, упаковка. Ну, и конечно дефрагментация жесткого диска.
Дополнительные материалы к статье.
Про экранные формы. Раньше, когда о Core 2 Quad никто даже не думал, быстрая прорисовка экранных форм была достаточно больной проблемой. Возникали промигивания при переключении по закладкам. Значительные торможения при изменении реквизитов в формах или при пролистывании списков. В каких местах кода происходят задержки можно посмотреть в отладчике с помощью замера производительности.
Четырнадцатый прием. Работа с закладками. Переключение по закладкам будет выполняться быстрее, если при отображении элементов формы будет выполнять как можно меньше команд. Например, так
//*******************************************************
Процедура ПриОткрытии()
СписокЗакладок = Форма.Закладки;
СписокЗакладок.Добавить("Общий,Кнопки", "Общий");
СписокЗакладок.Добавить("Льготы,Кнопки", "Льготы");
СписокЗакладок.Добавить("Объекты,Кнопки", "Объекты");
КонецПроцедуры //ПриОткрытии
//*******************************************************
Процедура ПриОткрытиПриВыбореЗакладки(НомерЗакладки, ЗначениеЗакладки)
Форма.ИспользоватьСлой(ЗначениеЗакладки, 2);
КонецПроцедуры //ПриВыбореЗакладки
Пятнадцатый прием. Сокращение расчетов при отображении текстовых полей. Ярким примером текстового поля содержащего формулу является вывод адреса на форму. Перерисовка и соответственно выполнение формулы происходит при изменении реквизитов формы, при смене закладок. Это обычно не имеет отношения к адресу и поэтому нет смысла вычислять представление адреса. В этом случае можно сделать, например, так. В форме вызов процедуры глобального модуля глПредставлениеАдреса(Адрес) заменить на вызов локальной процедуры ПредставлениеАдреса(), а в модуле формы использовать следующий код:
//*******************************************************
Перем СтАдрес, АдресПредставление;
//*******************************************************
Процедура ПредставлениеАдреса()
Если СтАдрес <> Адрес Тогда
СтАдрес = Адрес;
АдресПредставление = глПредставлениеАдреса(СтАдрес);
КонецЕсли;
Возврат АдресПредставление;
КонецПроцедуры //ПредставлениеАдреса
Формирование представления адреса тоже можно оптимизировать. К теме данной статьи это, наверное, не имеет прямого отношения, но все же. Для формирования представления адреса можно использовать такой код глобального модуля:
//*******************************************************
Перем глСокрАдреса[10];
//*******************************************************
// глПредставлениеАдреса(АдреснаяСтрока,Способ)
//
// Параметры:
// Адрес (строка), адрес представление которого нужно вернуть.
// Способ - способ представления адреса (если=1, то возвращает представление адреса без индекса)
//
// Возвращаемое значение:
// Строка: представление адреса
//
// Описание:
// Предназначена для формирования адресной строки в "удобочитаемом" виде
// для отражения в формах.
//
Процедура глПредставлениеАдреса(Адрес, Способ = 0) Экспорт
АдреснаяСтрока = СокрЛП(Адрес);
Если (АдреснаяСтрока = ",,,,,,,,,") или (АдреснаяСтрока = "") Тогда
Если Способ = 0 Тогда
Возврат "<>"
КонецЕсли;
Возврат ""
ИначеЕсли СтрЧислоВхождений(АдреснаяСтрока, ",") <> 9 Тогда
Возврат СтрЗаменить(АдреснаяСтрока, РазделительСтрок, ", ")
КонецЕсли;
Индекс = 2;
Результат = "";
лСпособ = Способ + 2;
АдреснаяСтрока = Сред(АдреснаяСтрока, 2);
Пока АдреснаяСтрока <> "" Цикл
Если АдреснаяСтрока = "," Тогда
Прервать
ИначеЕсли АдреснаяСтрока = ",,," Тогда
Прервать
ИначеЕсли АдреснаяСтрока = ",," Тогда
Прервать
КонецЕсли;
Поз = Найти(АдреснаяСтрока, ",");
Если Поз = 1 Тогда
АдреснаяСтрока = Сред(АдреснаяСтрока, 2)
ИначеЕсли Индекс < лСпособ Тогда
АдреснаяСтрока = Сред(АдреснаяСтрока, Поз + 1)
Иначе
Если Поз = 0 Тогда
СтрокаИзАдреса = АдреснаяСтрока;
АдреснаяСтрока = ""
Иначе
СтрокаИзАдреса = Лев(АдреснаяСтрока, Поз - 1);
АдреснаяСтрока = Сред(АдреснаяСтрока, Поз + 1)
КонецЕсли;
Если СтрокаИзАдреса = "" Тогда
ИначеЕсли Результат = "" Тогда
Результат = СтрокаИзАдреса
ИначеЕсли Индекс > 7 Тогда
Результат = Результат + глСокрАдреса[Индекс] + СтрокаИзАдреса
Иначе
Результат = Результат + ", " + СтрокаИзАдреса
КонецЕсли;
КонецЕсли;
Индекс = Индекс + 1
КонецЦикла;
Возврат Результат
КонецПроцедуры //глПредставлениеАдреса
//*******************************************************
глСокрАдреса[8] = ", д. ";
глСокрАдреса[9] = ", кор. ";
глСокрАдреса[10] = ", кв. ";
Т.к. адрес встречается во многих местах большинства конфигураций и хранится чаще всего в формате ИМНС, то данная оптимизация может быть весьма полезной.
Шестнадцатый прием. Использование промежуточных (буферных) переменных при сборке строк большой длины. Небольшое усложнение кода (добавляется 5 строк) может дать ускорение в несколько раз. Результат применения шестнадцатого приема можно посмотреть здесь: Дополнительные материалы к статье.
Для раскрашивания программного кода в тексте статьи в цвета конфигуратора 1С:Предприятия 7.7 была использована Разукрашка.
31.01.2009 /Константинов Алексей Викторович/
Редакция от 18.02.2011
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
HighLoad оптимизация Системный администратор 1С:Предприятие 7.7 1C77 Бесплатно (free)
Вариант для SQL 77
18.10.2022 5119 Dionisiy 7
HighLoad оптимизация Разработчик 1С:Предприятие 7.7 1C77 Абонемент ($m)
Конфигурация на 1С 7.7, показывающая блокировки на MS SQL сервере и доменных пользователей по SPID. Используется 1С++ и классы.
1 стартмани
09.11.2021 6815 10 ShoDm 17
HighLoad оптимизация Инструменты администратора БД Системный администратор Разработчик 1С:Предприятие 7.7 1С:Предприятие 8 1C:Бухгалтерия 1C77 Бесплатно (free)
Еще один подход к увеличению производительности 1C+SQL = использование RAM-дисков
16.02.2015 48412 kos 36
HighLoad оптимизация Системный администратор 1С:Предприятие 7.7 Оперативный учет 7.7 Бухгалтерский учет 7.7 Расчет 7.7 1C77 Абонемент ($m)
1С сама проверит своё железо и скажет, чего ей не хватает!
1 стартмани
12.01.2014 25067 80 by_1Cnik 7
HighLoad оптимизация Системный администратор Разработчик 1С:Предприятие 7.7 1C77 Бесплатно (free)
Недорогое повышение скорости работы 1С
31.05.2013 15209 ins-post 22
Чистка данных HighLoad оптимизация Системный администратор Разработчик 1С:Предприятие 7.7 1C77 Абонемент ($m)
По статье "Зачем в 1С нужно периодически пересчитывать итоги по регистрам?" http://infostart.ru/public/177171/ Обработка для 7.7, чтобы посмотреть что же творится в БД для SQL
1 стартмани
13.03.2013 25437 54 maxpiter 15
Инструменты администратора БД HighLoad оптимизация Системный администратор Разработчик 1С:Предприятие 7.7 1C77 Бесплатно (free)
Автоматическая переиндексация базы
11.09.2012 19613 Gazulo 3
HighLoad оптимизация Системный администратор Разработчик Оперативный учет 7.7 Бухгалтерский учет 7.7 Расчет 7.7 1C77 Россия Бесплатно (free)
Обратились ко мне с вопросом по теме форума: http://forum.mista.ru/topic.php?id=558772 Автор темы: "DennizzM". Название: "v7: 1c v7.7 ошибки транзакции - как отловить виновника?" Текст с сокращениями: "Вопрос наверняка не новый... Итак - есть база 1c v7.7 (самописная конфа). Периодически у пользователей возникает ошибка при проведении транзакции. База работает под терминалом. Нагрузка на дисковую подсистему небольшая, CPU на нуле, RAM до черта свободного. Вопрос вот в чем - как отловить инициатора первой транзакции которая всех держит? Итак - как мне выкрутиться? ;) ...я не имею права и не могу лезть внутрь конфы и модифицировать ее.".
13.07.2011 28874 hogik 16
Последние версии 1С++ 3.0.1.ХХ еще сильнее ускоряют 1С даже по сравнению с ТурбоБЛ :)
(7) Кстати, в последних версиях 1С+ 3.0.1.ХХ списки и таблицы значений автоматически создаются намного быстрее, чем в простой 1С, и даже чуть быстрее указанного тобой известного способа :)
У меня на этом тесте получилось что максимальная скорость достигается именно с ТурбоБЛ. Если отключить перехватчики в 1C++ скорость повышается, но все равно медленнее чем с ТурбоБЛ.
Проверял я это после введения ускоренного создания объектов в 1С++, честно говоря, был удивлен полученным результатом.
Функция _Новый(стрОбъект) Экспорт
Если стрОбъект = "СписокЗначений" Тогда
Возврат ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЕсли;
Если стрОбъект = "ТаблицаЗначений" Тогда
Возврат ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЕсли;
КонецФункции
Результаты проверки:
Список значений: 1: 410 2: 427
Таблица значений: 1: 498 2: 1254
Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипСписокЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Сообщить("Список значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2));
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипТаблицаЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Сообщить("Таблица значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2));
КонецПроцедуры
Ну и про переменные, которые надо сделать глобальными в текущем модуле. Уж не знаю на сколько ты при этом выиграешь в скорости, но вот неожиданных засад ты получаешь тем больше, чем больше у тебя таких переменных.
Спасибо за статью, будет полезна новичкам: недавно натолкнулся на - после просмотра кода пришел в ужас.
Вопросы вызывают пункты 7 и 11 (как и у всех).
Повсеместное использование глобальных переменных до добра не доводит. Должен быть баланс: иногда логичнее применить способ оптимизации 1 (железа или вообще технология).
Собственно к камням :)
Документ ВводРасчетов модуль документа:
Процедура ОбработкаПроведения(Режим = 0)
// Режим = 0 - провести документ без формирования движений по документу
// Режим = 1 - удалить движения документа
// Режим > 1 - допроведение документа
Если ГрупповаяОбработка() = 1 Тогда
глСообщениеГрупповойОбработки(ТекущийДокумент);
СтатусВозврата(0); Возврат;
ИначеЕсли Режим = 0 Тогда
Возврат;
КонецЕсли;
Если ДатаДок <> НТП Тогда
Предупреждение("Этот документ можно провести только в текущем периоде!");
СтатусВозврата(0); Возврат;
КонецЕсли;
Для Сч = 1 По _гл_СписокАбонентов.РазмерСписка() Цикл
Аб = _гл_СписокАбонентов.ПолучитьЗначение(Сч);
ИнициализацияАбонента();
КонецЦикла;
КонецПроцедуры //ОбработкаПроведения
При интерактивном проведении _гл_СписокАбонентов заполняется. А что будет если мне забожается выполнить ДокВводРасчетов.Провести() из кода обработки?
МНЕ кажется такой подход не оправдан. Не стоит раскидывать логику проведения по разным местам.
По 11 приему вроде не было вопросов. Скоро сделаю обезличенную базу - посмотреть как это выглядит можно будет там.
По 10 приему - можно еще погонять тесты, но варианта без объединения по вертикальным секциям состоящих из нескольких строк я не представляю...
> При интерактивном проведении _гл_СписокАбонентов заполняется. А что будет если мне забожается выполнить ДокВводРасчетов.Провести() из кода обработки?
Внутри конфигурации есть групповая обработка документов. Там все работает как надо...
Сейчас проверю. Добавлю статистику по этому вопросу...
Я НЕ сомневаюсь, что работает как надо :).
Речь об "изолированности" что-ли. Ведь можно передавать список в качестве параметра для функции проведения: ОбработкаПроведения(вхСписокАбонентов), и получить более "устойчивый" функционал :)
З.Ы. Сейчас задам вопрос в теме
При проведении документа в 1 транзакции время проведения не стабильно в течении сеанса:
1 проведение - 128 секунд
2 проведение - 216 секунд
3 проведение - 235 секунд
4 проведение - 700 секунд
5 проведение - 221 секунда
6 проведение - 668 секунд
При использовании приема время проведения стабильно в течении сеанса - 49 секунд
В 19 посте данные при работе в монопольном режиме.
В разделенном режиме терминальной сессии картинка иная.
Проведение в 1 транзакции
1 проведение - 756 секунд
2 проведение - 955 секунд
3 проведение - 1080 секунд
4 проведение - 1056 секунд
Проведение с использованием 5 приема - 65 секунд стабильно
1. Отключается автоматическое удаление движений документа
2. В форме документа создается процедура, которая запускает на проведение документ блоками
3. В модуле документа процедура проведения изменяется на работу с блоками данных
4. В модуле документа добавляется процедура отмены проведения
5. В глобальном модуле добавляются процедуры на события пометки на удаление и отмены проведения документов с "особой" обработкой документов без автоматического удаления движений
6. Изменяется групповая обработка документов, которая для документов без автоматического удаления движений открывает форму с передачей параметра запускающего документ на проведение
Блоки могут формироваться в виде списка (списка значений, массива и т.д.) или в виде указателя: номер строки, позиция в выборке по справочнику и т.д.
Примеры реализации можно посмотреть в типовых конфигурациях 1С или здесь
При этом рефакторинг даст существенно меньший прирост.
Сначала выявить узкие места, а потом решать в каком порядке их чинить.
Почему? А Вы это написали во втором абзаце "пятого приёма". Плюс приличные переделки конфигурации. Однако проблема больших транзакций в DBFной 1С существует. Я, как раз, недавно проводил тестирование этой проблемы. Так если выполняется 10'000 некоторых (моего теста) обновлений в рамках одной транзакции, то это занимает пол минуты. А для 100'000 таких же действий - часы. Т.е. это дольше не в 10 раз :-(. В этом смысле CodeBase - бяка... ;-)
Так такой выход из ситуации? Какие предложения?
"Так такой выход из ситуации?"
Сменить СУБД.
"Какие предложения?"
Если оставлять Ваш алгоритм, то хотя бы упразднить большие переделки конфигурации. Например, взять вот эту дрянь и добавить управляемый алгоритм принудительного завершения и начала реальной транзакции внутри логической транзакции. С помощью вызова некой функции, расставленной в тексте конфигуратора. И еще добавить алгоритм отслеживания целостности...
А про настройки сервера базы в статейке ни слова....
Зато немало места уделено тому, чему вообще не надо уделять внимания в теме "производительность". Какое-такое снижение производительности вы добъетесь манипуляцией объявления закладок формы?! Вы о чем? Отладка чего-то в формах совершенно бессмыслена, если результат "не заметен глазу".
Как приятно было узнать (из ссылка на subscribe.ru), что обращения к реквизитам формы "самые медленные". Только надо циклом обратиться к ним миллион раз, чтоб заметить это :))
Но для сдачи зачета пойдет ;)
Замените закладки на Перечисление или Константы. Собственно примеров можно придумать много...
Вот из той же ЗиК
Функция глСЗВПеречислениеСтароеВНовое(Старое) Экспорт
//Если Старое.Вид() = "СЗВОсобыеУсловияТруда" Тогда
Если Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12А Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п1;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Б Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п2;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12В Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п3;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Г Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п4;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Д Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п5;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Е Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п6;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Ж Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п7;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12З Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п8;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12И Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п9;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12К Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п10;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Л Тогда
Старое = ПолучитьПустоеЗначение("Перечисление.СЗВОсобыеУсловияТруда2002");
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12М Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пОС;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12О Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пПЖ;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.СЕВ26 Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пСЕВ;
//ИначеЕсли Старое.Вид() = "СЗВОснованияИТС" Тогда
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.СЕЗОН Тогда
Старое = Перечисление.СЗВОснованияИТС2002.СЕЗОН;
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.ЛЕПРО Тогда
Старое = ПолучитьПустоеЗначение("Перечисление.СЗВОснованияИТС2002");
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.УИК104 Тогда
Старое = Перечисление.СЗВОснованияИТС2002.УИК104;
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.ВОДОЛАЗ Тогда
Старое = Перечисление.СЗВОснованияИТС2002.ВОДОЛАЗ;
//ИначеЕсли Старое.Вид() = "СЗВОснованияВыслугиЛет" Тогда
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ГР Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п11ГР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ВП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п11ВП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ФЛ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п12;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78СС Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП80ПД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пПД;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП80РК Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пПДРК;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП81ГД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пГД;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП81СМ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСМ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ХИРУРГД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пГДХР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ХИРУРСМ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСМХР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ15 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ15;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ20 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ20;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ25 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ25;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ30 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ30;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.САМОЛЕТ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.САМОЛЕТ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.СПЕЦАВ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.СПЕЦАВ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.СПАСАВ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.СПАСАВ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.УЧЛЕТ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.УЧЛЕТ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ВЫСШПИЛ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ВЫСШПИЛ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.НОРМАПР Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМАПР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.НОРМСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.РЕАКТИВН Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЛЕТРАБ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ЛЕТРАБ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЛЕТИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ЛЕТИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ОПЫТИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ОПЫТИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИСПКЛС1 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ИСПКЛС1;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИТСИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ИТСИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.УВД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п14;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИТС Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п15;
КонецЕсли;
Возврат Старое;
КонецФункции // глСЗВПеречислениеСтароеВНовое()
или вот еще
Процедура глСброситьПрогрессор(Прогрессор) Экспорт
Прогрессор.ПолучитьЗначение(2).Прогрессор.Заголовок("");
Прогрессор.ПолучитьЗначение(2).ПроцентПрогрессора.Заголовок(Формат(0,"Ч3")+"%");
Прогрессор.ПолучитьЗначение(2).Обновить(0);
Прогрессор.УстановитьЗначение(1,0);
КонецПроцедуры // глСброситьПрогрессор
Это совершенно не имеет отношения к "1С:Предприятие". Требование "выноси за пределы цикла все, что можно сделать вне цикла" - это ШКОЛА. И дОлжно исполнятся не думая.
Документ ЗаявкаНаОткрытиеСчетов процедура СформироватьФайлНаОткрытиеСчетов ищем СоздатьОбъект("Справочник.ДокументыУдостоверяющиеЛичность").
Документ НачислениеНалоговСФОТ процедура ПровестиИзФормы ищем СоздатьОбъект("СписокЗначений").
Документ ПриказНаОплатуПоСреднему процедура Печать ищем СоздатьОбъект("ТаблицаЗначений").
...нашел еще 5 мест - надоело...
Теперь можно смеяться или плакать...
Сырая статья. Ну очень сырая. Поспешил ты. Написал то, что не стОило упоминания. Скомкал то, что достойно более тщательного описания (про "пятый пункт", например).
Вот что обидно.
А приведенные тобой примеры вполне ложаться в раздел "Программируйте правильно". Или "Как не надо кодить". А что? Стиль оказывает общеоздоровляющее действие и на производительность ;))
Хотелось бы поместить статью в свой директорий на диске "Полезные статьи", ан не судьба. Вот такое эгоистическое желание.
Но еще не вечер? Да? :)
"Удаление движений документа:..."
Согласен с Ёпрст в (41-46). И сомневаюсь, что "...проблем за 8 лет не возникало"©. Или всем всё безразлично при работе с Вашей разработкой... Или, типа, как в анекдоте: "Нам выдают бесплатное молоко, т.к. у нас вредное производство. Но мы этого не замечаем, не замечаем, не замечаем...".
На N-ой строке не провелось по какой-либо причине (транзакция например, или тупо по условию в модуле проведения, не суть важно как) и привет...Документик на половину проведён ? ...
Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипСписокЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("СписокЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Список значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2) + " 3: " + (С4 - С3));
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипТаблицаЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("ТаблицаЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Таблица значений 1: " + (С2 - С1) + " 2: " + (С3 - С2) + " 3: " + (С4 - С3));
КонецПроцедуры
Результаты проверки:
Без библиотек
Список значений: 1: 1405 2: 441 3: 5275
Таблица значений 1: 1693 2: 1246 3: 6356
Загружена turbo.bl
Список значений: 1: 396 2: 422 3: 5242
Таблица значений 1: 490 2: 1229 3: 6349
Загружена 1cpp.dll
Список значений: 1: 405 2: 427 3: 202
Таблица значений 1: 496 2: 1262 3: 253
Переписал тест. Убрал время на цикл. Поставил прямые вызовы.
Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
Перем А, ПустойСписокЗначений, ПустаяТаблицаЗначений;
С0 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
КонецЦикла;
С1 = _GetPerformanceCounter();
глПустойСписокЗначений.Выгрузить(ПустойСписокЗначений);
Для Индекс = 1 По 100000 Цикл
ПустойСписокЗначений.Выгрузить(А);
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("СписокЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
ПоправкаНаЦикл = С1 - С0;
Сообщить("Список значений: 1: " + (С2 - С1 - ПоправкаНаЦикл) + " 2: " + (С3 - С2 - ПоправкаНаЦикл) + " 3: " + (С4 - С3 - ПоправкаНаЦикл));
С1 = _GetPerformanceCounter();
глПустаяТаблицаЗначений.Выгрузить(ПустаяТаблицаЗначений);
Для Индекс = 1 По 100000 Цикл
ПустаяТаблицаЗначений.Выгрузить(А);
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("ТаблицаЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Таблица значений 1: " + (С2 - С1 - ПоправкаНаЦикл) + " 2: " + (С3 - С2 - ПоправкаНаЦикл) + " 3: " + (С4 - С3 - ПоправкаНаЦикл));
КонецПроцедуры
Результаты проверки:
Без библиотек
Список значений: 1: 1031 2: 352 3: 5204
Таблица значений 1: 1249 2: 1167 3: 6303
Загружена turbo.bl
Список значений: 1: 98 2: 348 3: 5178
Таблица значений 1: 116 2: 1143 3: 6279
Загружена 1cpp.dll
Список значений: 1: 101 2: 351 3: 131
Таблица значений 1: 118 2: 1142 3: 181
1. Загрузка ВК +
2.сокращением общего количества точек -
3.Сокращение вызовов СоздатьОбъект -
4. ?? Вообще не понятно о какой оптимизации идёт речь
5.спользованием эффективных порций -
6.Использовать НайтиЗначение вместо Принадлежит +/-
если СЗ статичный, то Принадлежит быстрее...причем намного
7.объявить переменными модуля не есть гуд -
8.Непонятно о каком повторном чтении данных идёт речь .. +
9.Выражения расчитывать вне мокселя +
10. Объединять ячейки -
(и вообще, стараться избегать их вообще, даже если страдает красота при объединении вертикальных ячеек)
11.Вы предлагаете смотреть отчет в 5-6 листах что ли ? Кто его вообще смотреть будет ?
-
12.Печать без просмотра +
Итого:
4 +
6 -
:)
Получается "оптимизация" наоборот...
1) Статья про абонентский отдел водоканала.
2) Фронт офис.
3) Компонента "Расчет".
Уже некий сюрреализм. Еще бы торговый зал супермаркета на журнале расчетов построили.
Похоже, дело было так. Пришел лох, попросил инструмент для закручивания шурупов, ему впарили титановый абак с заточенным углом. Мало ли, что отверток нет, лоха упускать нельзя!
Потом оказалось, что шурупов много, и расположены они близко друг к другу, а абак громоздкий. Нет проблем, пилим его на части. И чтоб не гремел, камешки вытряхиваем - за отдельную плату, конечно.
4) Перерасчет за пол года формирует 190000 записей за 2 минуты, при этом проводится только 1 документ.
190000 записей из одного документа, не уголовщина, конечно, но оскорбление общестенной нравственности - однозначно. Если вы едете в автомобиле по городу с нормальной скоростью, но на двух колесах, ПДД вы не нарушаете. Но на первом же посту вас тормознут - и правильно сделают.
Кстати, а зачем может потребоваться перерасчет сразу всех за полгода? При изменении законодалельства задним числом? Это уже форс-мажор, имхо. А если полгода назад абонент заплатил 200 рублей, а разнесли ему 20, так при нормальной реализации требуется одна запись, а не 180000.
Это не готовое решение, конечно, но пример реализации на компоненте Бухучет.
Речь шла о том, что содержательных расчетов для нескольких тысяч абонентских точек не требуется – начисление фиксированное. Содержательные расчеты, вроде перемножения двух чисел требуются при изменении статуса абонентской точки (справку принесли), при поступлении платежа – это две-три проводки. При вводе показаний счетчиков контролерами количество проводок соответствует количеству строк документа. Все это измеряется в секундах.
Вот начисление по бессчетчиковым абонентским точкам в случае, когда их десятки тысяч, требует оптимизации. Например, разделить получение (периодической) начисляемой суммы по абонентским точкам (заполнение непериодического реквизита «ТекущийПлатеж») и формирование проводок.
А статья как раз об оптимизации...
В конфигурации "Абонентский отдел водоканала", например, ПКО рассчитан на работу с 1 абонентом. Но есть ряд документов рассчитанных на работу с несколькими тысячами абонентов. И приведенный в заголовке пример как раз обсчитывает абонентов, услуги для которых рассчитываются по нормам.
Мои замечания касались применения в конкретной предметной области неподходящего инструмента.
Вот, например, "Но есть ряд документов рассчитанных на работу с несколькими тысячами абонентов".
Эти документы не существуют сами по себе. Они придуманы разработчиком конфигурации. Из потребностей автоматизации они не вытекают. И уж точно, когда клиент пришел выяснить состояние взаиморасчетов, оператор не должен перелопачивать записи в БД, к данному клиенту не относящиеся.
- есть заводик. делает розетки
- да? какие?
- вот смотрите. все здесь
- что всего 12? такое мы богато бачили. лучше бы сало показали
- да нет. он много может делать. это образцы - 12 цветов
- много может делать? а что, есть проблемы с производительностью? как вы их решаете
- сокращаем непроизводственные потери
- потери уже потеряны. итог "ацтой"
- но он ведь может делать 190000 шт. за 2 минуты
- зачем делать 190000, когда можно делать только 1?
- ...
Вобщем решения интересны, но не всегда реализуемы
Когда конфигурация самописная, то все понятно - режешь как хочешь. В типовых конфигурациях мне приходилось оптимизоровать лишь самые узкие места с точки зрения пользователей. Т.е. внося минимальные изменения в конфигурацию, но получая максимальный эффект.
Вполне очевидно, что это непростительная роскошь => такой документ не нужен.
Но в некоторых отдельных случаях turbo.bl может быть эффективннее. См. результаты проверки в 54 посте. Думаю это зависит от конкретной конфигурации и от конкретного комьютера. Например, если есть проблемы с загрузкой 1cpp.dll, то можно использовать turbo.bl. Это будет лучше чем не использовать ничего...
Естественно на том коме, где лежит база все быстро.
Конфигурация компов 1ПК: CoreDuo, 1Gb RAM, GigabitLAN , 2ПК: CeleronD, 512 Mb RAM , GigabitLAN/
Выключение Кашмарского эффекта не дает:(
1. можно уменьшить трафик по сети отключив неиспользуемые отборы и сортировки по операциям и проводкам
2. можно уменьшить трафик по сети увеличив время обновления списков
3. проверить работу антивирусов, отключить проверку сетевых дисков
4. проверить размещение каталогов пользователей, сделать каталоги локальными
5. почистить файл с настройками пользователей 1Cv7.CFG
6. можно уменьшить время обработки, сделать upgrade слабого компьютера
7. проверить работу сети. влючен ли Gigabit FullDuplex. какая скорость прокачки?
8. выполнить дефрагментацию жестких дисков обоих ПК
Но прием описанный в статье после загрузки 1С++ З.Х выполняется все равно быстрее, чем создание нового объекта. Это наглядно демонстрирует тест приема 3. Вот лог теста:
Список значений: 1 (из статьи): 1078 2 (альтернативный): 347 3 (типовой): 74725
Ускорение (из статьи): 69.32
Ускорение (альтернативный): 215.35
Прием 3 из статьи "1С:Предприятие 7.7. Оптимизация."
Таблица значений 1 (из статьи): 1252 2 (альтернативный): 1146 3 (типовой): 75911
Ускорение (из статьи): 60.63
Ускорение (альтернативный): 66.24
1cpp.dll загружена
Список значений: 1 (из статьи): 100 2 (альтернативный): 356 3 (типовой): 128
Ускорение (из статьи): 1.28
Ускорение (альтернативный): 0.36
Прием 3 из статьи "1С:Предприятие 7.7. Оптимизация."
Таблица значений 1 (из статьи): 118 2 (альтернативный): 1201 3 (типовой): 188
Ускорение (из статьи): 1.59
Ускорение (альтернативный): 0.16
Тогда я статью поправлю...
Ну и ассоциативный вектор вместо списка значений. Очень хороший объект (в 8-ке есть его аналог Структура), и просто Вектор (массив).
Про 1С++ в статье упоминается в самом начале, ссылка есть. Переписывать все материалы с сайта не считаю необходимым.
Присвоение Значения колонке таблицы значений типизированной как просто "Число"
Вдвое быстрее чем присвоение колонке для которой указана длина и точность.
А присвоение значения нетипизированной колонке о-о-очень медленное мероприятие.
В списке значений тоже фокус интересный есть:
Если добавлять значение справочника и не указывать представление, то 1с в базу за представлением сходит.
Поэтому всегда в качестве представления пустую строку передаю. Даже если список будет показан на экран все представления будут нормально отображены.
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 18924
Создание 31.01.09 22:19
Обновление 26.12.12 08:47
Просмотры 58196
Загрузки 0
Рейтинг
217
Комментарии 110
Код открыт Не указано
Рубрики HighLoad оптимизация
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 7.7
Конфигурация 1C77
Операционная система Не имеет значения
Страна Россия
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)