Графический план выполнения запроса 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='\

28 Comments

  1. unichkin

    Есть еще бесплатная утилита SQL Sentry Plan Explorer для чтения планов. Если скрестить ее с этой консолькой, то и студия на клиенте не нужна…

    Reply
  2. berezdetsky

    (2) SSMS — бесплатный инструмент от вендора СУБД. Более функциональный, чем Plan Explorer.

    Reply
  3. Gilev.Vyacheslav

    (1)

    (5)Тогда так http://www.gilev.ru/#ConsoleGilevRu учетка Пользователь без пароля

    Reply
  4. berezdetsky

    (6) Моя обработка не использует техжурнал и, как следствие, не приводит к дополнительной нагрузке и не накладывает требований по наличию прав доступа к хосту сервера приложений. Я достаю планы выполнения непосредственно из кеша планов SQL Server.

    Ваш подход в целом точнее, но затратнее.

    Reply
  5. herfis

    Возможность обойтись без тех-журнала — несомненный плюс.

    Reply
  6. Gilev.Vyacheslav

    (7) логирование в ТЖ одной сессии создает настолько мизерные затраты, что говорить что это «более затратное» самообман

    Reply
  7. berezdetsky

    (9) Я говорю о затратах не столько технических, сколько организационных. Для ларьков эти затраты действительно мизерные.

    Reply
  8. Gilev.Vyacheslav

    (10) а что по вашему лучше, логин с авторизацией на субд или без авторизации в какую либо базу данных на сервере 1С?

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

    Reply
  9. zarucheisky

    (10) Ваня 🙂

    Это кому там понадобилось-то?

    «Неужели в наших котлетах будет мясо?» (с)

    Эх.. Ромы на вас нет :))))

    Reply
  10. zarucheisky

    (11) Там на уровне СУБД

    Reply
  11. zarucheisky

    (10) ИМХО, ежели MS SSMS перекрыт вместе с MS VS, то можно воспользоваться

    http://www.atlantis-interactive.co.uk/api/applicationdownload.ashx?key=ASE

    Reply
  12. berezdetsky

    (12) Привет! Мне и понадобилось. 🙂 Как говорится, делал как для себя. 🙂

    Reply
  13. herfis

    (11)

    даже фирма 1С не смогла ничего подобного написать

    Не первый раз слышу в такой формулировке и каждый раз улыбаюсь. Вы, безусловно, молодцы, но формулировка улыбает.

    Типа 1С всей фирмой пыталась-пыталась, пыталась-пыталась и таки не смогла — «фух, не могу больше, не выходит каменный цветок. Такое только команде самого Гилева под силу».

    Reply
  14. zekrus

    Доброе утро!

    Решение востребованное без условно.

    Меня терзают смутные сомнения, вы

    не из компании «Раздолье» случайно?

    С уважением

    Reply
  15. Gilev.Vyacheslav

    (16) если не следили за развитием ЦУПа, то иронию понимаю, а вот если следили… )))

    Reply
  16. zarucheisky

    (17) Нет, если не ошибаюсь, Иван трудится в иной компании 🙂

    Reply
  17. artbear

    (7) Иван, хорошая работа, спасибо!

    ИМХО цитату хорошо бы включить в описание публикации

    «Моя обработка не использует техжурнал и, как следствие, не приводит к дополнительной нагрузке и не накладывает требований по наличию прав доступа к хосту сервера приложений. Я достаю планы выполнения непосредственно из кеша планов SQL Server. «
    Reply
  18. berezdetsky

    (17) Нет.

    (20) 🙂 Ok, добавлю в описание.

    Reply
  19. sevushka

    Мелкие нюансы, для будущих поколений 🙂

    ProgId = «V» + XMLСтрока(ВерсияПриложения.Основная) + XMLСтрока(ВерсияПриложения.Младшая) + «.COMConnector»;

    Основная а не старшая. По крайней мере для 8.3.8

    If Cluster.HostName = HostName Then

    надо приводить к одному регистру, иначе не срабатывает (в строке подключения стоит uppercase например, а в Cluster.HostName lowercase)

    Reply
  20. sevushka

    Продолжение (не могу исправлять предыдущее сообщение)

    СтрокаПодключения = «Provider=SQLNCLI11;Server=» + ИмяСервера + «;Database=» + ИмяБазыДанных + «;»;

    не у всех есть 11, кто-то и на 10 сидит (SQL — 2008R2).

    Далее. Еще надо настраивать dsn, по умолчанию он лезет через named pipes, а на некоторых серверах (например моем) они выключены, надо использовать tcp/ip (или менять строку подключения, или включать каналы на сервере).

    Ну и в итоге — не сработало. Подключилось (причем пользователя давал и датабейз овнера, и sa, и domain authorization — разницы нет). Запрос выполняется, колонки таблицы тз в ВыполнитьЗапросSQL заполняются, но запрос пустой.

    Если Не Recordset.EOF Тогда <—- здесь истина, т.е. данных нет. Время на клиенте и сервере совпадает.

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

    Reply
  21. sevushka

    Автору на заметку

    Добавляю в текст запроса

    , qp.query_plan AS ПланВыполнения

    , qp.dbid as ИДБазы <——— вот эту строчку. И у меня, для многих баз, qp.dbid = null.

    Соответственно, в условии

    and qp.dbid = db_id()

    null не равен 10 (id моей базы)

    Reply
  22. sevushka

    Ну и на закуску

    Убираю в запросе строчку and qp.dbid = db_id(), чтобы были все запросы.

    Делаю примитивный запрос к одной таблице.

    Доходит до

    Процедура СопоставитьЗапросы(СтатистикаВыполнения)

    СтатистикаВыполнения — таблица, где мой запрос есть.

    Но… он не сопоставляется. Можно поставить галочку «показывать все доступные запросы», тогда запрос виден в таблице, но его еще надо найти в куче.

    Разбираться уже не стал, почему сопоставление не работает.

    а еще в таблице результатов при даблклике {(2,62)}: Переменная не определена (ЭтотОбъект)

    Новый ОписаниеОповещения(«ОповещениеОВыбореРежимаОткрытия», <<?>>ЭтотОбъект, Расшифровка),

    т.е. для конфигураций, которые еще работают в режиме совместимости, это тоже не работает.

    Обработку скачивать не рекомендую.

    Reply
  23. berezdetsky

    (22) .. (25) Спасибо за комментарии. Основные косяки исправил, но пока не выкладывал.

    Про dsn не понял. У меня named pipes везде выключены. По tcp/ip и shared memory подключается без проблем.

    qp.dbid = null на 1Сных запросах не видел. Покажи пример запроса и версии 1С и SQL Server, пожалуйста.

    По сопоставлению — для пакета порядок запросов в пределах секунды иногда нарушается. При этом сопоставление пока не работает.

    Если не работает для одного запроса — опять же давай тестовый пример.

    Reply
  24. sevushka
    Reply
  25. berezdetsky

    (27) Выложил исправленную версию с улучшенным сопоставлятором.

    По named pipes возьму таймаут — поиграюсь с разными версиями.

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

    Reply
  26. user617199_pablonikolaev

    спасибо за труды

    Reply
  27. kirinalex

    (4)

    SSMS

    в чем именно SQL Server Management Studio более функциональный, чем SentryOne Plan Explorer?

    Reply
  28. tormozit

    Аналогичный инструмент «Статистика по запросам MSSQL» есть в подсистеме Инструменты разработчика . Он также использует процедурный кэш MSSQL и не создает какой либо нагрузки на работу серверов. В этой же подсистеме в инструменте «Консоль запросов» на странице «Запрос результата» с помощью кнопки «Статистика MSSQL» можно посмотреть статистику по последнему выполненному запросу.

    Reply

Leave a Comment

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