Варианты конкатенации строк в 1С и замеры производительности.




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2024-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='\

14 Comments

  1. ildarovich

    Странно, но в статье Опять двойка, на которую автор ссылается, уже приводился предлагаемый здесь метод. Даже код уже был приведен

    Функция ВСтроку(Массив) Экспорт
    Возврат Сред(СтрЗаменить(ЗначениеВСтрокуВнутр(Массив), «»»},» + Символы.ПС + «{«»S»»,»»», «»), 53 + СтрДлина(Формат(Массив.Количество(), «ЧГ=»)), Массив.Количество())
    КонецФункции

    Также в комментарии http://forum.infostart.ru/forum24/topic75023/message908183/#message908183 к той статье приведен еще более быстрый (на 12%) метод за авторством speshuric с использованием объекта ЗаписьXML.

    Reply
  2. Dementor

    (1) ildarovich, все возможно. Но финт со ЗначениеВСтрокуВнутр() я придумал для своей обработки работы с веб-сервисом, которая до этого очень медленно работала. После этого я решил сравнить её быстродействие с «классикой» и способом, который нашел на партнерском форуме. А уже затем я решил поделится с общественностью своей наработкой. Про статью «Опять двойка» узнал в процессе верстки своей, так же как и про другие отдаленно похожие заметки (на других ресурсах). От мысли писать свою статью я не отказывался по причинам: она оригинальная, не повторяет чужих идей, приведены конкретные цифры замеров производительности в то время, когда другие лишь мимолетом упоминали про свои субъективные ощущения.

    Раз существует более «навороченный» вариант с ЗаписьXML, то конечно стоит его рассмотреть и добавить в табличку сравнения быстродействия. Я думал и про этот объект, но не знал про его любопытный метод ЗаписатьБезОбработки() и потому не стал рассматривать. А вот от использования указанной в комменте реализации составления строки из массива я бы рекомендовал воздержаться — в ней есть баг, который я у себя дополнительно обошел (хотя в некоторых случаях искажение содержимого роли не играет и потому некоторым может подойти).

    Reply
  3. Dementor

    (1) ildarovich, про 12% — полное вранье. Добавил в обработку тестирование ЗаписиXML — результаты сопоставимы с методом массива почти на 99%!!! Так на формирование строки из 50000 подстрок методом массива уходит 1466 милисекунда, а с помощью ЗаписиXML — 1474. При работе со 100000 подстрок результаты — 2906 и 2985. Единственное преимущество — элегантность кода и отсутствие шаманства.

    Reply
  4. Dementor

    Статья и обработка обновлены четвертым способом конкатенирования строк.

    Reply
  5. infostart user
  6. Улугбек

    Как говорится — в 8-ке это реализовано:

    http://v8.1c.ru/o7/201408str/index.htm

    Функция форматирования СтрШаблон()

    Функция работы со строками СтрСравнить()

    Функции работы со строками СтрНачинаетсяС(), СтрЗаканчиваетсяНа()

    Функции работы со строками СтрРазделить(), СтрСоединить()

    Функция работы со строками СтрНайти()

    Reply
  7. Dementor

    (5) infostart user, это не способ, а всего лишь анонс будущей функциональности. Как показывает практика, самый короткий промежуток между заметкой в зазеркалье и получением тестовой сборки платформы равен полугоду. Скорее всего добавят в 8.3.6

    Reply
  8. Улугбек

    Вот оно, значит, как.

    Reply
  9. Dementor

    (7) Улугбек, а на заборе написано, что Цой жив. И еще много чего тоже написано…

    А попробуйте зайти в конфигуратор и воспользоваться этими функциями!

    Подсказка: в ЗАЗЕРКАЛЬЕ пишут разработчики платформы о новых фичах, которые они у себя разрабатывают. Это не место для официальных пресс-релизов, а всего лишь блог. После разработки пройдет еще цикл тестирования и по результатам примут решение, когда переносить их в рабочие сборки.

    Reply
  10. CheBurator
    После разработки пройдет еще цикл тестирования и по результатам примут решение, когда переносить их в рабочие сборки.

    вау, там у них есть тестирование? мы перестанем чувстовать себя подопытными кроликами? наконец-то!

    Reply
  11. Dementor

    (10) CheBurator, разве можно быть настолько доверчивым?

    Людям свойственно ошибаться, даже при тестировании на наличие ошибок 🙂

    Reply
  12. with

    ИМХО

    1) 1С генерирует не исполняемый код, в всего лишь строит объектную модель, которая потом исполняется в виртуальной машине.

    2) Такие типы интерпретаторов не предназначены для большого количества вычислений, которые требуют скорости работы. Написанный код на 1С всегда уступит по скорости реализации на с++. Это надо понимать, и не ждать чудес.

    Ну и последнее, приведенные примеры работают быстрее, потому что там строки создаются и обрабатываются на уровне одного объекта, написанного на с++ и 1С там только дергает системные ф-ции.

    Reply
  13. SlavaKron

    (1) Следует исправить на:

    Сред(СтрЗаменить(ЗначениеВСтрокуВнутр(Массив), «»»},» + Символы.ПС + «{«»S»»,»»», «»), 53 + СтрДлина(Формат(Массив.Количество(), «ЧГ=»)))

    Вы из строки берете количество символов, равное количеству элементов массива.

    Reply
  14. Lapitskiy

    (1) ЗначениеВСтрокуВнутр — ошибочно излишне обрезает строку справа, в некоторых вариантах тестов.

    Видимо вместо Массив.Количество() — надо что-то другое.. Разбираться не было времени, решил использовать ЗаписьXML.

    Reply

Leave a Comment

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