<?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='\
а где НЕ В ИЕРАРХИИ? вот где жесть-то )
1. На перед, не известно какой план запроса получится
2. Логику кэширования лучше оставить. У нашей организации бывают пользователи что 14 дней базу не закрывали, и так же обработки. Регламентные работы 1 раз в 14 дней, максимально сеансов бывает и до 600, максимальных соединений до 200.
1,4. Такие запросы признак проблем с проектированием
Хаус + запросы = ildarovich
Лучше смените иллюстрацию, а то складывается негативное впечатление, будто вы товарный знак стырили.
Я не говорю, что вы так и сделали, но впечатление складывается.
(3) true SQL DBA,
ну если еще глубже посмотреть, то СГРУППИРОВАТЬ ПО оптимальнее чем ВЫБРАТЬ РАЗЛИЧНЫЕ
Предпочитаю регистры сведений с доп. данными для отдельно взятых случаев (вроде 1 и 4), при этом запись в эти регистры стараюсь делать в фоновых заданиях.
В случаях 2 и 3 обычно как параметр не ставлю в запрос, а накладываю отбор.
(4) vasyak319,
Эх.. на выбор картинки ушло больше времени, чем на написание текста :).
Поменял.
А вы уверены, что Пример 1 работоспособен? А то 1С утверждает, что когерентные запросы возможны только в секции «ГДЕ» и мои попытки игнорировать это утверждение всегда натыкались на то, что оно оказывалось верным.
Пример 2: можно просто переписать условие как «Р.Склад В (срез последних)» и никаких тебе соединений таблиц с одной стороны и никаких необходимостей переоткрывать форму — с другой.
Пример 3: А вы смотрели в SQL профайлере, как 1С преобразует конструкцию «В ИЕРАРХИИ»? Я, если что, сам не смотрел, но там по-любому должно быть что-то своё, одинэсовское, потому что SQL про группы не в курсе и без такого анализа ценность вашего предложения нулевая. Вполне возможно, что сервер 1С сам делает преобразование, аналогичное предложенному вами, так что ваш способ будет тормозить даже сильнее, потому что у вас два обращения к серверу вместо одного и передача списка ссылок вместо одной.
Пример 4: «Как мне кажется»
В таких случах надо смотреть план запроса, иначе это не оптимизация, а гадание.
(3) true SQL DBA,
незачет :).
Во вложенной таблице выборка без фильтра.
Даже визуально видна значительно более медленная работа при обновлении динамического списка.
А план запроса покажет перебор большого числа записей из счет-фактур.
(1) rozer,
На самом деле, такая же ситуация как в третьем примере. Избавление от «В ИЕРАРХИИ» несколько улучшит ситуацию.
(2) pbazeliuk,
Вполне известно — получается лучше.
Тут нужно найти баланс. Проведение вычислений при каждом обновлении динамического списка мне видится нецелесообразным.
Как вариант — в форме можно сделать обработчик ожидания, срабатывающий каждый час и обновляющий эти значения.
Каким вы видите оптимальное архитектурное решение в обоих случаях?
(7) vasyak319,
Данный пример вполне работоспособный.
Ситуация не изменится — при каждом обновлении динамического списка система будет вычислять этот сред последних, а уже потом соединять с основной таблицей.
Срез последних сам по себе тяжелый — три уровня вложенности получается (выборка максимальных значений, выборка детальных записей по максимальным значениям, соединение с таблицей документов).
Все четыре примера успешно опробованы не раз на разных базах. «В ИЕРАРХИИ» — это запрос в цикле.
Вы не обладаете информацией, а делаете далеко идущие выводы.. проверить то не сложно :).
Не делает он такого преобразования, и обращений к серверу СУБД в моем случае получается меньше.
В таких случах надо смотреть план запроса, иначе это не оптимизация, а гадание.
Решить эту задачу можно разными способами. Фраза «как мне кажется» отражает мое личное мнение, основанное на практическом опыте, относительно эффективности подхода с кешированием в промежуточных таблицах в сравнении с другими вариантами. Тут даже планы запросов не надо смотреть, чтобы увидеть более эффективный вариант.
Кстати, в типовом Документообороте подход с кэшированием успешно применяется для ряда объектов.
(6) vandalsvq,
Дополнительная нагрузка, как правило, совсем минимальная, поэтому можно смело вставлять запись в такие регистры в процедуры записи основных объектов.
Информация обновляется оперативнее, да и сложность реализации меньшая.
На самом деле, точно такая же ситуация — если делать отбор «В ГРУППЕ», то при каждом обновлении динамического списка будет происходить выборка иерархии.
Выбрав иерархию самостоятельно и передав массив объектов в отбор просто с видом сравнения «В СПИСКЕ» можно ускорить обновление динамического списка.
(12)
Да нет, надо. Иногда преобразование запроса, которое вроде бы должно только добавить тормозов, уменьшает время его выполнения на порядок-другой. И даже глядя на результат не понимаешь, почему так. А ответ в плане запроса.
По пункту 4.
Решение с созданием дополнительных таблиц следует использовать если подобная операция довольно частая и вносит «определенную нагрузку».
(9)
Во вложенной таблице выборка без фильтра.
Даже визуально видна значительно более медленная работа при обновлении динамического списка.
А план запроса покажет перебор большого числа записей из счет-фактур.
Все равно плохо!
Мой запрос работает быстрее, а тот, который вы оптимизируете (с группировками) — еще быстрее!!!
(5) Nefertary — вы правы.
Во вложении картинка с замерами производительности и обработка, с помощью которой они получены (для БП 3.0).
Наиболее правильным решением задачи из Пример 1 является создание отдельного РС с данными, которые нужно получать для списков.
Пример — РС НаличиеПрисоединенныхФайлов в типовой БП 3.0, это механизмы БСП.
Хороших выходных!
(16) true SQL DBA,
Так проводить замеры совсем некорректно.
Это как раз и есть решение «в-лоб».
Вы не учли особенности динамического списка — данные выбираются порциями (к тексту запроса добавляется выборка первых записей «ПЕРВЫЕ N», в условие добавляется граничная ссылка на объект и добавляется сортировка). Т.е. фактически платформа выполняет другой запрос.
Создайте динамические списки на основе этих запросов и снимите трассировку через MSSQL Profiler.
Похоже надо расширить статью и показать планы запросов с пояснениями.. не хотелось перегружать на самом деле.
(13)
Ты меня малость не понял, список элементов формирую как и ты писал, до передачи в отбор. Просто вместо параметра отбор «В СПИСКЕ».
Вопрос что мы записываем туда, реквизиты из объекта, согласен, накладных копейки. А если делаем пересчет статистических показателей — лучше уж в фон. Тем более с использованием БСП проблем никаких, пишешь «правильно» процедуру, тестируешь без фона, потом просто обертку из ДлительныеОперации делаешь и все.
Насколько я осведомлен, ПЕРВЫЕ n будут выбираться только если порционное (динамическое) чтение данных стоит, а оно будет если у списка платформа может определить ключ. В свою очередь это относится только к запросам на основании объектов метаданных.
Оффтоп: в этом плане в 1С++ (на 7.7) динамические списки были намного шире, их можно было наполнять собственным запросом при условии установки уникального ключа. Т.е. не было большой необходимости привязываться к метаданным.
(18) vandalsvq,
Да, согласен по тому, что ты написал.
И таких динамических списков (с динамическим считыванием данных) подавляющее большинство в конфигурациях.
Без этого динамический список уже получается простым табличным полем с запросом, к которому применимы стандартные правила оптимизации запросов.
Честно говоря, я не помню, чтобы в динамическом списке можно было определить запрос не на основании метаданных. Что имелось в виду?
(19)
Имел в виду указывать или нет основную таблицу в форме редактирования запроса динамического списка.
(0) в чем преимущества использования динамических списков в сравнении с использованием АРМ разработанным на обычных неуправляемых формах?
делали замеры производительности использования динамических списков и использования списков обычных форм?
(21) Rustig,
Мне кажется, что сравнивать обычные формы списков и управлямые динамические формы списков нельзя. Слишком большая разница в доступном функционале.
При одинаковых условиях (выборка только из основной таблицы) оба механизма работают одинаково быстро.
Если нужен вывод данных из смежных таблиц — в общем случае, динамический список будет быстрее за счет выполнения одного запроса, т.к. в обычной форме уже нужно использовать процедуру «ПриПолученииДанных».
Плюс в динамическом списке у пользователей значительно больше свободы в настройке отборов, сортировок и т.д. При сложной настройке динамические списки могут работать медленно, но это не говорит о том, что обычные формы лучше. Там просто нельзя сделать аналогичные пользовательские настройки.
(21) Rustig, НЕ всегда возможно делать обычные списки (особенно когда конфигурация написана в такси 🙂 )
Добрый день! можете подсказать какими инструментами делали анализ производительности запроса?
(24) sashapere,
http://infostart.ru/public/252236/
http://infostart.ru/public/291874/
SQL Server Profiler
Скрины планов запросов для большей наглядности сделал с помощьюhttp://www.sqlsentry.com/products/plan-explorer/
(25) последняя ссылка не работает.
(26) Mortiferus,
видимо, автор снял публикацию (там скрины были битые и я просил автора это поправить).
UPD. Добавил пятый пункт про опциональные отборы.
(3) true SQL DBA,
Запрос, ИМХО, неверный
1)Использование слова РАЗЛИЧНЫЕ во вложенном запросе не оправдано
2)Его нужно использовать в основном запросе, иначе записи не будут уникальными в случае >1 счета-фактуры на 1 реализацию.
Показать
(29) bulpi,
На самом деле в данном случае различные во вложенном запросе обеспечивает уникальность поля ссылка в основном.
Поле признак избыточно, т.к. можно выводить поле (НЕ x.ДокументОснование есть NULL)
Предложенный пример #1 самый непроизводительный, причем к гигантским отрывом (медленнее в несколько сотен раз) Всех прочих. Подвисания дикие… до нескольких десятков секунд! Вычисление поля в цикле…
Показать
(31) nvv1970,
Об этом сказано в конце примера — данный запрос хорош ТОЛЬКО для динамического списка с динамическим считыванием данных.
если больше 128 элементов, то платформа будет создавать временную таблицу, причем индексированную
Про пример 1. А как в таком случае будет работать отбор ДС по полю «признак»? не умрет ли он совсем по сравнению с левым соединением?
Про пример 3. Проводили исследования про использование В ИЕРАРХИИ через доп РС с данными для nested sets?
А в динамическом списке возможно ли отображать табличные части документа?
На днях пришел к выводу, что есть ситуации, когда динамический список вообще стоит выкинуть, прицепить к форме таблицу значений и активнее использовать
У меня это оказалась обработка из серии рабочее место кладовщика, которая долгое время медленно обрастала новыми требованиями. В итоге запрос оброс множеством параметров, а сам динамический список стал очень медленно отрабатывать.
(28) Направьте меня пожалуйста на опциональные функции компоновщика — где почитать?
Правильно ли понимаю для Примера 5: Если параметр «Автор комментария» не заполнен и поля второй таблицы заключены в фиг скобки то левого соединения не происходит?
Покажите пример где опционально поле второй таблицы (по параметру) не выводится и не происходит соединения.
(5) всегда было интересно чем, если план будет абсолютно одинаковый.