<?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='\
Зачем делать запрос к таблице ДвиженияССубконто, если ты все равно делаешь запрос к основной таблице регистра бухглатерии? Оптимальнее делать запрос либо только к ДвиженияССубконто либо к двум таблицам: к основной таблице и к таблице Субконто.
(1) tormozit,
согласен, но я умышленно разнес на два запроса.
Объясняю:
Для Субконто использую ДвиженияССубконто. Для измерений, ресурсов и реквизитов — основную таблицу. Так легче потом делать замеры и определять необходимость индексации реквизита.
Например, в УПП в регистре бухгалтерии Международный есть реквизит ПервичныйДокумент — составной по всем видам документов. Но любой документ так же может быть в роли субконто этого регистра. Если буду делать все в одном запросе — усложняю задачу по поиску причины тормозов.
PS. Невнимательно прочитал вопрос. Да, запрос к Субконто более оптимальный, чем к ДвиженияССубконто, исправлю, спасибо!
Вот ведь все хорошо пишите. Но это вот зачем писать-то? На сколько увеличат объем журнала транзакций именно ваши «ручные» транзакции? Да ни насколько.
Периодически сжимать журнал транзакций на рабочей базе нельзя, ну только если вы техномазохист и/или у вас НЖМД в «сервере» аж целых 40Гб.
(3) yukon,
вы не поверите, после удаления 50млн записей регистров методом TSQL DELETE база выросла в полтора раза (в моем случае до 150Gb) как раз за счет разрастания журнала транзакций. DELETE пишет себя в журнал транзакций, даже если recovery model = simple.
(4)
Охотно верю. И как часто вы удаляете 50 млн записей? Неужели ежедневно.
Если действия массовые и разовые, то сжать журнал транзакций разово можно. Но периодически сжимать на рабочей базе нет необходимости.
Если у вас на сервере один жесткий на 320Gb, то да это ПРОБЛЕМА, согласен.
(5) yukon,
так я собственно предлагаю периодически сжимать файл транзакций только при массированных удалениях, особенно если запас дискового пространства не ахти. Рассказать про все случаи разрастания файлов mdf ldf — это совсем другой контекст статьи.
ps. По своему опыту знаю, что урезание файла журнала транзакций можно выполнять при работающих пользователях. Эта операция быстрая и безболезненная. А вот урезание файла с данными (mdf) может быть долгим, т.к. процесс похож на дефрагментацию диска. Файл данных разрастается, например, после реструктуризации базы — попробую объяснить почему: все таблицы пересоздаются и записываются в конец файла mdf, данные из старых таблиц переносятся в новые, старые удаляются, и появляются дырки в начале файла mdf. Как-то так…
Можно, но крайне не нужно.
Это не так. Операция далеко не безболезненная.
Это весьма упрощенное и, как следствие, в большинстве случаев, неверное представление. На увеличение размера mdf файла(ов) влияют с десяток факторов. А уж на размещение данных внутри mdf-файла(ов) как бы не сотни.
Внешняя простота работы SQL-сервера, не означает, что внутри все примитивно устроено. Тот факт, что SQL сервер до определенных пределов умеет сам за собой ухаживать, не означает, что можно выполнять любые манипуляции — пока не падает все типа нормально.
В частности, размер ldf файла в модели восстановление simple SQL сервер выбирает именно такой, чтобы обслуживать базу данных при существующей интенсивности работы. Вместо помощи серверу и увеличения размера ldf файла, хотя бы до размера «чуть больше чем надо», вы предлагаете на постоянной(!) основе вставлять серверу палки в колеса, это же «быстро и безболезненно».
(7) yukon,
Юрий, я прямо чувствую, что вы обладаете тайными знаниями, и очень искусно их прячете от общества 🙂
Дайте пруфлинки, объясните развернуто, чем таким чревато урезание журнала транзакций при подключенных к базе пользователях? Все вам скажут спасибо, если знания будут полезны. Тут атмосфера вполне доверительная.
(9) yukon,
вот, уже лучше, осталось только чтобы ссылки открывались 🙂
(10)
По клику не открываются — какой-то набор букв вываливает 🙁 а copy-paste работает. Мистика 🙂
(11) yukon,
прочитал, но так и не нашел ответа на свой вопрос: если у нас объемная 1С-база, с ежедневным полным бэкапом и включенным recovery mode = simple, и мы провели массированное удаление с помощью команды T-SQL DELETE, и получили распухший журнал транзакций, соизмеримый с размером файла данных, и видим, что свободное файловое пространство на исходе, и спинным мозгом чувствуем, что в любой момент наступит коллапс всей базы, что же все-таки КОНКРЕТНО нам мешает в этом случае сделать усечение файла журнала транзакций?
(12)
0_0 за час? Там только чтения страниц 30 А4. Минимум на весь день, а с практикой так и на все 3-4 дня.
Это как так? 150 гигов для современных дисков это не очень внушительный объем. Даже для серверных версий дисков. Заложите в бюджет расширение дискового пространства.
Само по себе такое событие «свободное файловое пространство на исходе, и спинным мозгом чувствуем, что в любой момент наступит коллапс всей базы» уже ЧП. Говорит о недостаточном уровне планирования выполняемых работ. Вы ведь предварительно на тестовом стенде прогоняли столь массивную операцию? И что, на тестовом стенде журнал транзакций не вырос до столь внушительных размеров?
Конкретно, разово ничего не мешает. Но это далеко не простая и безболезненная процедура. Если уж прям нужно то сделайте ее во время наименьшей загрузки базы. Еще лучше — в «монопольном» режиме. При этом размер усеченного файла оставьте достаточно большим, для обслуживания нормальной рабочей интенсивности работ.
В нормальном режиме эксплуатации SQL сервер самостоятельно производит усечение журнала по мере необходимости.
(9)(10)(11)
архив zip Сохранил в одном архиве для истории.
(13) yukon,
теперь понял, спасибо за совет! А вы не хотите по этому поводу написать статью на ИС с конкретными рекомендациями для 1С-внедренцев — как правильно настраивать журнал транзакций и почему, чтобы уберечь от возможных негативных последствий?
PS. Для меня, как для внешнего подрядчика обычно недоступны все IT-ресурсы заказчика. Чаще всего они выделяются по мере необходимости — нарезаются виртуальные машины с определенными параметрами. Поэтому на тестовых базах такое часто случается — недостаток дискового пространства. Эту ситуацию я и описал выше.
(14)
Спасибо.
(15)
Ну вы и задачки ставите. «Правильно» — это к SQL DBA, а «на пальцах» могу попробовать.
Маленький баг есть. Получить его сложно. Если в конфигурации количество регистров > 255 то на базе MS SQL упадет при заполнении объектов поиска. У меня такая ситуация на УПП+Appius на документе КорректировкаЗаписейРегистров.
Просто повесил проверку на количество таблиц.
Почему-то в моем случае сразу не получилось запросто использовать…
В базе все документы за сворачиваемый период уже помечены на удаление.
Пытался сделать удаление одного вида документа.
При заполнении таблица «Документы без движений» — пустая, т.к. при ее заполнении анализируются документы не помеченные на удаление.
В процедуре «АнализОднойИзТаблиц» в строке модуля 739 под комментом «еще раз проверим отсутствие движений» выполняется запрос на наличие движений у объекта с условием «НЕ ТекДокумент.ПометкаУдаления».
При этом результат запроса всегда пустой и удаление не происходит.
К слову, в выражении «ТекстЗапроса_БезДвижений» тоже содержится условие на «НЕ ТекДокумент.ПометкаУдаления».
Это все потому что данный запрос относится только к таблице документов без движений. А автор как-то забыл поставить условие. После правки данного блока вроде все нормально.
Можно на почту Альтернативный контроль помеченных и быстрое удаление средствами SQL berator37@mail.ru . Заранее спасибо
(19) timm00, (18) Wrols,
насколько я понял то там ошибка не в запросе, а в условии после него:
вместо условия
Если Запрос.Выполнить().Выбрать().Количество() = 0 Тогда
нужно
Если Запрос.Выполнить().Выбрать().Количество() > 0 Тогда
т.е. если есть движения, то нельзя удалять
Показать
глюк какой-то?, не могу изменить адресат поста, ошибся и ответил 20-му
(18) Wrols, (19) timm00,
мой предыдущий пост предназначался вам
Добрый день!
Пытаюсь в УТ 11.0 почистить справочник «Контрагенты».
{Форма.Форма.Форма(539)}: Поле объекта не обнаружено (ОбщийРеквизит)
МдРез = Метаданные[ИмяПоля];
А можно ли как то удалить документы за определенный период ?
barelpro, вы очень душевно поработали. Восхищает, что обработка (субъективно) раз в 50 быстрее удаляет данные и при этом позволяет другим пользователям полноценно работать с базой (в том числе запись и проведение документов. Спасибо.
Однако есть и просьба устранить две странные ошибки.
1) Заменить процедуру ЗначениеНеЗаполнено на сам знаете что….
2) Возможно я не прав, но…. у похоже в коде процедуры АнализОднойИзТаблиц
Понадобилось заменить
Потому как ваша обработка останавливает любую активность, как только находит строку, которую удалять нельзя.
Поправьте меня, если я не прав.
(23) zekrus,
В своей версии обработки я добавил
СпЗамен.Вставить(«ОбщийРеквизит», «ОбщиеРеквизиты»);
последней строчкой. Вроде взлетело.
Хорошая обработка! Даже не смотря на некоторые, выше отмеченные ошибки.
Есть предложение добавить опцию «отложенное удаление», при котором скрипт не выполняется, а сохраняется в текстовый файл.
Очень не хватает функции «Разорвать циклическую ссылку» .
А то есть два документа СчетФактураВыданный (реквизит ДокументОснование) и ОказаниеУслуг(реквизит СчетФактура) оба помечены на удаление и ссылаются друг на друга.
Чтобы удалить документы, ссылающиеся друг на друга добавил строки
в процедуру СоздатьЗапросВСхемеАнализа
Очень хочется услышать мнение автора обработки на этот счет.
(29) pit201201, А где это добавить, поточнее можно?
У меня не заработало.
Странно у меня работает.
(21) правильное исправление такое
добавить перед выполнением запроса строку
Кусок тогда будет выглядеть так
Показать
Тогда для любого очередного документа к удалению, не важно помеченный он или нет, будет проверяться отсутствие движений. Если есть движение хоть в каком то регистре, где документ является регистратором, то результат запроса будет пустой и соответственно выполнится условие
и у документ справедливо не будет удален.
Автору бы не мешало поправить обработку
На файловой базе не заработала
Проходит анализ объектов, но объекты в результате не помечаются галочкой «Можно удалять» и не удаляются.
Жаль бессмысленно потраченные 5 $m .
Подтверждаю, что для файловой базы ЭТА обработка не работает! Занимаюсь отладкой и исправлением ошибок уже второй час и пока результата нет. Действительно жаль 5$m!!!!
(25) Алексей, спасибо. я поправил как вы сказали и все заработало. а то у меня тоже останавливалась сразу обработка.
автору обработки — огромнейшее спасибо за труд. реально выручил. можно сказать вытащил из трясины ))
РАБОТАЕТ! тем у кого не сработало — см. комментарий 25
прогонять приходится 2-3 раза. потом уже остатки добиваем штатным удалением помеченных.
базу упп 1.3 на 150 тысяч помеченных объектов, на обычном пк corei5 с 8 гб оперативки зачистила за сутки. автору спасибо
Скачал данную обработку в итоге по времени работает не быстрее да ладно бы не быстрее, так она работает не корректно (удаляет лишние данные без движений, да и приходится править ошибки в коде) все что написано выше что полезная полная чушь…
Жаль потраченные 5 стартмани
(41) — там уже выше комментировали, что она действительно работает очень выборочно…но вы же всегда можете заминусовать 🙂
Блок, начинающийся со строки 739
Показать
Я так понимаю, что тут проверяется, есть ли у документа движения. Во-первых при этом вылетает на первом же документе, у которого нет движений. Поэтому вот это:
меняем на это:
а Прервать; на Продолжить;
А что понимается под выбрать()?
Создается и сразу же уничтожается в памяти объект из которого берется только количество()? Флуктуация какая то..
А потом что с запросом, снова выбрать или выгрузить?
(44) тут как раз всё понятно, проверяем пустая ли выборка.
Выполнить() создаёт объект РезультатЗапроса.
Выбрать() создаёт объект ВыборкаИзРезультатаЗапроса для этого объекта
Количество() возвращает количество значений в выборке.
В принципе можно заменить на
НЕ Запрос.Выполнить().Пустой()
А дальше выгружать нечего. Это запрос просто проверить, есть ли ссылки на этот объект в движениях.
Буду пробовать на базе 200 ГБ )
На управляемых формах не планируете делать?
Хотелось бы, чтобы автор учел комментарии и исправил свою обработку, иначе непонятно можно ей пользоваться или нет.