Имя: Пароль:
1C
1С v8
Оптимизация кода
0 Rumpil
 
20.02.12
09:50
Доброе утро, господа. У меня существует файл с ценами в формате  
Excel, 156 тысяч строк, в этом файле так получилось что есть какое то количество записей-дубликатов. Соответственно при загрузке в 1С и создании документа "Установка цен номенклатуры контрагентов" я должен не только искать такой товар в базе 1с, но и после нахождения его прежде чем добавить его в табличную часть моего документа я должен проверять не был ли он уже посажен ранее в эту табличную часть. Код под эту задачу написал, но он дико весит - за 15 часов он обработал только около 20 тысяч строк. МОжет подскажете как можно оптимизировать код ?


   Попытка        
       гл_appExcel = Новый COMObject("Excel.Application");        
   Исключение        
       Сообщить(ОписаниеОшибки());
       Возврат;        
   КонецПопытки;
   
   exWorkBook = гл_appExcel.Workbooks.Open(Файлы);    
   RangeAll = exWorkBook.ActiveSheet.UsedRange;
   
   если СтрокиС = 0 тогда
       СтрокиС=1;
   КонецЕсли;    

   
   ДокОбъект                                  = Документы.УстановкаЦенНоменклатурыКонтрагентов.СоздатьДокумент();
   ДокОбъект.Дата                          = ТекущаяДата();
   
   ДокОбъект.Контрагент                    = Справочники.Контрагенты.Вендор;
   ТипЦен = ДокОбъект.ТипыЦен.Добавить();
   ТипЦен.ТипЦен = ВыбраннаяЦена;
   ДокОбъект.Ответственный                = УправлениеПользователями.ПолучитьЗначениеПоУмолчанию(ПараметрыСеанса.ТекущийПользователь, "ОсновнойОтветственный");                    
   

   
   
   Для НомерСтроки = СтрокиС По СтрокиПо Цикл
       ОбработкаПрерыванияПользователя();
       ПрописьюШтрихкод =  Формат(RangeAll.Cells(НомерСтроки, 1 ).Value, "ЧГ=0");
       ПрописьюМодель = RangeAll.Cells(НомерСтроки, 2 ).Value;
       ПрописьюНаименование = RangeAll.Cells(НомерСтроки, 4 ).Value;
       ПрописьюСебестоимость = RangeAll.Cells(НомерСтроки, 8 ).Value;
       
       //Товар = Справочники.Номенклатура.ПустаяСсылка();
       //Товар = Справочники.Номенклатура.НайтиПоНаименованию(ПрописьюНаименование,Истина);
       
       Товар = "";    
       Артикул = Сред(ПрописьюШтрихкод,1,16);
       
       Запрос = Новый Запрос;
       Запрос.Текст =
       "ВЫБРАТЬ
       |    Номенклатура.Ссылка
       |ИЗ
       |    Справочник.Номенклатура КАК Номенклатура
       |ГДЕ
       |    Номенклатура.Наименование = &ТекНом
       |    И Номенклатура.Модели.Наименование = &ТекМод
       |    И Номенклатура.Артикул = &ТекАрт";
       Запрос.УстановитьПараметр("ТекАрт", Артикул);
       Запрос.УстановитьПараметр("ТекНом", ПрописьюНаименование);
       Запрос.УстановитьПараметр("ТекМод", ПрописьюМодель);
       
       Результат = Запрос.Выполнить();
       Выборка = Результат.Выбрать();
       Пока Выборка.Следующий() Цикл        
           Товар = Выборка.Ссылка;    
       КонецЦикла;

       
       
       если НЕ ЗначениеЗаполнено(Товар) Тогда
           
           Сообщить("Товар "+ ПрописьюНаименование +" не найден в базе и не загружена себестоимость.",СтатусСообщения.Информация);
           
       КонецЕсли;
       
       если ЗначениеЗаполнено(Товар) Тогда
           ИскомыйТовар = Новый Структура;
           ИскомыйТовар.Вставить("Номенклатура", Товар);
           РезультатПоиска = ДокОбъект.Товары.НайтиСтроки(ИскомыйТовар);
           
           Если РезультатПоиска.Количество() = 0 Тогда  
               
               Если ПрописьюСебестоимость = Неопределено Тогда
                   Сообщить("Цена на товар "+ ПрописьюНаименование +" не заполнена в файле Excel",СтатусСообщения.Информация);
               Иначе
                   НоваяСтрока                    = ДокОбъект.Товары.Добавить();
                   НоваяСтрока.Номенклатура          = Товар;
                   НоваяСтрока.ЕдиницаИзмерения    = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("?d");
                   НоваяСтрока.Валюта                = ВыбраннаяЦена.ВалютаЦены;
                   НоваяСтрока.ТипЦен              = ВыбраннаяЦена;
                   НоваяСтрока.Цена                    = ПрописьюСебестоимость;
                   ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
               КонецЕсли;
           КонецЕсли;
       КонецЕсли;            
       
   КонецЦикла;    
   
   exWorkBook.Close( Ложь );
   
   гл_appExcel.Workbooks.Close( );
1 Dirk Diggler
 
20.02.12
09:56
загрузить все в ТЗ, запросом выбрать и свернуть её из временной таблицы.
2 Rumpil
 
20.02.12
09:57
(1) о, идея, спасиб, сейчас попробую
3 Steel_Wheel
 
20.02.12
09:57
Это ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

вытащи из цикла, записывай только на каждую 1000-ую строку
4 Steel_Wheel
 
20.02.12
09:57
ты изнасиловал свою БД )
5 artems
 
20.02.12
10:07
+(4) в особо извращенной форме ))
6 decdmb
 
20.02.12
10:18
+ загружать не через COM, а через ADO.
7 Rumpil
 
20.02.12
10:30
Переписал код, не сказать что все полетелело, но пошустрее вроде заработал:

   Попытка        
       гл_appExcel = Новый COMObject("Excel.Application");        
   Исключение        
       Сообщить(ОписаниеОшибки());
       Возврат;        
   КонецПопытки;
   
   exWorkBook = гл_appExcel.Workbooks.Open(Файлы);    
   RangeAll = exWorkBook.ActiveSheet.UsedRange;
   
   если СтрокиС = 0 тогда
       СтрокиС=1;
   КонецЕсли;    
   
   
   
   ДокОбъект                                  = Документы.УстановкаЦенНоменклатурыКонтрагентов.СоздатьДокумент();
   ДокОбъект.Дата                          = ТекущаяДата();
   //ДокОбъект.Организация                    = УправлениеПользователями.ПолучитьЗначениеПоУмолчанию(ПараметрыСеанса.ТекущийПользователь, "ОсновнаяОрганизация");
   ДокОбъект.Контрагент                    = Справочники.Контрагенты.Вендор;
   ТипЦен = ДокОбъект.ТипыЦен.Добавить();
   ТипЦен.ТипЦен = ВыбраннаяЦена;
   ДокОбъект.Ответственный                = УправлениеПользователями.ПолучитьЗначениеПоУмолчанию(ПараметрыСеанса.ТекущийПользователь, "ОсновнойОтветственный");                    
       ОбработкаПрерыванияПользователя();

       Таблица = Новый ТаблицаЗначений;
       Таблица.Колонки.Добавить("ПрописьюШтрихкод",Новый ОписаниеТипов("Строка"));
       Таблица.Колонки.Добавить("ПрописьюМодель",Новый ОписаниеТипов("Строка"));
       Таблица.Колонки.Добавить("ПрописьюНаименование",Новый ОписаниеТипов("Строка"));
       Таблица.Колонки.Добавить("ПрописьюСебестоимость",Новый ОписаниеТипов("Число"));
       
       Для НомерСтроки = СтрокиС По СтрокиПо Цикл
           
           НоваяСтр = Таблица.Добавить();
           
           НоваяСтр.ПрописьюШтрихкод =  Формат(RangeAll.Cells(НомерСтроки, 1 ).Value, "ЧГ=0");
           НоваяСтр.ПрописьюМодель = RangeAll.Cells(НомерСтроки, 2 ).Value;
           НоваяСтр.ПрописьюНаименование = RangeAll.Cells(НомерСтроки, 4 ).Value;
           НоваяСтр.ПрописьюСебестоимость = RangeAll.Cells(НомерСтроки, 8 ).Value;
       КонецЦикла;
   
   
   
   Для каждого Стр из  Таблица Цикл

           
       Товар = "";    
       Артикул = Сред(Стр.ПрописьюШтрихкод,1,16);
       
       Запрос = Новый Запрос;
       Запрос.Текст =
       "ВЫБРАТЬ
       |    Номенклатура.Ссылка
       |ИЗ
       |    Справочник.Номенклатура КАК Номенклатура
       |ГДЕ
       |    Номенклатура.Наименование = &ТекНом
       |    И Номенклатура.Модели.Наименование = &ТекМод
       |    И Номенклатура.Артикул = &ТекАрт";
       Запрос.УстановитьПараметр("ТекАрт", Артикул);
       Запрос.УстановитьПараметр("ТекНом", Стр.ПрописьюНаименование);
       Запрос.УстановитьПараметр("ТекМод", Стр.ПрописьюМодель);
       
       Результат = Запрос.Выполнить();
       Выборка = Результат.Выбрать();
       Пока Выборка.Следующий() Цикл        
           Товар = Выборка.Ссылка;    
       КонецЦикла;

       
       
       если НЕ ЗначениеЗаполнено(Товар) Тогда
           
           Сообщить("Товар "+ Стр.ПрописьюНаименование +" не найден в базе и не загружена себестоимость.",СтатусСообщения.Информация);
           
       КонецЕсли;
       
       если ЗначениеЗаполнено(Товар) Тогда
           ИскомыйТовар = Новый Структура;
           ИскомыйТовар.Вставить("Номенклатура", Товар);
           РезультатПоиска = ДокОбъект.Товары.НайтиСтроки(ИскомыйТовар);
           
           Если РезультатПоиска.Количество() = 0 Тогда  
               
               Если Стр.ПрописьюСебестоимость = 0 Тогда
                   Сообщить("Цена на товар "+ Стр.ПрописьюНаименование +" не заполнена в файле Excel",СтатусСообщения.Информация);
               Иначе
                   НоваяСтрока                    = ДокОбъект.Товары.Добавить();
                   НоваяСтрока.Номенклатура          = Товар;
                   НоваяСтрока.ЕдиницаИзмерения    = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("?d");
                   НоваяСтрока.Валюта                = ВыбраннаяЦена.ВалютаЦены;
                   НоваяСтрока.ТипЦен              = ВыбраннаяЦена;
                   НоваяСтрока.Цена                    = Стр.ПрописьюСебестоимость;
               Сообщить("Добавлена цена на товар "+ Стр.ПрописьюНаименование +", цена - " + Стр.ПрописьюСебестоимость,СтатусСообщения.Информация);
   
               КонецЕсли;
           КонецЕсли;
       КонецЕсли;            
       
   КонецЦикла;    
   
   ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

   
   exWorkBook.Close( Ложь );
   
   гл_appExcel.Workbooks.Close( );
8 DrShad
 
20.02.12
10:35
Сообщить() убери оно тоже сильно тормозит
9 DrShad
 
20.02.12
10:36
(6) +100500
10 Rumpil
 
20.02.12
10:37
(8) ок
11 Maxus43
 
20.02.12
10:40
запросом к ёкселю шустрей ж будет
12 DrShad
 
20.02.12
10:40
(10) лучше создавай Текст в качестве лога и потом выводи его в конце в Поле на форме и записывай соответственно
13 Rumpil
 
20.02.12
11:08
сделал через йоксель, вроде скорость полета хорошая
14 Лефмихалыч
 
20.02.12
11:25
спасибо, поржал

1. Запрос из цикла вынеси, замени на временную таблицу и соединение с номенклатурой
2. Либо в запрос воткни Первые 1, либо в цикл обхода выборки воткни Прервать
3. Вот это "РезультатПоиска = ДокОбъект.Товары.НайтиСтроки(ИскомыйТовар);" выкоси наиух, замени на запрос. Нормализуй источник, чтобы дублей не было, тогда не потребуется эта проверка
4. Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("?d"); вынеси из цикла вообще, зачем это каждый раз заново находить?
5. К экселю запросом через АДО обращайся

А в целом - да отсохнут руки, написавшие это
15 DexterMorgan
 
20.02.12
11:29
(14) <А в целом - да отсохнут руки, написавшие это>
А в целом - да отсохнут руки, написавшие это
16 ЧеловекДуши
 
20.02.12
11:31
Грузи через АДО, быстрее
17 ЧеловекДуши
 
20.02.12
11:33
+(14) +100500 :)
18 Rumpil
 
20.02.12
11:46
(14) а через АДо как сделать ?
19 decdmb
 
20.02.12
12:04