<?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);
помимо этого я написал процедуру, аналогичную СоздатьГруппировкиВТаблице именно для индексированной таблицы. Но там совсем медленно все протекает.
а ты попробуй:
Показать полностью
приятно удивишься!
Желательно везде ставить "*", т.е. делай так:
Показать полностью
и ещё. вот это не совсем понял:
Судя по всему, из за того, что в Индексированной Таблице не удаляются колонки при свертке.
если ты нехочешь, чтоб оставались "дети", то и ставь третий параметр в методе "группировать" = 0
(5). Да, звездочка действительно рулит )). Спасибо за просвещение
если писать
табИТ.Группировать(«Контрагент:*Контрагент; Док:*Док»,»Сумма»,1);
то скорость метода Группировать возрастает, на глаз, этак в 3-4 раза.
а третий параметр, как я понял из описания, касается только последнего уровня:
«чРасшифровкаПоследнегоУровня — число, если 1, то в каждой строке последнего уровня группировки будет таблица с расшифровкой, содержащая строки исходной таблицы в нетронутом виде.».
собственно, так он и работает
Ну расскажи теперь про замеры.
И кстати, надеюсь, ты ставишь старт счетчика до «табИТ.Группировать(«Контрагент:*Контрагент; Док:*Док»,»Сумма»,1);», и не до «ЗначениеИзФайла(ИмяФайла,таб);» ? 😉
(7) я похож на дауна ?? ))
фактически после применения пресловутой звездочки актуальность этих измерений потеряна. Метод Группировать() явно выигрышный вариант. Правда, попробую еще на больших таблицах, и сделаю окончательный вывод
Кстати, Евгений, в документации про нее не сказано,
ты не мог бы просвятить, где бы можно было получить более подробное описание класса (я пользовался описанием, скачанным с 1cpp.ru)?
Актуальность не потеряна. Для тех случаев, когда невозможно использовать ВК.
(8) в документации написано:
Синтаксис: Группировать(стрГруппировки, стрКолонкиСумм, [чРасшифровкаПоследнегоУровня = 0])
Параметры:
стрГруппировки — тип: Строка. Строка, описывающая требуемую структуру группировки. Задаётся в виде <ИмяИндекса1>: <ИндексноеВыражение1> [; <ИмяИндекса2>: <ИндексноеВыражение2> … ]. ИндексноеВыражение — строка в том же формате, что и для метода ДобавитьИндекс()
теперь смотрим на метод «ДобавитьИндекс»:
Синтаксис: ДобавитьИндекс(стрИдентификатор, стрВыражение, [чТолькоУникальныеЗначения = 0])
Параметры:
стрИдентификатор — тип: Строка. Идентификатор создаваемого индекса;
стрВыражение — тип: Строка. Индексное выражение. Индексное выражение состоит из списка идентификаторов колонок, разделённого запятыми. Если перед именем колонки стоит символ ‘-‘, то сортировка осуществляется в обратном порядке. Если перед именем колонки стоит символ ‘*’, то сортировка осуществляется по внутреннему представлению объекта.…
т.е. получается так: если ты не ставишь звёздочку, то идёт ещё одно обращение к БД, за счет чего и начинаются не нужные нам тормоза 😉
(9) Lapitskiy, а когда невозможно использовать ВК?
JohnyDeath — твоя правда, моя невнимательность
Lapitskiy если невозможно использовать ВК, то актуальность этих измерений вообще нулевая.
На больших таблицах (порядка 100000) проверил — 1с на этой процедуре уходит в глубокую задумчивость, из которой вывести удалось через диспетчер задач. Ну может быть, машина у меня слабая. 1с++ довольно резво расправлялась с таблицей свыше 200000 строк, создавая в ней упомянутые две группировки + последняя
(13) я считаю, что ТЗ размером в 200000 строк — это слишком. Ведь ты же берёшь их откуда-то? Наверное из БД запросом. Может на этапе запроса выкидывать(группировать,сворачивать) нужные строки? Вряд ли кому-то понадобится отчет, у которого будет столько строк.
я пока только начинаю экспериментировать с прямыми запросами, причем работаю в ДБФ (через СоздатьОбъект(«OLEDBData»)). И пока не смог добиться, чтобы в запросе работала группировка ((.
Посему и стал искать быстрые способы группировки, чтобы не терялся выигрыш в скорости прямого запроса. Первые мои шаги общения с компонентой, поэтому не судите строго
Прошу автора поправить свое описание про «Выигрыш моей процедуры» 🙂
Ты же убедился, что ИТЗ группирует шустрее ? 🙂
ок, конечно!
artbear
хотя, если уж совсем быть строгим, то сортировка по внутреннему представлению может дать проигрыш уже при выводе результатов
(18) это как? поясни.
(19) ты про сортировку ? согласись, кому интересно видеть отчет с сортировкой по внутреннему представлению
(20) Обычно интересует сортировка по показателям (сумма, приход, расход и т.д.). Тогда немного непонятна твоя фраза «может дать проигрыш уже при выводе результатов».. Кому дать проигрыш? По сравнению с кем/чем?
(21) Вообще-то waol рассуждает вполне здраво. Для вывода сгруппированой ИТ нужно будет по новой создавать индексы, но уже не по внутреннему представлению, а по строковому. К примеру
ИТ.Группировать(«Товар: *Товар», «Сумма»);
ИТ.УдалитьИндекс(«Товар»);
ИТ.ДобавитьИндекс(«Товар», «Товар»);
вот на последней то строчке мы и проваливаемся. И такую операцию надо будет проделывать со всеми потомками.
Даже без использования * ИТЗ выигрывает на средних и больших таблицах, на маленьких, естественно, будет выигрыш обычных видов группировок.
(22) Лех, а ты не думал как-то оптимизировать именно этап создания таблиц-потомков, может быть, написать свой распределитель памяти или еще что?
(waol) А с другой стороны, опытные пацаны делают так:
1) как выше написано, группируют уже в запросе
2) если не получается п.1, значит, они уже в запросе получают доп. поля типа КонтрагентНаименование/КонтрагентКод и т.д. для исключения лишних обращений к базе данных, и далее группировка делается уже не по Контрагент без *, а по КонтрагентНаименование/КонтрагентКод
(24) что касается п.1 — давай предположим, что он не получается
а что касается п.2 — то группировать по наименованию — не очень корректно, поскольку наименования не всегда уникальны, т.получается группировка Код и еще группировка Наименование, опять таки при условии, что уникален код, т.е. лишняя группировка. В общем — нюансы, и для моего опыта не все так однозначно.
(25) Ну так тебе никто не мешает использовать еще одно ОГРОМНОЕ преимущество ИТЗ — группировку по нескольким полям, например, Группировать(«Группировка1:КонтрагентНаименование,КонтрагентКод;Группировка2 и т.д.») !
Ты пойми, я призываю тебя к тому, чтобы исключить/минимизировать лишние обращения к базе данных!
ИТЗ умеет не только индексировать и группировать по нескольким полям таблицы.
Такую фишку через штатный код 1С с более-менее подходящим быстродействием универсальным способом так просто не сделаешь 🙂
А тут халява 🙂
(22) Ну это ты написал для сортировки по «наименованию». Тут — да, будет польза, а я писал про сортировку по показателям.
(25. п.2)
А ты делай индекс, состоящий из двух колонок: Наименование и Код (предполагая, что эта комбинация уникальна).
млин, по п.2 Артур уже опередил…
(waol) Нужно расшифровывать про минимизацию обращений к базе через запросы? Или нет?
(30) не получилось у меня использовать метод группировки в запросах с использованием
OLEDBData ((… я уже писал, кажется.
Если дашь полезный совет — не откажусь ))
про группировку по нескольким полям — спасибо за намек, я пока ее не исследовал, только собирался посмотреть, есть ли такая возможность )). Приколно — я в сабжевой процедурине все собираюсь сделать такую возможность, да все руки не доходят. Возможно теперь уже и не дойдут.
(23) Про возможности сокращения накладных расходов конечно думал, хотя не слишком упорно 🙂
Правильнее было бы вообще не создавать вложенных таблиц, а создавать некую деревянную структуру для обхода, и отдельно висящие итоговые строки, и каким-то образом организовать обход всего этого добра.
(31) 1. Весь смысл в том, чтобы ты все необходимые поля доставал в запросе — например, для Контрагентов нужны сам элемент, его наименование, код, в запросе соответственно нужно получить ИД, Наименование, Код.
Для ИТЗ неважно, каким образом получен запрос — прямой запрос 1С++ или обычный запрос 1С.
Главное, чтобы ИТЗ брал из таблицы готовые данные, а не пытался обратиться к базе данных.
Т.е. вместо довольно медленного ИТЗ.Группировать(«Контрагент:Контрагент», «Сумма») нужно юзать что-то вроде ИТЗ.Группировать(«Контрагент:КонтрагентНаименование,КонтрагентКод», «Сумма»)
.
2. Максимально оптимально, чтобы и группировка была в запросе, но раз у тебя это пока не получается, можешь делать группировку в ИТЗ, скорости у ИТЗ не столь плохие при соблюдении условия из п.1
artbear в принципе все логично, исходя из предыдущего диалога ))
довольно полезные советы, благодарствую
ADirks это уже будет по-видимому другой объект
за ИндексированнаяТаблица отдельное спасибо, это действительно прорыв!
сравнимо с появлением обычной ТаблицаЗначений в 77
в процедурах СоздатьГруппировкиВТаблице, СоздатьГруппировкиВТаблицеСВложеннымиПериодами исправлена ошибка. Возникала в тех случаях, когда группировка возникала в последней строке таблицы
а вобще можно и так :
ИТЗ.Группировать(«Контрагент:КонтрагентНаименование,*Контрагент»,
«Сумма»)
🙂
(36) верно ) за промежуток между 35 и 36 сообщением я не поверишь, это уже понял ) и то что штука наимощнешая в общем тоже