Имя: Пароль:
1C
 
ADODB асинхронное выполнение BACKUP DATABASE и получение прогресса
0 TormozIT
 
гуру
23.08.15
21:48
Решаю задачу выполнения резервного копирования базы в MSSQL с отображением прогресса в форме (асинхронно). Решаю долго и мучительно. Пока не успешно. Ниже код через ADODB

ADODBCommand.CommandText = "BACKUP DATABASE TO DISK='my.bak' WITH STATS=10";
Options = adAsyncExecute + adExecuteNoRecords"; // 16 + 128
ADODBCommand.Execute(RecordsAffected, Null, Options);
Пока ADODBCommand.State = 4 Цикл
    ПаузаИис(1);
    Если ADODBCommand.ActiveConnection.Errors.Count > 0 Тогда
    Сообщить(ADODBCommand.ActiveConnection.Errors.Count);
    КонецЕсли;
КонецЦикла;

Асинхронно процесс выполняется, но прогресс в виде текстовых сообщений в свойстве Errors появляется только после завершения выполнения команды (когда ADODBCommand.State = 0). И даже тогда он появляется только в количестве 1 сообщение (первый вывод прогресса).

На sql.ru уже порылся.
http://www.sql.ru/forum/731198/tadocommand-v-asinhronnom-rezhime
1 TormozIT
 
гуру
23.08.15
22:02
Если подключить обработчик события ADODB.Connection.InfoMessage, то он вызывается опять же только после завершения выполнения команды и ровно 3 раза всегда с одним и тем же сообщением прогресса.
2 МихаилМ
 
23.08.15
23:50
ms sql profiler вам поможет. либо наведет на правильную строку поиска
3 DmitrO
 
24.08.15
08:59
http://dev.citykirov.ru/
Обработка ВосстановлениеБД. Там это есть. Глянь.
Написана давным давно, проблем с получением прогресса при бекапе вроде у меня не было.
4 vde69
 
24.08.15
09:18
смотри в типовых

ДлительныеОперации.СообщитьПрогресс(Всего, мТекущийАдрес)
5 TormozIT
 
гуру
24.08.15
09:34
(3) Касперский на этот сайт выругался. Можешь кинуть на почту или файлообменник?
6 DmitrO
 
24.08.15
09:41
(5)отправил по почте
7 vde69
 
24.08.15
09:45
// Регистрирует в сообщениях информацию о ходе выполнения фонового задания.
//   В дальнейшем эту информацию можно считать с клиента при помощи функции ПрочитатьПрогресс.
//
// Параметры:
//  Процент - Число  - Необязательный. Процент выполнения.
//  Текст   - Строка - Необязательный. Информация о текущей операции.
//  ДополнительныеПараметры - Произвольный - Необязательный. Любая дополнительная информация,
//      которую необходимо передать на клиент. Значение должно быть простым (сериализуемым в XML строку).
//
Процедура СообщитьПрогресс(Знач Процент = Неопределено, Знач Текст = Неопределено, Знач ДополнительныеПараметры = Неопределено) Экспорт
    
    ПередаваемоеЗначение = Новый Структура;
    Если Процент <> Неопределено Тогда
        ПередаваемоеЗначение.Вставить("Процент", Процент);
    КонецЕсли;
    Если Текст <> Неопределено Тогда
        ПередаваемоеЗначение.Вставить("Текст", Текст);
    КонецЕсли;
    Если ДополнительныеПараметры <> Неопределено Тогда
        ПередаваемоеЗначение.Вставить("ДополнительныеПараметры", ДополнительныеПараметры);
    КонецЕсли;
    
    ПередаваемыйТекст = ОбщегоНазначения.ЗначениеВСтрокуXML(ПередаваемоеЗначение);
    
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = ПередаваемыйТекст;
    Сообщение.Сообщить();
    
КонецПроцедуры

// Находит фоновое задание и считывает из его сообщений информацию о ходе выполнения.
//
// Возвращаемое значение:
//   Структура - Информация о ходе выполнения фонового задания.
//       Ключи и значения структуры соответствуют именам и значениям параметров процедуры СообщитьПрогресс().
//
Функция ПрочитатьПрогресс(Знач ИдентификаторЗадания) Экспорт
    Перем Результат;
    
    Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
    Если Задание = Неопределено Тогда
        Возврат Результат;
    КонецЕсли;
    
    МассивСообщений = Задание.ПолучитьСообщенияПользователю(Истина);
    Если МассивСообщений = Неопределено Тогда
        Возврат Результат;
    КонецЕсли;
    
    Количество = МассивСообщений.Количество();
    
    Для Номер = 1 По Количество Цикл
        ОбратныйИндекс = Количество - Номер;
        Сообщение = МассивСообщений[ОбратныйИндекс];
        
        Результат = ОбщегоНазначения.ЗначениеИзСтрокиXML(Сообщение.Текст);
        Прервать;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции
8 TormozIT
 
гуру
24.08.15
09:58
(4) (7) Проблема не в регистрации/отображении, а в асинхронном получении информации о прогрессе от MSSQL через ADODB
9 TormozIT
 
гуру
24.08.15
10:54
(6) Спасибо. Оказалось, что проблема с получением сообщений о прогрессе по ходу выполнения команды была из-за CursorLocation, который в моем случае был 3 (клиент), а нужно было 2 (сервер).
10 TormozIT
 
гуру
24.08.15
10:57
Похоже при асинхронном вызове Execute() все таки получать прогресс нельзя. При синхронном работает такой способ

            RS = Connection.Execute(ТекстЗапроса);
            Пока RS<>Неопределено Цикл
                Warning = Connection.Errors(0);
                Если Warning.NativeError=3211 Тогда
                    ТекстСообщения = Warning.Description;
                    ИндикаторВыполнения = Число(Лев(ТекстСообщения, Найти(ТекстСообщения, " ")-1));
                КонецЕсли;
                RS = RS.NextRecordset();
            КонецЦикла;
11 mistеr
 
24.08.15
11:00
Сомневаюсь, что можно дбиться желаемого через ADODB.
12 DmitrO
 
24.08.15
11:01
(10)при асинхронном надо через события работать
13 TormozIT
 
гуру
24.08.15
11:02
(12) Пробовал. Не помогает (1)
14 DmitrO
 
24.08.15
11:12
(13)а если ExecuteComplete обрабатывать, а не InfoMessage?
15 TormozIT
 
гуру
24.08.15
12:22
(14) Судя по описанию, должно получиться. Но пока сделал синхронно и с частыми обновлениями работает приемлемо.
16 Fram
 
24.08.15
12:29
(10) а при таком способе проц не грузит на 100%?
17 TormozIT
 
гуру
24.08.15
13:21
(16) Вызов NextRecordset ждет получения очередного результата (сообщения о прогрессе). Процессор он не грузит, т.к. это синхронный внешний вызов. Поэтому их будет столько, сколько сообщений с прогрессом выдаст сервер.
18 TormozIT
 
гуру
24.08.15
15:50
При расположении курсора на сервере выполнение Rd1.NextRecordSet закрывает Rd1. А мне нужно чтобы он оставался открытым. При расположении курсора на клиенте ADODB.COMMAND.Execute() сначала ждет получения всех recordset'ов и только потом возвращает управление.
19 Гёдза
 
24.08.15
15:51
(18) покажи конечный код
20 TormozIT
 
гуру
24.08.15
15:57
РезультатЗапроса = ОбъектЗапрос.Execute(); // Тут ждет последнего результата при CursorLocation = 3
    лРезультат = РезультатЗапроса;
    Пока лРезультат <> Неопределено Цикл
        РезультатЗапроса = лРезультат;
        Если СоединениеADO.Errors.Count > 0 Тогда
            Сообщение = СоединениеADO.Errors(0);
            Если Сообщение.NativeError = 3211 Тогда
                Сообщить(Сообщение.Description);
            КонецЕсли;
        КонецЕсли;
        лРезультат = РезультатЗапроса.NextRecordset(); // После выполнения этой строки при CursorLocation = 2 (сервер) объект в РезультатЗапроса закрывается
    КонецЦикла;
    КоличествоСтрок = РезультатЗапроса.RecordCount; // Тут ошибка при CursorLocation = 2
21 DmitrO
 
24.08.15
16:21
>>А мне нужно чтобы он оставался открытым.
>>КоличествоСтрок = РезультатЗапроса.RecordCount

Мы восстанавливаем/бекапим базу, количество каких строк (чорт побери) хочется узнать при этом? :)

RecordCount - это свойство доступно только при DML запросах (количество обработанных строк).

Клиентский курсор имеет смысл только для DSL запросах (select), и по сути при помощи библиотеки курсоров загружает в память все что вернул сервер и позволяет потом бегать туда сюда по выборке. Что на самом деле малоэффективная и малоприменимая штука (щас это уже никому не надо, ни кто не применяет).
22 DmitrO
 
24.08.15
16:24
DML это insert,update,delete
23 TormozIT
 
гуру
24.08.15
16:26
(21) У меня универсальная функция. Поэтому мне нужно обеспечить ее работу в большом числе ситуаций. Снижение ее универсальности повлечет обширные изменения.
24 TormozIT
 
гуру
24.08.15
16:35
В общем добавил в свою функцию параметр отвечающий за обновление прогресса вместе с выполнением NextRecordset, а получение последнего RecordSet для D*L запросов придется теперь делать снаружи этой функции.
Требовать и эффективности, и гибкости от одной и той же программы — все равно, что искать очаровательную и скромную жену... по-видимому, нам следует остановиться на чем-то одном из двух. Фредерик Брукс-младший