Оптимизация типовых функций из кода 1с в 1С:Предприятие 8.Х




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2025-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

32 Comments

  1. Душелов

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

    Reply
  2. Evg-Lylyk

    Давайте только опишем какие функции нужно оптимизировать

    Reply
  3. alexk-is

    Нужно было заводить не статью, а группу

    Reply
  4. artbear

    Обновил публикацию.

    По тестированию предполагаю использовать юнит-тестирование в том виде, как выкладывал в ветке по RegExp.

    Reply
  5. Душелов

    (3) Публикацию можно расширить.

    Reply
  6. artbear

    (5) Расширил публикацию.

    Выложил Тест_РазложитьСтрокуВМассивПодстрок.epf

    4 сравнения —

    Выполнений: 1 000 Функции из Бух 1.6 и КОРП 2.0 время: 797 мс

    Выполнений: 1 000 функций на RegExp время: 1 016 мс

    Выполнений: 1 000 функций на VBScript время: 390 мс

    Выполнений: 1 000 Функции ЗначениеИзСтрокиВнутр время: 641 мс

    Reply
  7. alexk-is

    (6) «из Бух 1.6 и КОРП 2.0» — это тоже оптимизированный мною вариант. «Родной вариант» выглядит несколько иначе. Он есть в первоначальном варианте теста из http://www.infostart.ru/public/64222/ Тест прикрепил к сообщению.

    Предлагаю включить его «как есть», т.е. не загонять в 1 строку. Тогда разница в производительности будет очевиднее.

    И еще замечание по замерам в тестах. На полученные результаты тестирования влияют циклы. Что искажает время результатов. Нужно из результатов тестов исключать время на циклы. Тогда останется только время выполнения самих функций. Примеры таких тестов можно посмотреть здесь http://www.infostart.ru/public/19021/

    Reply
  8. alexk-is

    +7 …что-то тест не прикрепился 🙁

    Reply
  9. artbear

    (8) В подфоруме завел новую тему по этой функции

    Reply
  10. artbear

    (8) ОФФ. Я тебе по разукрашке ответил — не очень удобно работать 🙂

    Reply
  11. artbear

    (7) Исправился — исключил время циклов.

    Reply
  12. artbear

    (12) Женя правильно сказал, что ради подобной функции не нужно юзать отдельную компоненту.

    Вполне можно написать простой код на ВБ-скрипт и оформить его в виде отдельной функции 1С или класса 1С.

    Да и сортировка массива ИМХО довольно редкий случай, намного чаще работаешь с сортировкой других коллекций.

    Reply
  13. artbear

    (12) Завел новую подтему «Сортировка массива»

    http://infostart.ru/public/64770/forum/topic/30873/

    Reply
  14. tango

    (13) в УТ нашел два места, где тупым перебором ищется значение в массиве

    Reply
  15. artbear

    Еще кандидаты на оптимизацию из общего модуля «ОбщегоНазначения»

    ТолькоЦифрыВСтроке

    ВыделитьСлово

    ЕстьНеЦифры

    МассивыИдентичны

    УдалитьНеЗаполненныеЭлементыМассива

    УдалитьПовторяющиесяЭлементы

    УдалитьПовторяющиесяЭлементыМассива

    Reply
  16. tango

    только цифры:

    Попытка

    нн = Число(Тестстрока);

    Исключение

    Сообщить(«блин, не только цифры…»);

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

    Reply
  17. IamAlexy

    лучше бы закрытие месяца в типовых БП на SQL базах оптимизировали бы 🙂

    Reply
  18. Valerich

    (18) на этом сайте уже выложено несколько вариантов оптимизаций

    Reply
  19. artbear

    (17) Блок Попытка-КонецПопытки очень медленный как правило.

    Нужно потестить подобное преобразование 🙂

    Reply
  20. lustin

    Артур — тут такое дело

    вот такой тест

    Процедура ПроверитьРазборСтроковогоПараметраScriptЗначенияСКавычкамиВВнутри() Экспорт
    первыйЭлемент = Символ(34)+»я» +Символ(34);
    второйЭлемент = Символ(34)+»тест»+Символ(34);
    результат = ОбщегоНазначенияАльтернативный.РазложитьСтрокуВМассивПодстрок(первыйЭлемент+»=»+второйЭлемент,»=»);
    Я_Тест.ПроверитьРавенство(результат[0],первыйЭлемент);
    Я_Тест.ПроверитьРавенство(результат[1],второйЭлемент);
    КонецПроцедуры

    не пройдет на функции ОбщегоНазначенияАльтернативный.РазложитьСтрокуВМассивПодстрок

    Функция РазложитьСтрокуВМассив(Строка, Разделитель = «,») Экспорт
    Возврат Script2.eval(«Split(«»» + Строка + «»», «»» + Разделитель + «»»)»).Выгрузить();
    КонецФункции
    

    с ошибкой компиляции VBScript из-за недопустимого знака

    сейчас пробую сделать так чтобы тест проходил

    Reply
  21. lustin

    (21)

    блин, а не получается пока с наскока придумать как обойти это финт — туплю наверное 😐

    Reply
  22. artbear

    (21) «Не пройдет» или уже не проходит? ты в реале протестил?

    Reply
  23. lustin

    (23) вечно я недоформулирую

    «Не прошел» имелось ввиду;

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

    Reply
  24. rasswet

    «требуется предварительная инициализация» каким образом?

    Reply
  25. artbear

    (25) До вызова быстрого основного метода РазложитьСтрокуВМассив

    предварительно нужно где-то вызвать метод Инит() — он довольно тормозной 🙁

    Reply
  26. iceflash

    Вообще, мне кажется данная «оптимизация» палка о двух концах. Из одного интерпретатора передавать управление на исполнение кода в другой=)

    Тут наверное стоит подходит со стороны. что можно сделать средствами 1ц, а что средствами сторонних скриптовых движковВК. И на сколько я знаю обмен и взаимодействие по технологии COM достаточно ресурсоемкий (процессор, оперативная память), и данный вывод я делаю не как разработчик на 1ц, а как системный программист, 1ц — это «дуновение потребностей»=) Т.е. например когда действительно нужно применить регулярку, имеет смысл использовать JS регулярку=)

    А вообще конечно хотелось бы увидеть примеры замеров производительности (обязательно раз по 10 как минимум, с средним арифметическим) 😎

    Reply
  27. Serg G

    результаты тестов зависят от многих факторов. Например, большая часть времени уходит на создание обьекта (New RegExp) , на чем часто играют создатели, так сказать, «более быстрых альтернатив». Если же он создан и уже весит в памяти , то отработает, наверняка, быстрее всех. Хотя, Split() — это слишком примитивно.

    Во-вторых, существенно влияет последовательность тестов. Т.е., что вы тестируете первым, то и покажет лучшие СВОИ результаты. Это связанно с оперативной памятью. (Кто-то ранее заметил, что запись в одну переменную — но физически это не так.)

    RegExp — проверенный временем обьект, очень мощный и нужный. Главный минус, что он сторонный/внешний и ОСевой.

    (Могу ошибаться, но в учебных платформах 1C com-обьекты тоже не подключаются. )

    И всё же, при всех плюсах RegExp-a, желательно использовать стандартные наборы функций. Впринципе, это закон любой седы.

    Реализовать такой обьект, как RegEx, в 1с не реально, имхо! Лучше лоббировать его включение и оптимизацию в саму платформу.

    Reply
  28. artbear

    Сейчас, конечно, я уже не найду результатов тестирования, 5 лет все-таки прошло 🙂

    Но проверял на нескольких разных алгоритмах, естественно, на большом количестве выполнений.

    Reply
  29. artbear

    (28) >существенно влияет последовательность тестов

    Не соглашусь.

    Нет такой явной зависимости от последовательности выполнения

    Reply
  30. Serg G

    (30) Ну, я только знакомлюсь с 1с, так что, извините, 2010 для меня тоже самое что и 2020. 🙂

    Имеется ввиду, если тест идет одной процедурой, последовательно.

    Когда-то давно, тестировал ADO vs DAO на создание нескольких десятков и даже сотен тысяч строк в таблице… Впоследствии выяснилось, , последний покажет худший СВОЙ результат, чем будь он первым. Понимаете, даже хранение результатов первого теста в переменной уже уменьшает оперативную память, что приведет к более медленной отработке второго теста.

    Такие «микротесты» (и тут http://infostart.ru/public/64222/) нужно проводить на идеально «вылизанных» машинах: без лишних служб, без сетей, без антивирусов и тп, что может «тормознуть» ОС на мгновение. И то… В общем, если проводить тесты, то уж на максимальных нагрузках.

    >…на большом количестве выполнений.

    Разбейте томик К.Маркса на слова, например, где результаты будут более 5 сек, хотя бы.

    ps: Еще, подозреваю, что скорость wscript и сscript разная и точно зависит от установленных комплексов защиты компьютера и их настройки. Т.е. на разных машинах, результаты могут отличаться.

    А на чем работает 1с при Eval()(Выполнить()) или на дефолте в системе?

    Reply
  31. ZLENKO

    Реализовано в версии 8.3.6.1977 функции: СтрРазделить(), СтрСоединить()

    Читаем тут: https://infostart.ru/public/366865/

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *