Заметочки про 1С:Предприятие 8 (редакция 23.03.2012)
За время программирования на 8.х, накопилось пока немного материала, но как мне кажется очень интересного. Появились простые решения, которые в более сложной реализации встречаются в типовых конфигурациях и в некоторых публикациях на Infostart'е. Собственно в статье речь пойдет об этих решениях.
31.05.2010 20:49 [28.04.2012 05:17] 530 [+] [−] Перейти к публикации
(1) Количество повторов 1000000
Замер код записан в 4 строки. Завершено за 3,329 сек.
Замер код записан в 1 строку. Завершено за 0,5 сек.
У меня получилось приблизительно в 6 раз. Но здесь нужно учитывать только время переходов. Если в цикле будут команды, которые выполняются медленно, то и результаты будут иными.
Ответили: (4)
С результатами согласен
| Код |
|---|
Функция ТочноеВремя()
Script = Новый COMОбъект("MSScriptControl.ScriptControl");
Script.Language = "javascript";
Возврат Script.eval("new Date().getTime()");
КонецФункции
Процедура КнопкаСформироватьНажатие(Кнопка)
Старт = ТочноеВремя();
А = 0;
Для Сч = 1 По 1000000 Цикл
А = А + 1;
КонецЦикла;
Сообщить("В несколько строк:" + (ТочноеВремя() - Старт) + " мск");
Старт = ТочноеВремя();
А = 0;Для Сч = 1 По 1000000 Цикл А = А + 1;КонецЦикла;
Сообщить("В одну строку:" + (ТочноеВремя() - Старт) + " мск");
КонецПроцедуры |
Результат(вне отладки):
В несколько строк:1 531 мск
В одну строку:1 078 мск
Но я бы объяснил это не лишними повторениями или переходами между командами, а наличием возможных точек останова и возможностью указания строки ошибки.
Ответили: (15)
(12)(15) Да, убедил. Это действительно сказываются дополнительные коды (1) в компилированном коде, которые означают номер строки для отладки. В 1С, в отличие от нормальных сред программирования (типа Visual Studio или Embarcadero RAD) нет разделения на режимы компиляции Debug и Release. В 1С, по сути, всегда режим Debug. Ради интереса я перенес тест из формы в модуль обработки, поставил на нее пароль, и обфусцировал ее. Обфускация, кроме всего прочего, выкидывает отладочные коды (1). И результаты сразу стали одинаковыми! Правда, чуть больше, чем не для обфусцированных - вместо 1 сек для 1 строки и 1,4 сек для 6 строк стало по 2 сек. для обоих вариантов, что вполне объяснимо - обфускация добавляет лишние переходы и прочие запутывающие коды.
Но, по большому счету, и раньше было известно, что 1С для всяких сильно вычислительных и переборных задач совсем не подходит. В реальной же жизни, как правило, скорость работы 1С упирается в скорость работы с БД, и на этом фоне оптимизация просто кода 1С приносит практически незаметные результаты.
Ответили: (17)
(18) На самом деле 1С и компилятор и интерпретатор одновременно. Исходный код компилируется в промежуточный "п-код" либо в момент первого обращения к модулю, если исходный текст модуля открыт, либо заранее, если исходный текст модуля запаролен или исходный текст модуля отсутствует. Далее полученный "п-код" выполняется виртуальной машиной 1С в режиме интерпретатора.
Правда, не знаю, как выполняется клиентский код в тонком и веб-клиентах 8.2.
(17) Ну давай посчитаем. В твоем тесте цикл выполняется миллион раз, в варианте шести строк внутри цикла 4 строки, т.е. за время выполнения теста происходит обработка отладочного кода (1) четыре миллиона раз. Именно этих четырех миллионов вызвовов команды (1) нет в варианте с одной строкой. Уходит на это примерно пол-секунды (на моем рабочем компе разница между тестами 0.4 секунды). В обычной жизни для вывода пользователю результатов запроса из БД надо выполнить не более нескольких тысяч строк (с учетом всех циклов), что на три порядка меньше, чем в тесте. Т.е. способом "пишем всю программу в одну строку" ты будешь ловить миллисекунды.
Я отнюдь не отрицаю, что эффект есть, я просто говорю, что, как правило, он совсем не стоит внимания. Возможно, в исключительных случаях, и бывает, что таким способом можно получить хоть немного заметную экономию времени. Но скорее всего, это тяжелые алгоритмические или переборные задачи, которые, в таком уж случае, гораздо эффективнее писать на других, компилируемых, языках. С++, например. Выигрыш по времени выполнения чисто алгоритмической программы на С++ по сравнению с 1С может достигать нескольких тысяч раз.
Ответили: (24)
2(13): вот и я о том подумал, на самом деле, одна строка или 6 строк, машине (компилятору) по барабану, для нее на вход поступает линейный поток символов (включая управляющие символы). И какая тут разница, сколько строк или пробелов? Это разве что, время разбора лексем увеличивается за счет работы со строками, типа, чем больше пробелов и прочих не значащих символов, тем больше время разбора, но что бы в два раза!!!
Кстати, в приведенном коде разбора строки с элементами в массив, есть ошибка, а точнее ограничение. Если в элементах разбираемой строки встречается двойная кавычка, то приведенный код упадет. Поэтому перед преобразованием надо добавить
| Код |
|---|
РазбираемаяСтрока = СтрЗаменить(РазбираемаяСтрока, """", """"""); |
Ответили: (27)
Иногда встречал простые задачи, которые нельзя ни перенести на сервер, ни реализовать на запросах - все делалось на клиенте.
Вот мои замеры (10 млн итераций):
Замер код записан в 6 строк. Завершено за 25,652 сек.
Замер код записан в 1 строку. Завершено за 14,771 сек.
11 секунд выигрыша в моем случае - большой плюс.
Предложенный способ оптимизации действительно отношу к особенностям компилятора/интерпритатора, а не к оптимизации кода в полном смысле этого слова.
Но все равно плюс автору за статью.
(25) Ни каких ограничений нет. См. пост (25) - там смимаются все ограничения.
А если серьезно, то у меня такой способ разбора строк встречается часто. Взял из модуля, где разбираются строки вида ЭлементыФормы.КоманднаяПанель.Кнопки.Подменю.Кнопки.Действие.Подсказка
Главное ведь сам прицип. Если принцип понятен, то модифицировать команду под разбор, например, строки чисел уже не составит труда.
(Подсказка: S заменить на N и убрать некоторые кавычки)
1. Почему для построения двухуровневого дерева нельзя обойтись только первой частью запроса ?
2. Зачем в одной колонке нужно иметь разные типы ?
3. Не понял текста запроса после "Объединить Все" .
- Второй запрос будет пустым . зачем это нужно ?
4.
"ИТОГИ
| Организация КАК СтруктураДоговоров,
| СУММА(Сумма)
|ПО
| Организация");"
- После опции ИТОГИ употреблена не агрегатная функция , а "Организация" .
Что это ?
(29) Вот пока выложил только скриншот "Пример 3". Как думаешь, это будет интересно?
В двух словах - там по периодическому регистру сведений КурсыВалют вычисляются периоды действия курсов и ещё ряд показателей, при этом исключаются записи в которых курс установлен такой же как в предыдущей записи.
Ответили: (34)
(35) Изменение задолженности? Разве типовые отчеты этого не показывают? Хотя остатки в разрезе документов можно таким образом развернуть.
Нет. Я имел ввиду несколько иное представление именно периодических регистров сведений: КурсыВалют, ЦеныНоменклатуры и т.д. Где это может использоваться? Например, здесь
Для ,в целом симпатичного, примера 3 нужно указать , что в случае большой таблицы регистра КурсыВалют (более 1000 записей), мы получим серьезное замедление.
Дело , конечно, в том , что при соединении по неравенству в первом запросе размер "промежуточной" таблицы запроса резко возрастает.
Например , получение первой временной таблицы Периоды при помощи кодинга может дать многократный выигрыш по быстродействию .
(38) По оптимизации выборки в нарастающих итогах могу дать ссылочку
Здесь фишка в другом - убрать повторяющиеся данные из цепочки, а оставить только точки перехода с датами, когда данный переход был выполнен.
Т.е. для цепочки 0, 0, 1, 1, 1, 0, 0, 0, 1
должны остаться только 0, 1, 0, 1
Ответили: (70)
(38) ... неужели ... не ужели ... НЕужели ... неУЖЕЛИ ... вотВЕДЬвот ...
Ответили: (42)
Второй в пакете запрос я еще не осилил - до твоей "фишки" не дошел.
Отметив возможное замедление , продолжим "ковырять" первый запрос пакета.
В нем фильтрация по &Валюта применена дважды , причем один раз в условии соединения. На мой взгляд , эффективнее и понятнее будет следующий запрос для получения временной таблицы "Соединения"
Выбрать РАЗРЕШЕННЫЕ КурсыВалют.Период
Поместить Периоды
из Регистр.КурсыВалют
Где КурсыВалют.Валюта=&Валюта;
ВЫБРАТЬ
Периоды.Период как Период1,
Максимум (ЕСТЬNULL(Периоды1.Период, Периоды.Период)) КАК Период2
Поместить Соединения
Из
Периоды КАК Периоды
Левое Соединение Периоды КАК Периоды1
Периоды.Период > Периоды1.Период
Сгруппировать по
Периоды.Период
Посмотрел второй запрос.
Пример 3 хорош лишь как любопытная демонстрация запросной техники , но ни в коем случае не образец решения задачи. Лучше бы явно это указать в теме.
Действительно , выгрузив таблицу регистра в таблицу значений мы за ОДИН проход получим выходное дерево многократно быстрее.
Ответили: (45)
| Цитата |
|---|
| - Как-то не очень получается...
- Конечно можно и получше нарисовать. Ну, там в трехмерной проекции... - А я бы нарисовал немного в профиль - Да потому, что у вас всё в профиль © Миссия Клеопатра |
Добавил вариант с оптимизацией. Работает немного побыстрее, но понять, что делается в двенадцати пакетном запросе мне кажется сложнее.
Хм.. А как у тебя тема обновляется ?
Скромно поинтересуюсь : а можно посмотреть пример 3 - оба варианта до оптимизации и после.
Первый запрос не изменился. Во втором поля выборки, два внутренних соединения, Итоги - как были так и остались.
Ответили: (50)
(54) по поводу апдейта для решения проблем с нарастающими итогами говорено давно... Иначе оптимизированный запрос с соединением по неравенству занимает много страниц... Некоторые "гуру" даже разбираться не хотят (:
На самом такими темпами нужно ждать 1с 8.5 или 9.0, где будет реализована возможность редактирвания ВРЕМЕННЫХ таблиц и что-то типа UPDATE.
(57) там можно в меньше, чем 15 строчек уложиться...вопрос только в производительности... А производительсноть повышается 3 способами:
1. Наращивание железа
2. Оптимизация рутинных операций путем переписывания на assemblere (или другом языке)
3. Написанием сложного и длинного алгоритма, возможно с применением математических моделей.
(61) Проверялась в субботу действительно на файловом варианте.
На небольших объёмах проверять бессмысленно.
Создай 1 000 - 10 000 различных курсов по одной валюте и сравни результаты.
выигрыш в быстродействии должен быть никак не меньше 1.5 раза.
На мой вкус, "Гостинец" в первой строке выдает как раз правильный результат :
"Изменение курса" в первой строке не имеет смысла , т.к. пред.курс неизвестен.
А пока помечтаем и о другой необходимой возможности в языке запросов 1с :
указывать в полях выборки запрос . Разумеется , такая возможность давно реализована в диалектах SQL.
И тогда вместо соединения по неравенству можно следующее, многократно более эффективное :
| Код |
|---|
Выбрать КВ.Период как ТекущийПериод, (Выбрать Первые 1 КВвнутр.Период из РегистрСведений.КурсыВалют как КВвнутр ГДЕ КВвнутр.Период<КВ.Период Упорядочить ПО КВвнутр.Период Убыв) как ПредыдущийПериод ИЗ РегистрСведений.КурсыВалют как КВ |
Ответили: (71)
| Цитата |
|---|
| Разумеется , такая возможность давно реализована в диалектах SQL. |
Разумеется.
И в 1С++ тоже.
Все чаще ловлю себя на мысли, что с 1С++ (в связке с FormEx, разумеется) не осталось ничего, о чем стоит помечтать.
Пора, наверное, на восьмерку. Освежить, так сказать, мечтательный раздел мозга.
(60) Загрузил курсы валют за 12 лет. Получил следующие результаты для файловой версии.
Вариант 3. Обычное соединение. Завершено за ~35,5 сек.
Вариант 3. Оптимизированное соединение. Завершено за ~12,5 сек.
Гостинец. Оптимизированное соединение. Завершено за ~12,5 сек.
Починенный Гостинец. Оптимизированное соединение. Завершено за ~12,5 сек.
Разница в производительности очень не значительная
Ответили: (101)
(82) Давай подробнее.
Рассматривается файловый вариант. Исследуются две обработки
"Гостинец.epf"
и "Пример 3_2" , скачанный в текущей теме сегодня в 18-20 мск.
Количество ежедневных курсов (подряд) с 1998 года по сегодняшний день составило в тестовой базе БП 1.6 - 4400 шт.
Замер времени исполнения запроса производился средствами ТВОЕЙ обработки.
Каждая обработка запускалась 3 разF.
Время выполнения Гостинец.epf - ~ 11.7 сек
Время выполнения Пример3_2.epf - ~ 17.7 сек
Выигрыш 1.5 раза.
Кто нас рассудит ? Помогите , люди добрые !
Ответили: (104)
(101) Так. Был немного занят - делал сыну мечи.
Итак дома загрузил курсы в БП 1.6 - 8491 запись в регистре сведений Курсы валют по EUR и USD с 01.01.1999
Время выполнения Гостинец.epf - ~ 12.3 сек
Время выполнения Пример3_2.epf - ~ 12.6 сек
Время выполнения Пример3.epf - ~ 35.5 сек
Не удержался- копнул.
Последний запрос ( чем отличается Пример3_3 от гостинца)- никакой прибавки к быстродействию не даёт.
Львиную долю времени (90%) занимает запрос соединения по неравенству.
Если из первого запроса "Гостинца" убрать строку "Индексировать по Период1,Период2"
то мы и получим быстродействие 1.5 сек.
В свою очередь , если мы добавим строку "Индексировать по Период1,Период2" в твой Пример 3_3 ,то получим те самые 11.7 сек (т.е. запрос из-за этой строки выполнился медленне в 8 раз ).
И честно говоря - это очень и очень странно.
Явное создание необходимого индекса многократно тормозит общий пакет запроса. Получается , что оптимизатор запроса лучше создает тот самый индекс.
(115) В (106) я сразу написал, что убрал все индексы. Да, это "Гостинец", я уже писал об этом, но видимо где-то потерялось. Ещё раз: "Да, это Гостинец", только из первого запроса убрал лишнюю операцию с датами, объединил 6 и 7 пакет и исправил ошибку в первой записи.
Я выложил новые "Пример3" и "Пример3_2". На небольших объемам данных "Пример3" показывает изумительные результаты, а на больших объемах "Пример3_2" держит паритет с "Гостинец".
Про временные таблицы вот что я думаю. Для файловой версии во временных таблицах видимо используется какая-то оптимизация, которая, возможно, использует существующие индексы, которые возможно транслируются во временные таблицы.
В таком случае, принудительная индексация имеет смысл только для таблиц без индексов, например, табличных частей документов или для таблиц значений.
Но это пока только догадки. Нужно тестировать.
Давай уж добьем до конца этот вопрос.
(68) ,(107) Саша и Артур , просьба :
Пожалуйста , протестируйте и сравните на предмет быстродействия:
1. Прикрепленную обработку в (60) Гостинец.epf
2. В текущей теме в разделе "файлы" четвертый файл "пример с оптимизацией" Пример 3_2.epf.
Нужно в БП , а потом в УТ создать ежедневные разные курсы по одной валюте за 12 лет и запустить обработки 1 и 2. Сравнить время выполнения .
Не откажите хорошему человеку. Вы нас рассудите с Алексеем.
P.s. Было бы хорошо - и для файлового варианта и для клиент-серверного.
Ответили: (127)
(124) А не проще прекратить быстродействиями меряться?
Практической пользы - практически ноль. Ну, одна за 17 секунд, другая за 15...
Ну и фигли?
Нажал я кнопочку "Загрузить" и пишу этот коммент (а менеджер по асе девочку охмуряет).
Один фиг загрузит быстрее, чем вышеизложенное
530 [+] [−] Перейти к публикации
И на сколько быстрее? (примерчик)
Ответили: (2) (3) (4) (16) (19) (320)