Разгон РАУЗ в 1С УПП 1.3 (платформа 8.2)




Принцип обмена данными из 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='\

55 Comments

  1. ojiojiowka

    К сожалению, УПП нет под рукой, поэтому задам пару вопросов. Вторая часть статьи годная, единственное, могут возникнуть проблемы, если в этот момент меняются данные (хоть это и редко случается). Я бы запихнул это в параметры сеанса и обновлял бы их при изменении. По первой части:

    1) Разве эффект не был бы таким же, если у физического лица включить индексирование? Меня просто не очень прельщает кардинальная переделка порядка измерений. Здесь помогло, в другом случае может навредить. Надо полностью оценить все основные операции над этим регистром.

    2) Не будет ли являться избыточным для первого измерения (физического лица) ещё и установка свойства индексировать? Почитайте про структуру индексов 1С. Нужный индекс уже будет, зачем создавать избыточный с периодом между физ лицом и остальными измерениями?

    Reply
  2. DNSokol

    (1) ojiojiowka,

    Отвечу по порядку:

    Про изменение данных. Да, данные меняются, но, не просто так по коду ползал. Функция ЗаполненыНастройкиАналитикиУчета() делает выборку практически из статичного справочника, которые меняется не чаще чем почти никогда. Это же касается и функции ШаблонИзмеренийКлючаАналитики(). Самый большой вопрос был по функции ПолучитьКлючАналитики(). Тут возможны изменения, в т.ч. и при расчете себестоимости. Поэтому, если вызов данной функции вернул пустой результат, отрабатывает уже типовое создание ключа аналитики, после чего вызывается стандартная функция ОбновитьПовторноИспользуемыеЗначения(). Единственное, чем плох этот алгоритм, так это тем, что ОбновитьПовторноИспользуемыеЗначения() сбрасывает кэш не конкретной функции, для которой включено повторное использование значений, а весь кэш. Тем не менее, т.к. вызовы сброса сильно не частые (у меня в расчете себестоимости сбрасывается кэш 3-4 раза, то использование повторно возвращаемых значений дает очень положительный эффект на быстродействие.

    Про эффект. Нет, не был бы. Подробно вспоминать (ибо уже давно не кодер) как работают механизмы 1С просто времени не было. К сожалению. Просто есть факт того, что если измерение сделать первым по списку, то получил прирост скорости работы. Если к этому включить индексирование (в конфигураторе), то прирост будет еще более существенный. Если просто включить индексирование, то прирост будет не такой, как с перемещением измерений.

    Про «Надо полностью оценить все основные операции». Это не просто сделать надо, это обязательно надо сделать и в первую же очередь. Я про это в статье и написал. Т.к. если просто переместить измерения и включить индексирование, то можно получить ни прирост в скорости работы, а ухудшение. Например, если в УПП включено использование заказов, и, информации по заказам сильно больше в регистре, чем информации по переданным материалам, то мои изменения приведут к не желательным последствиям.

    Про избыточность индекса. Нет, не будет избыточным. Просто похоже 1С при создании на SQL таблицы для регистра сведений (по крайней мере для независимого) делает кластерный индекс вида «измерение1+измерение2+измерение3», а если на измерение повесить галку «индексировать», то будет сделан дополнительно еще один индекс по тем полям, для которых галки «индексировать» установлены. Именно по этой причине злоупотреблять галочками «индексировать» нельзя, т.к. если, например, измерений будет более чем много, то хаотичная расстановка галочек приведет к тормозам при записи (много индексов будет) и отсутствию прироста скорости при чтении (всё равно запросы не будут попадать в индексы и будут сканы таблиц на SQL).

    В общем и целом как-то так.

    Reply
  3. AlX0id

    (2) DNSokol,

    Про избыточность индекса. Нет, не будет избыточным. Просто похоже 1С при создании на SQL таблицы для регистра сведений (по крайней мере для независимого) делает кластерный индекс вида «измерение1+измерение2+измерение3», а если на измерение повесить галку «индексировать», то будет сделан дополнительно еще один индекс по тем полям, для которых галки «индексировать» установлены.

    Ну и в чем тогда дополнительная польза от индекса «Измерение1» при наличии индекса «измерение1+измерение2+измерение3»?

    Reply
  4. DNSokol

    (3) AlX0id,

    Выгода в скорости. Если у меня запрос только по ФЛ, то SQL выберет индекс по ФЛ, который более оптимален, чем кластерный индекс => запрос отработает быстрее.

    Reply
  5. qwinter

    (3) AlX0id, для данного регистра разницы между между просто врубить индексирования, и переместить и врубить в быстродействии не будет.

    А вообще выборка по первому индексу всегда эффективней, чем по второму, третьему и т.д. Поэтому перемещение относительно других индексированных элементов действительно дает эффект. Но так как данный регистр не подчинен регистратору и не имеет реквизитов с свойством «Индексировать» то у него нет таблиц индексов. И поставив «Индексировать» у физического лица вы создадите единственный индекс. И не важно, какой будет порядок у реквизитов.

    Reply
  6. AlX0id

    (5) qwinter,

    Непериодический регистр сведений

    Индекс

    Условие и описание

    Измерение1 + [Измерение2 +…]

    Есть хоть одно измерение регистра.

    Индекс, включающий все измерения в том порядке, в котором они заданы при конфигурировании.

    ИзмерениеN + Измерение1 + [Измерение2 +…]

    Измерению «ИзмерениеN» задано свойство «Индексировать» или свойство «Ведущее» и при этом это не первое и не единственное измерение.

    Индекс, включающий все измерения. Первое поле — ИзмерениеN, затем все остальные измерения в том порядке, в котором они заданы при конфигурировании.

    В частности:

    Таблица: РегистрСведений.АналитикаУчетаПартий, Имя таблицы хранения: InfoRg19844, Назначение: Основная

    — поля:

    СтатусПартии (Fld19845)

    Заказ (Fld19846)

    ДоговорКомитента (Fld19847)

    Комиссионер (Fld19848)

    ДоговорКомиссионера (Fld19849)

    ДокументПередачи (Fld19850)

    ФизЛицо (Fld19851)

    НазначениеИспользования (Fld19852)

    Ссылка (Fld19853)

    (SimpleKey)

    — индексы:

    ByDims

    СтатусПартии + Заказ + ДоговорКомитента + Комиссионер + ДоговорКомиссионера + ДокументПередачи + ФизЛицо + НазначениеИспользования (Fld19845 + Fld19846 + Fld19847 + Fld19848 + Fld19849 + Fld19850 + Fld19851 + Fld19852)

    ByResource19854

    Ссылка + СтатусПартии + Заказ + ДоговорКомитента + Комиссионер + ДоговорКомиссионера + ДокументПередачи + ФизЛицо + НазначениеИспользования (Fld19853 + Fld19845 + Fld19846 + Fld19847 + Fld19848 + Fld19849 + Fld19850 + Fld19851 + Fld19852)

    BySimpleKey

    SimpleKey (SimpleKey)

    Показать

    Reply
  7. AlX0id

    (4) DNSokol,

    В чем заключается его оптимальность по отношению к кластерному индексу можете сказать?

    ЗЫ. А по поводу ЗаполненыНастройкиАналитикиУчета() — запустил у себя расчет себестоимости — вызывается ровно 8 раз.. Видимо, сильно зависит от настроек учета..

    Reply
  8. PiccaHut001

    Автор, спасибо. Ускорили РАУЗ в 30!!! раз. Видно, писателям типовой УПП было недосуг заморачиваться просмотром своего овнокода шедеврального творения. Работает на 10 документах, и ладно. А потом эти удакисертифицированные преподаватели запрещают нам писать запросы в цикле(даже если цикл из 2 итераций).

    Reply
  9. DNSokol

    (5) qwinter,

    Создает, но немного не так, как я описал. Тут ошибочка. Когда смотрел на SQL базу, то посмотрел на регистр, в котором несколько измерений индексировалось.

    Reply
  10. DNSokol

    (6) qwinter,

    Ну, тут нет времени подробно разбираться. Тут просто констатирую факт, что разница есть, и, она видна. Если просто порядок измерений поменять, то выборка быстрее производится. Если включить индексирование, то создается на SQL еще один индекс (к тому, что уже имеется «по умолчанию»). Так что порядок имеет значение.

    Reply
  11. DNSokol

    (8) AlX0id,

    это уже в книжки по СУБД. Сорри.

    Reply
  12. AlX0id

    (12) DNSokol,

    Ну и на том, спасибо, что отправили )) Если на пальцах, то:

    Кластерный индекс — это сама таблица. А вот некластерный индекс в вашем случае — это только ключ из одного столбца.

    Если в таблице несколько столбцов, а в некластерном индексе ключ из одного, то и занимать таблица будет больше страниц, чем некластерный индекс, соответственно, чтобы просканировать некластерный индекс надо меньше прочитать экстентов серверу. Отсюда и выигрыш.

    Reply
  13. unoDosTres

    ну идея понятна, вот только функцию

    ПолучитьКлючАналитики

    найти не удалось, я так понимаю все три перечисленные функции вызывались из ОбщегоМодуля «РасширеннаяАналитикаУчета», правда Релиз конфы посвежей, думаю попробовать хотя бы на вызове двух функций проверить с изменением порядка измерений в регистре АналитикаУчетаПартий

    Reply
  14. kapustinag

    (8) AlX0id, Оптимальность/Неоптимальность индекса по одному измерению по сравнению с кластерным индексом — вещь относительная, то есть в разных условиях эксплуатации БД и при разных характеристиках таблицы преимущество может быть то у одного индекса, то у другого.

    С одной стороны, кластерный индекс физически в файле базы данных размещается таким образом, чтобы получить выигрыш при чтении данных — то есть узлы кластерного индекса располагаются рядом со строками самой таблицы. Это — в плюс кластерному индексу.

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

    Но — еще раз повторюсь — эти плюсы и минусы могут пересиливать друг друга на разных запросах, разной наполненности таблиц, разной степени фрагментированности БД, разной разбивке БД на файлы…

    Reply
  15. DNSokol
    Reply
  16. DNSokol

    (15) kapustinag,

    именно так! Помимо этого есть еще множество нюансов, влияющих на конечный результат. Просто в первой части статьи хотел показать сам принцип, что прежде чем лезть в SQL и что-то там докручивать, можно внести небольшие изменения в порядок следования измерений и индексирование. Если делать всё вдумчиво, а не просто «индексы ускоряют, значит сейчас везде понатыкаю галок <индексировать>» то можно получить достаточно существенный прирост производительности.

    Reply
  17. Константин С.

    тогда уж опиши эту процедуру)

    «ШаблонИзмеренийКлючаАналитики»

    Reply
  18. DNSokol

    (18) Константин С.,

    )))) Да я хотел измененные модули приложить, а они только при включенных «поборах» прикладываются 🙂 Изменил статью. В коней статьи добавил код, который менялся.

    Reply
  19. AlX0id

    (15) kapustinag,

    Ну вот поэтому-то я и задал вопрос автору, почему он в данном случае считает более оптимальным именно некластерный индекс.

    Но чем больше я в это вдаюсь, тем все «страньше и страньше».

    Во-первых, некластерный индекс, создаваемый 1С, не так уж и сильно отличается по длине от кластерного в случае того же регистра АналитикаУчетаПартий — так как включает в себя все измерения регистра. То есть, короче ровно на один ресурс.

    Во-вторых, по результатам замера производительности расчет себестоимости делает в основном не запросы по Физлицу, как можно предположить из статьи (но довольно странно с точки зрения логики РАУЗ), а по ресурсам регистров аналитики (которые как раз-таки индексированы в типовой).

    Вот со второй частью повествования я могу согласиться, хотя у меня данная ситуация и не повторяется. А вот с первой — что-то слишком натянуто. Непонятно, откуда взята мысль, что надо индексировать именно это измерение.

    ЗЫ. Начал ковыряться в структуре индексов — вообще наткнулся на такую картину:

    Регистр аналитики до реструктуризации

    И такие индексы по всем регистрам сведений. То есть НЕкластерные.

    А вот если изменить структуру регистра в 1С — тут же появляется кластерный индекс..

    Reply
  20. DNSokol

    (20) AlX0id,

    Как бы это по мягше то сказать то…. В общем, я писал уже, что не плохо бы книжки почитать.

    Например, про кластерные индексы можно тут узнать. Там же можно узнать почему кластерный индекс на таблицу может быть только один, а не много. И изучив то, как MS SQL строит кластерный индекс можно понять, почему порядок измерений влияет на скорость выборок, при том, существенно.

    Про физлицо. Узнать почему нужно индексировать в моем случае именно это измерение — можно из статьи. Там явно это написано. Там же написано, что нужно сделать перед тем, как принять решение о том, что физлицо нужно переместить «вверх» списка измерений.

    В остальном вам помогут или ЖКК или изучение того, как РАУЗ работает, а конкретно, как строятся выборки по аналитикам и почему в конкретно моем примере перемещение физлица дало прирост в скорости.

    Приношу извинения, но просто заниматься преподаванием основ СУБД нет времени.

    Reply
  21. asved.ru

    Что касается дополнительного индекса по первому полю кластерного индекса — очень странна Ваша мысль. Регистр-то непериодический, независимый, поэтому поле действительно идет первым в кластерном индексе.

    Размер дополнительного индекса возможно, будет немного меньше (а возможно — и нет, тут смотреть надо, не задублировалось ли в нем первое поле), но потом все равно придется делать key_lookup, так что далеко не факт, что СУБД выберет именно такой путь. Это возможно при высочайшей селективности, отсутствии требуемых страниц в буфере и нагруженности I/O.

    Если бы Вы не ограничивались описанием работы исключительно на уровне 1С, а привели план запроса, а заодно и latches по нему для случаев с дополнительным индексом и без него, ваши мысли были бы яснее.

    В общих чертах можно сказать, что порядок измерений регистра сведений действительно влияет только на эффективность исполнения запроса по нему. Так что подход с изменением структуры верен при условии, что нет других существенных обращений, которым изменение этого порядка помешает. Есть еще возможность создания специализированного индекса средствами СУБД, хоть это и есть нарушение лицензионного соглашения, и официально я рекомендовать такое не могу.

    Хотелось бы, конечно, чтобы платформа позволяла построение произвольных индексов.

    Reply
  22. AlX0id

    (21) DNSokol,

    А где вы увидели в моем сообщении, что я ищу несколько кластерных индексов по таблице? В картинке в явном виде показано, что до реструктуризации нет КЛАСТЕРНОГО индекса в принципе, а после, как сказано в сообщении — есть.

    Если бы Вы не ограничивались описанием работы исключительно на уровне 1С, а привели план запроса, а заодно и latches по нему для случаев с дополнительным индексом и без него, ваши мысли были бы яснее.

    Вот чего я ожидал увидеть в статье, а не некое эмпирически подобранное решение.

    В остальном вам помогут или ЖКК или изучение того, как РАУЗ работает, а конкретно, как строятся выборки по аналитикам и почему в конкретно моем примере перемещение физлица дало прирост в скорости.

    Ну так приведите же хоть один запрос из расчета себестоимости, где этот индекс дает прирост производительности, и половина вопросов отпадет.

    Reply
  23. DNSokol

    (22) asved.ru,

    Я же в преамбуле к статье написал, что тут приведена рекомендация по тому, как можно повысить производительность. И там же написал, что некоторые вещи просто принимаются на веру. У меня при написании материала не было задачи доказать, что то, что принято за аксиому, аксиомой и является. Более того, у меня так же не было задачи блестать знаниями профайлера и кому-то что-либо доказывать.

    Еще раз — основная задача материала — дать небольшую базу о том, используя какие основы и какие подходы можно существенно поднять производительность, а не загрузить читателя потоком сознания. И судя по комментариям, некоторым статься помогла. Т.е. цель материала достигнута.

    Именно поэтому, все описание ограничено средствами 1С и тем, как средствами 1С модно улучшить работу. И именно поэтому тут нет дополнительной «технической доказательной базы». Если есть пытливые умы, которые хотят посидеть под профайлером и почитать книжки — я не против и ни в коей мере не ограничиваю. Берите профайлер и вперед. Можете свою статью написать, где будет большая доказательная база с планами выполнения запросов и т.д.

    Сейчас имеем следующее — цель статьи достигнута. На этом большая и жирная точка. Если у меня будет другая цель, напишу по другому.

    Reply
  24. DNSokol

    (23) AlX0id,

    в школу. Учится. Цели проводить обучение у меня не стоит. Ровно как и не стоит цели рассказывать основы СУБД. Про планы запроса — читаем очень внимательно и вдумчиво преамбулу к статье. Там кратко описано содержание статьи. Нужен профайлер и полный технический анализ — берите в руки инструменты и вперед. Напишите тут свой доклад на тему улучшения производительности с техническим обоснованием. У меня задачи загрузить потоком сознания и показать какой я крутой СУБДист — не было.

    Reply
  25. AlX0id

    (25) DNSokol,

    Мдэ? То-то я смотрю, вы, как «крутой СУБДист» меня в школу «учится» отправляете ))

    Хорошо, не буду задавать вам вопросов, которые вам неудобны.

    Reply
  26. AlexBar

    Мне не совсем понятно в чем выигрыш при получении шаблона через новый модуль? При входе в функцию «ШаблонИзмеренийКлючаАналитики» передается параметр «СтруктураКлючиАналитики» которая и содержит «кешированные» шаблоны. Запрос к СУБД производится только в том случае, если в этой структуре шаблон не найден. Смотрите строку

    Если СтруктураКлючиАналитики = Неопределено
    ИЛИ Не СтруктураКлючиАналитики.Свойство(ИмяСтруктурыИзмерений, ШаблонИзмерений) Тогда

    Т.е. к СУБД обращение производится только один раз для каждого из регистров «УчетЗатрат» («УчетЗатратРегл»). Вы анализировали сколько раз при вызове данной функции выполняется запрос?

    То же самое касается и «ПолучитьСоздатьКлючАналитики». Для каждого ключа аналитики действие производится только один раз, после получения ключа он помещается в таблицу и в следующий раз считывается уже оттуда:

        // Попробуем получить ключ аналитики из кэша.
    Если СтруктураКлючиАналитики <> Неопределено Тогда
    ЭлементКлючАналитики = ПолучитьКлючАналитикиИзТаблицы(
    СтруктураИзмерений,
    ИмяРегистра,
    СтруктураКлючиАналитики
    );
    КонецЕсли;
    
    Если Не ЗначениеЗаполнено(ЭлементКлючАналитики) Тогда

    Показать

    Т.е. обращение к СУБД и запись в СУБД ключа производится производится только один раз для каждого набора аналитики.

    Вы анализировали эту ситуацию прежде чем оптимизировать данные участки кода?

    Reply
  27. DNSokol

    (27) AlexBar,

    Я тоже сначала так думал. Но, расстроило меня то, что СУБД даки постоянно читалась. Поэтому, выигрыш в том, что мы не лезем каждый раз в базу.

    Так вот, если уж разбираться подробно, то если смотреть вызовы функции ШаблонИзмеренийКлючаАналитики в модуле расширенной аналитики, то видно приблизительно следующее:

    Запрос.Текст = «ВЫБРАТЬ»;
    СтруктураИзмерений = Новый Структура();
    МассивИзмерений = Новый Массив();
    ШаблонИзмерений = ШаблонИзмеренийКлючаАналитики(КлючАналитики.Ключ, Неопределено);
    
    

    т.е. вместо «кэша» всегда и во всех вызовах передается «неопределено». Итого у нас получается 2 варианта: использовать повторное использование значений или городить огород с реализацией кэша. Я выбрал второй вариант, т.к. изменения типовых модулей минимальны, а это значит, что обновлять их будет проще, в случае надобности. Собственно, это еще и ответ на вопрос про анализ 🙂 естественно анализировал, и, естественно смотрел что в функцию передаётся.

    И да, то же самое касается и «ПолучитьСоздатьКлючАналитики». Эта функция вызывается в единственном месте в функции «ПолучитьЗначениеКлючаАналитики». В данную функцию передается тот самый «кэш» последним параметром, и… и он во всех вызовах использует или «неопределено» или туда передается пустая структура, как, например в процедуре «ПолучитьАналитикуРаспределенияЗатратНаВыпуск», которая вызывается из «ВыполнитьРаспределениеСтрокиРасходовНаВыпуск» которая вызывается из «ВыполнитьРаспределениеРасходов» в которой вот это перед вызовом:

    СтруктураКлючиАналитики = Новый Структура
    

    поэтому в этом «кэше» всегда пусто. Поэтому чтение СУБД происходит при каждом новом вызове. Можно было всё эту вереницу вызовов размотать, докопаться до того, как заставить всё это работать с кэшем, а можно было просто сделать повторное использование.

    У меня есть предположения, почему кэш перестали использовать, но, это только предположения.

    Reply
  28. AlexBar

    Вероятно мы с Вами смотрим разные куски кода указанного модуля.

    Приведенный Вами код имеет отношение только к процедурам тестирования и проверки ключей аналитики: «ОбновитьНаименованияКлючейАналитики» и «ПроверитьСсылочнуюЦелостностьКлючейАналитики». Пожалуй это мы обсуждать не будем, так как к нашей теме отношения не имеет.

    В функции же, которая возвращает значение ключа аналитики («ПолучитьЗначениеКлючаАналитики») используется иной код:

     ШаблонИзмерений = ШаблонИзмеренийКлючаАналитики(
    ИмяРегистра,
    СтруктураКлючиАналитики
    );

    Именно эта функция и используется во всех механизмах расчетов и формирования движений РАУЗ.

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

    Reply
  29. DNSokol
    Reply
  30. asved.ru

    (24) DNSokol, т.е. Вы вводите людей в заблуждение на предмет дополнительной индексации первого поля кластерного индекса — и считаете, что цель статьи достигнута?

    Reply
  31. DNSokol

    (31) asved.ru,

    Напишите свою статью. без «заблуждений». Это первое. Второе — я не буду объяснять почему индекс по ФЛ будет работать быстрее чем имеющийся кластерный индекс. У меня не стоит цели рассказывать основы MSSQL. И третье — зачастую людям нужно получить эффект, а не пространственные объяснения. Я в преамбуле написал, что для объяснений есть книги. Я не знаю как по другому еще сказать. Перечитайте что ли еще раз то, что жирным выделил.

    Ну и да, четвертое — постройте табличку с 5 полями и кластерным индексом. Сделайте выборку с условием сначала по первому полю, потом по 4. Измерьте скорость выполнения. Изучите план выполнения. Потом на эту же табличку постройте индекс на первое поле, так же сделайте выборку по индексу из первого поля. Скорость измерить так же надобно. А вот потом на основе полученного эксперимента можете написать здесь статью про то, какой нехороший я, вводящий людей в заблуждение, и какой хороший вы. Заодно посмотрим, на сколько эта статья будет популярна и скольким людям ваша статья поможет увеличить скорость расчета себестоимости в 10 и более раз.

    Тема закрыта.

    Reply
  32. pumbaE

    селективность

    Reply
  33. ojiojiowka

    (32) по поводу свойства «индексировать» у поля «ФизическоеЛицо» Вы так и не ответили. После изменения порядка измерений оно так и осталось избыточным…

    Reply
  34. AlexBar

    Дмитрий, относитесь ко всему спокойнее. Вы же видите по комментариям что есть люди которым Ваша статья помогла, а это по моему мнению очень важно! А сколько еще людей прочтет вашу статью и будут Вам благодарны!

    Я, да и другие коллеги, не пытаюсь Вас критиковать, всего лишь пытаюсь понять суть.

    Вот допустим Вы приводите данные что вызов функции «ЗаполненыНастройкиАналитикиУчета» производится более 300 тысяч раз за время проведения одного документа РСВ. Соответственно столько же раз выполняется запрос. В такой ситуации вполне логичное решение от этого избавиться, так как это само по себе не нормально.

    Я запустил замеры времени на своей базе на момент расчета себестоимости. После расчета посмотрел результат: у меня вызов этой функции производится всего 2 раза. При этом аналитики учета у нас доработаны, в ключи введены еще пара измерений. Расчет себестоимости не превышает 10 минут.

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

    Reply
  35. DNSokol

    (35) AlexBar,

    Сорри, просто 1001 дело когда делаешь, заносит иногда. По теме — отвечу позже. У нас в базе объективно много таких вызовов. Распишу всё ближе к ночи.

    Reply
  36. asved.ru

    (32) DNSokol,

    Второе — я не буду объяснять почему индекс по ФЛ будет работать быстрее чем имеющийся кластерный индекс

    Зато я уже объяснил несколькими комментариями выше, почему он НЕ будет работать быстрее.

    Я в преамбуле написал, что для объяснений есть книги

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

    И самое смешное то, что от установки флажка «индексировать» на первом измерении независимого непериодического регистра сведений структура индексов не меняется вообще.

    Reply
  37. DNSokol

    (35) AlexBar,

    про 300 тыс. К сожалению, от этого не избавиться. Точнее, можно избавиться только одним способом — избавившись от РАУЗа как такового. Дело в том, что в самом регистре с аналитиками около 30 тыс. ключей. Это значит ровно одно — будет минимум 30 тыс. обращений минимум. Распределение затрат многоэтапное. Я уже неоднократно проползал весь РАУЗ. Там или глобально все переделывать надо, а это трудозатраты бешенные, или пытаться минимизировать количество обращений к СУБД. Я в общем и целом специально акцент сделал на физлицах и материалах. Если в организации большое количество рабочего персонала и большое количество подразделений, то в аналитикеУчетаПартий сформируется столько уникальных записей, сколько возможно вариантов ФизЛицо+ДокументПередачи+НазначениеИспользования. Т.о. выходит что количество таких комбинаций безгранично. В моем случае пока это 30 тыс. вариантов. РАУЗ пока из все не вычитает, бузет лезть в базу. Далее, 4 этапа распределения этих затрат, но, есть «перезакрытия». Всё это приводит к тому, что типовыми механизмами вычитываться все эти 30 тыс. позиций будут около 10 раз (точнее, количество итераций больше, но, не все 30 тыс. ключей за раз вычитываются).

    В итоге, что мы имеем? А имеем то, что при таком объеме спецодежды и спецоснастки (а такой объем комбинаций именно по этой части учета) нужно или упрощать учет (не реально), или оптимизировать чтения базы. Последний вариант наименее трудозатратный в сило возможности использования повторного использования возвращаемых значений. В этом случае вся эта куча аналитит будет прочитана только один раз за расчет себестоимости.

    Reply
  38. DNSokol

    (37) asved.ru,

    ну-ну. С выключенной галкой «индексировать» время расчета себестоимости 11:20. Если включаем эту галочку и проводим расчет себестоимости, то время получается 8:02.

    Внимание вопрос — что делает галочка?

    Reply
  39. AlexBar

    (38) DNSokol,

    Каким методом ты подсчитывал количество вызовов функции «ЗаполненыНастройкиАналитикиУчета»?

    Мне сейчас интересен не столько механизм оптимизации, сколько понять причину таких многочисленных вызовов.

    Расчет себестоимости оперирует только ключами аналитики в процессе решения уравнений.

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

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

    Дима, у тебя точно типовой код РСВ?

    Попробуй провести РСВ в 3 итерации: первый документ выполняет пункты 1-2, второй 3-4, третий 5.

    Зафиксируй сколько времени у тебя займет проведение каждого из этих документов.

    Зафиксируй при какой итерации происходит многочисленный вызов обозначенной функции.

    Не психуй и не поленись. Очень хочется разобраться.

    Reply
  40. Балабас

    (40) количество вызовов определяется с помощью замера производительности.

    Reply
  41. DNSokol

    (40) AlexBar,

    Расчет типовой. РСВ естественно не создает. Я специально написал про материалы и физлиц. Типовой документ «Передача материалов в эксплуатацию» создает ключи. у меня таких документов в месяц более 200. В каждом документе около 100 строчек. Помимо этого, есть еще возвраты, перемещения и т.д. Которые так же ключики создают. В идеале, если ключ единожды создан, то он должен использоваться, если бы не одно «но». В типовой УПП есть механизм назначений использования спецодежды и спецоснастки. В этом механизме используется справочник «назначения использования», который в свою очередь подчинен номенклатуре. Т.е. для каждой номенклатурной позиции будет столько записей в этом справочнике, сколько вариаций «счет учета/статья/подразделение/метод списания». У меня при 50 подразделениях, 10 статьях затрат (5 статей Принимаемые + 5 статей не принимаемые) и 4 счетах учета, используемых для отражения амортизации спец. одежды, на каждую позицию создается в итоге (т.в. спец* выдается во все подразделения) около 500-800 записей в этот справочник. А это всё — уникальные ключи для РАУЗа. Вот отсюда и вызовы.

    Я, собственно, по этому и писал, что такое ускорение, как в статье, в первую очередь касается тех, у кого большой объем спец* на производстве. Можно, конечно, переделать этот блок, но, опять же, это упирается в большое количество трудозатрат. Проще провести оптимизацию вызовов. По крайней мере, на данном этапе.

    Что до эксперимента, то каждый документ «Передача материалов в эксплуатацию» в итоге или создает, или использует 100 ключей. которые еще и «длинные», потому как для того, что бы по спец. одежде добраться до затратного счета, нужно проделать путь «Документ передачи (в измерениях для РАУЗ есть) -> Физлицо (в измерениях для РАУЗ) -> Назначение использования (ключ) -> Способ отражения расходов (по ссылке из ключа)».

    Про измерения. После того как попередвигал измерения, документ стал проводиться около 3х секунд. До этого около минуты проводился.

    Если взять регистры РАУЗа, то самый маленький — это аналитика вида учета. Там порядка 20 тыс. записей. Дальше аналитика учета затрат — 80 тыс. записей. Еще дальше — аналитика учета партий. Там около 200 тыс. записей уже. Когда оптимизировался было 150 тыс.

    Вся «проблема» в спец. одежде. Если её выкинуть, то да, процедура по чтению ключей вызывается 3 или 4 раза.

    Количество вызовов смотрел замером производительности. Не поверил. Поставил итератор. Сходится. Могу скрин в ЛС кинуть, если интересно. Не могу тут прицепить изображение.

    Reply
  42. AlexBar

    (42) DNSokol,

    Я немного потерян. О чем мы сейчас говорим? Об РСВ или хоз.документах? Если о хоз.документах тогда количество вызовов становится вполне понятным если все записи являются уникальными. Если об РСВ, то укажи мне откуда производятся такие многочисленные вызовы. У меня конечно не так много спец***, но если следовать твоим рассуждениям, то в любом случае указанные функции должны вызываться столько раз, сколько различных аналитик имеется в регистре учета затрат. Я продолжаю тему только по одной причине: я не поленился внести указанные тобой изменения. Если до этих изменений РСВ проводился 9:35, то с внесенными изменениями после реиндексации и реструктуризации регистров получил время 9:29. Выигрыш в пределах погрешностей, связанных с нагрузкой на сервер рабочими базами. Однако твои результаты иные: с 2-х часов до 10-ти минут. Другой коллега заявил что ускорение 30-ти кратное. Цифры впечатляющие. Но я пытаюсь докопаться до сути.

    Если ты решишь не продолжать дальше тему, то достаточно сказать: Леша, давай тему закроем. 🙂

    Reply
  43. DNSokol

    (43) AlexBar,

    Написал же… Речь о хоз. документах естественно в части создания и РСВ — в части чтения. Документ «Передача материалов в эксплуатацию» создает много уникальных ключей, которые потом вычитываются РСВ.

    Если смотреть по этапам:

    Этап 1. Первичные документы (конкретно по спец**) в течение месяца формируют множество уникальных ключей.

    Этап 2. Документами Корректировка НЗП так же походу создаются ключи (или читаются). документы делают бухгалтера перед закрытием.

    Этап 3. Документом «расчет себестоимости» вызывается процедура «ПроцедурыРасчетаСебестоимостиРасширеннаяАналитика.ВыполнитьДействияДокумента», которая в конечном счете приводит к вызову «ВыполнитьРаспределениеЗатрат», которая в свою очередь в цикле вызывает следующую функцию:

    // Заполним аналитику получателя (кор. аналитику)
    АналитикаПолучателя = ПолучитьАналитикуПолучателя(СтрокаБазы, СтрокаДанныеИсточника, ПравилоРаспределения, СтруктураШапкиДокумента);
    
    

    Тут АналитикаПолучателя — это тот самый пресловутый «кэш», который на самом деле не кэш, а набор ключей для дальнейшего расчета. Ну и понятно, что при каждом вызове в цикле функции «ПолучитьАналитикуПолучателя» производится сброс этого кэша, т.к.

    // Возвращает аналитику получателя согласно способу определения аналитики, который указан в правиле распределения.
    //
    Функция ПолучитьАналитикуПолучателя(СтрокаБазы, СтрокаИсточника, ПравилоРаспределения, СтруктураШапкиДокумента)
    
    АналитикаПолучателя = Новый Структура;
    
    

    Соответственно, если повторное значение не использовать, то при каждом вызове «ПолучитьАналитикуПолучателя» происходит чтение базы. При повторном использовании заполнение структуры «АналитикаПолучателя» производится сильно быстрее, т.к. при одинаковом наборе входящих параметров мы читаем базу только при первом вызове ПолучитьАналитикуПолучателя. При всех последующих вызовах то, что уже закэшировано сервером — просто возвращается. Чтение базы происходит только по тем ключам, которые не были получены ранее.

    Надеюсь, теперь понятнее объяснил. Или нет? Что не понятно?

    Reply
  44. DNSokol

    (43) AlexBar,

    И да, похожая «петрушка» наблюдается еще на строительстве, где много отношений с комиссионерами. У меня есть такой филиал. АналитикаУчетаПартий содержит 20 тыс. уникальных строчек (уникальные пары Комиссионер/Договор), но, считается по ним всё очень быстро, т.к. нет кучи циклов. По комиссионерам ключ/значение читается только 1 раз, и далеко не все 20 тыс. записей (в отличие от спец**), т.к. отношения эти не долгоиграющие.

    Reply
  45. asved.ru

    (39) DNSokol,

    С выключенной галкой «индексировать» время расчета себестоимости 11:20. Если включаем эту галочку и проводим расчет себестоимости, то время получается 8:02.

    А план запроса показать стесняемся?

    Reply
  46. PiccaHut001

    (46) asved.ru, вы *а****и уже, план запроса не показатель, он может быть разным для одной базы, после ночной индексации он один, вечером, после активной работы — другой. Мы же оптимизируем 1С, какой тогда смысл его выкладывать?

    Reply
  47. ojiojiowka

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

    Reply
  48. leo-i

    Добавьте тогда и это:

    ШаблонИзмеренийИзМакета(ИмяРегистра).

    И пара вопросов:

    1. Почему выбрали свойство «Повторное использование возвращаемых значений» — «На время сеанса», а не «На время вызова»?

    2. Чем на Ваш взгляд может быть чревато включение в модуль «РасширеннаяАналитикаУчетаПовторноеИспользование» функции СформироватьЗапросПоЗначениямАналитики(СправочникСсылка)?

    Reply
  49. DNSokol

    (49) leo-i,

    не добавлял, т.к. по времени исполнения вроде как существенной прибавки к скорости работы не дает. Но, в принципе можно добавить.

    По вопросам:

    1. На сколько я понял из описаний, то при установке значения повторного использования «на время вызова», то по окончании работы процедуры на стороне сервера, кэш слетает, а если выбрать «на время сеанса», то кэш существует на все время сеанса работы, т.е. пока клиентское приложение не закроется. Т.к. в расчете себестоимости постоянно вызовы между клиентом и сервером прыгают, то я подумал, что лучше режим выбрать «на время сеанса», хотя, тут может и не сильно прав… нужно будет поиграть с вызовами, посмотреть, к чему это приведет.

    2. На первый взгляд — ничем. Но, могу заблуждаться. нужно смотреть откуда функция вызывается.

    Reply
  50. ketr

    Сделал всё как написано, ощутимого прироста производительности не получил(

    Вместо одного часа , стало считаться 50 минут

    Reply
  51. DNSokol

    (51) значит у вас тормоза где-то в другом месте. Надо конкретно с вашей базой разбираться. Так же тормоза могут быть из-за не корректно произведенных настроек сервера СУБД. У меня как-то одним тюнингом СУБД получилось существенно поднять производительность.

    В любом случае без каких-либо подробностей о базе, что-то конкретное сказать сложно.

    Reply
  52. Монту

    Интересная статья, себестоймость в 1С УПП с большим числом полуфабрикатов закрывается 3-4 часа, меня это не устраивает. В выходные попробуем данное решение, и поделюсь замерами времени

    Reply
  53. Монту

    Итого результатов никаких. Ускорение на 2 минуты с 2,08 часа до 2,06 можно считать погрешностью

    Reply
  54. DNSokol

    (54) Значит в базе небольшое количество значений в регистре. Для того, чтобы понять почему 2 часа считается, надо прогнать расчет с/с под замером производительности, посмотреть на каком запросе тормоза и танцевать оттуда. Тормоза могут быть как вычислительные (только увеличивать производительность сервера), так и из-за гигантского количества запросов к базе. И тут вот нужно смотреть, куда лезет расчет и там ковыряться. Если есть интерес повысить скорость, можем вместе как-нибудь посмотреть.

    Reply
  55. Монту

    В регистре АналитикаУчетаПартий заполнены: Комиссионер, Договор комиссионера,Ссылка

    в регистре АналитикаУчетаЗатрат заполнены: Затрата, Характеристика, Серия, Качество, ссылка

    в регистре АналитикаВидаУчета заполнены: Раздел учета, Организация, Подразделение, Счет учета, Счет учета(ну), ссылка

    А 99,9% времени это ПроцедурыРасчетаСебестоимостиРасширеннаяАналитика.ВыполнитьДействияДокумента

    Интерес есть, производство большое, в смысле много полуфабрикатов да и продукции так что большой месяц может считаться и 3-4 часа

    Reply

Leave a Comment

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