Загрузка Dbf-файла, 1С 7.7

BBDragon

Well-known member
04.05.2008
148
0
#1
В программе необходимо подгружать dbf-файл, содержащий порядка 400 000 записей. Сам файл содержит более 30 полей, из них загружается 21. Загрузку запустил в 05.07.2010г. в 15-40 по московскому времени, до сих пор она не завершена. Хотелось бы как-то оптимизировать алгоритм с целью увеличения быстродействия.

Код:
Процедура ВыборФайла()
КаталогЗагрузки = ""; 
ФайлЗагрузки = "";
Если ФС.ВыбратьФайл(1, ФайлЗагрузки, КаталогЗагрузки, "Выберите файл", "*.dbf|*.dbf", , ) = 1 Тогда
ФайлЗагрузки = КаталогЗагрузки + ФайлЗагрузки;	
КонецЕсли;
КонецПроцедуры	 

Процедура Сформировать() 
ИмФайл=СокрЛП(ФайлЗагрузки); 
ДБФ = СоздатьОбъект("XBase"); 
ДБФ.ОткрытьФайл(ИмФайл,,1);
ДБФ.Первая(); 
СпрПац = СоздатьОбъект("Справочник.Пациенты"); 
Пока ДБФ.ВКонце() = 0 Цикл 
Если (ДБФ.PR_IZM <> 2) Тогда // обрабатываем только неудаленные записи
СпрПац.Новый();
СпрПац.ФамилияПациента = СокрЛП(ДБФ.FAM); 
СпрПац.ИмяПациента= СокрЛП(ДБФ.IM);
СпрПац.ОтчествоПациента= СокрЛП(ДБФ.OT); 
Если СокрЛП(ДБФ.SEX)="1" Тогда
СпрПац.ПолПациента = "М"
Иначе СпрПац.ПолПациента = "Ж";
КонецЕсли;

СпрПац.ДатаРождения = СокрЛП(ДБФ.BIRTHDAY);
СпрПац.СерияНомерПолиса = СокрЛП(ДБФ.SERIES)+''+СокрЛП(ДБФ.NUMBER);
СпрПац.Регион = СокрЛП(ДБФ.REGION);
СпрПац.Район = СокрЛП(ДБФ.A_RN);
СпрПац.НасПункт = СокрЛП(ДБФ.A_NAS);
СпрПац.Улица = СокрЛП(ДБФ.A_STREET);
СпрПац.Дом = СокрЛП(ДБФ.A_DOM);
СпрПац.Корпус = СокрЛП(ДБФ.A_KORP);
СпрПац.Квартира = СокрЛП(ДБФ.A_KV);
СпрПац.Статус = СокрЛП(ДБФ.STATUS);
СпрПац.КодДокумента = СокрЛП(ДБФ.C_DOC);
СпрПац.СерияНомерДокумента = СокрЛП(ДБФ.SN_DOC);
СпрПац.РегионСтрахования = СокрЛП(ДБФ.REGIONS);
СпрПац.НомерДоговора = СокрЛП(ДБФ.N_DOG);
СпрПац.КодСМО = СокрЛП(ДБФ.KOD_SMO);
СпрПац.ДатаВыдачиПолиса = СокрЛП(ДБФ.DATE_VID); 

ДР=СокрЛП(ДБФ.DATE_OUT); 
ДатаСтрока = Формат(ДР, "ДДММГГГГ");
Если (ДатаГод(ДР)>1900) и (ДатаГод(ДР)<1950) Тогда // Загружена дата с 2001 по 2050 год
НоваяДата=Лев(ДатаСтрока,6) + "20" + Прав(ДатаСтрока,2); 
Иначе НоваяДата = ДатаСтрока; //обычная дата XX века
КонецЕсли;
СпрПац.ДатаОкончанияПолиса = НоваяДата;
СпрПац.ДатаИзмененияПолиса = СокрЛП(ДБФ.DATE_IZM);
СпрПац.Записать();

СпрПолис = СоздатьОбъект("Справочник.ПолисыСтраховыхКомпаний"); 
СпрПолисСерияНомер=СокрЛП(ДБФ.SERIES)+' '+СокрЛП(ДБФ.NUMBER);
Если СпрПолис.НайтиПоНаименованию(СпрПолисСерияНомер)=0 тогда	 
СпрПолис.Новый();
СпрПолис.СерииПолисов=СокрЛ(ДБФ.SERIES); 
СпрПолис.НачальныйНомерПолиса=СокрЛ(ДБФ.NUMBER); 
СпрПолис.Наименование=СокрЛ(ДБФ.SERIES)+' '+СокрЛ(ДБФ.NUMBER); 
СпрСтрах=СоздатьОбъект("Справочник.Контрагенты");
Если СпрСтрах.НайтиПоКоду(ДБФ.KOD_SMO)=0 тогда
СпрСтрах.Новый();
СпрСтрах.Код= СокрЛП(ДБФ.KOD_SMO);
СпрСтрах.Записать();
КонецЕсли;
СпрСтрахДок=СпрСтрах;
СпрПолис.СтраховаяКомпания=СпрСтрахДок.ТекущийЭлемент();
СпрПолис.Записать();
КонецЕсли;
ДБФ.Следующая();
КонецЕсли;
КонецЦикла;
Сообщить("Конец Загрузки");
ДБФ.ЗакрытьФайл(); 
КонецПроцедуры
 
H

Hryv

#2
Я с месяц назад делал тест
создавал 10.000 элементов справочника
пустых
это занимало в моей тестовой базе 30 минут

а у вас 400 - 800 тысяч элементов создается, кроме того другие действия

если, предположим, ваше железо в 5 раз быстрее моего, то все равно я бы прогнозировал, что не меньше чем сутки будет работать эта загрузка

ЗЫ можно было бы через каждые 1000 записей сообщение выдавать, хоть видно было бы чего ждать
 

vbs

Well-known member
18.02.2007
1 708
1
#3
ЗЫ можно было бы через каждые 1000 записей сообщение выдавать, хоть видно было бы чего ждать
А я бы вместо этого сообщения (или вместе с ним) предложил через 1000-10000 (число можно получить экспериментально) записей начинать - завершать транзакцию

Добавлено: И не могу удержаться от шпильки : скорость не бывает медленной (как и цена дешевой), она может быть НИЗКОЙ или ВЫСОКОЙ.
 

BBDragon

Well-known member
04.05.2008
148
0
#5
Всем спасибо за помощь!! Мне повезло и загрузка завершена спустя всего 18ч после начала :) Железо - Core 2 Duo E6750 @ 2,66 GhZ, RAM 2 Gb, XP SP2. Но вот незадача - вчера торопился к врачу, в спешке ткнул в списке выбора свою локальную базу, а не сетевую, с которой все работают. Хотелось бы избежать еще одной загрузки базы.. Ясное дело простым копированием файлов не обойтись, выгрузка и загрузка справочника займет также уйму времени. Что можно еще предпринять?
 

vbs

Well-known member
18.02.2007
1 708
1
#6
Ясное дело простым копированием файлов не обойтись, выгрузка и загрузка справочника займет также уйму времени
Если конфигурация одна и та же, что мешает тупо скопировать соответствующие файлы SC*.* ?
 

BBDragon

Well-known member
04.05.2008
148
0
#7
Если конфигурация одна и та же, что мешает тупо скопировать соответствующие файлы SC*.* ?
Уже пробовал, выдает "Нарушена структура данных таблицы SC30".
При поытке тестирования и исправления базы:

Таблица - SC30. Не сошлись типы полей номер 9(SP1306).
Проверка физической целостности таблиц ИБ. Неисправимая ошибка.
 

vbs

Well-known member
18.02.2007
1 708
1
#8
И еще о пользе транзакций.
Замечено, что 10 раз по 10000 читать из ДВФ-файла и писАть в справочник быстрее, чем один раз 100000.
Мне периодически приходится проделывать некие действия со справочником номенклатуры размером 50К через ДБФ-переходник, так что собственный опыт имею
 

vbs

Well-known member
18.02.2007
1 708
1
#10
А еще можно попробовать забивать гвозди микроскопом :)

Добавлено: К тому же
СпрПолис = СоздатьОбъект("Справочник.ПолисыСтраховыхКомпаний");
СпрСтрах=СоздатьОбъект("Справочник.Контрагенты");
совершенно незачем делать в цикле
 

vitfil

IT-интегратор
02.04.2004
2 062
0
#11
1. Создание объектов вынести за цикл.
2. Через каждые 100 строк фиксировать транзакцию (кстати, ускорение записи при использовании транзакций - это баг 7.7, ставший фичей).
А еще расскажите мне, как у вас вообще завершилась загрузка? Хотя, подозреваю, что просто всегда выполнялось условие...
Код:
Пока ДБФ.ВКонце() = 0 Цикл 
Если (ДБФ.PR_IZM <> 2) Тогда // обрабатываем только неудаленные записи
...
ДБФ.Следующая();
КонецЕсли;
КонецЦикла;
 

vbs

Well-known member
18.02.2007
1 708
1
#12
Через каждые 100 строк фиксировать транзакцию (кстати, ускорение записи при использовании транзакций - это баг 7.7, ставший фичей).
Когда фиксировать транзакцию, зависит, видимо, от железа.
У меня при фиксации через каждую тысячу все равно летает, так что обычно делаю через несколько тысяч
 

BBDragon

Well-known member
04.05.2008
148
0
#13
Поправил процедуру, поставил транзакцию через каждую тысячу - скорость фантастически возросла! По крайней мере 1500 записей загружает буквально за 3-4 секунды! Поставил на загрузку 400 000 записей, проверим, что получится в итоге)
Всем спасибо огромное за помощь :)))))
 

BBDragon

Well-known member
04.05.2008
148
0
#15
Спасибо, почитал)

Увы, загрузка работает некорректно(
Загружается только первая запись из файла, причем 31 раз, а далее больше ничего не грузится. Естественно, что обработка очень быстро завершает свою работу. Я вчера на радостях забыл проверить, что в итоге попадает в справочник, вот и попал впросак..

Код:
		ИмФайл=СокрЛП(ФайлЗагрузки); 
ДБФ = СоздатьОбъект("XBase"); 
ДБФ.ОткрытьФайл(ИмФайл,,1);
ДБФ.Первая(); 
СпрПац = СоздатьОбъект("Справочник.Пациенты"); 
СпрПолис = СоздатьОбъект("Справочник.ПолисыСтраховыхКомпаний"); 
СпрСтрах=СоздатьОбъект("Справочник.Контрагенты");  

НачатьТранзакцию();
Для k=1 по ДБФ.КоличествоЗаписей() Цикл 
// заполнение спрвочника
Если Цел(((k/1000)-Цел(k/1000))*k)=0 Тогда //фиксируем транзакцию, если K - кратно тысяче
ЗафиксироватьТранзакцию();
КонецЕсли;
НачатьТранзакцию();
КонецЦикла;	 
ЗафиксироватьТранзакцию();

Думаю, что проблема в моем условии проверки k на кратность тысяче, но не могу понять, что у меня за ошибка.. :)
Подскажите, пожалуйста, каким образом вы фиксируете транзакции через 1000 записей?
 

vitfil

IT-интегратор
02.04.2004
2 062
0
#16
Код:
КоличествоЗаписей = 0;
Пока ... Цикл
Если КоличествоЗаписей = 0 Тогда
НачатьТранзакцию();
КонецЕсли;
//что-то делаем

//что-то записываем
КоличествоЗаписей = КоличествоЗаписей + 1;

Если КоличествоЗаписей = 1000 Тогда
ЗафиксироватьТранзакцию();
КоличествоЗаписей = 0;
КонецЕсли;
КонецЦикла;
Если КоличествоЗаписей <> 0 Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
 
T

TimeDontWait

#17
Код:
сч=1000;
НачатьТранзакцию();
Для k=1 по ДБФ.КоличествоЗаписей() Цикл 
// заполнение спрвочника
Если к=сч Тогда //фиксируем транзакцию, если K - кратно тысяче
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;	 
ЗафиксироватьТранзакцию();
И обнулять счетчик
 

BBDragon

Well-known member
04.05.2008
148
0
#18
Код:
КоличествоЗаписей = 0;
Пока ... Цикл
Если КоличествоЗаписей = 0 Тогда
НачатьТранзакцию();
КонецЕсли;
//что-то делаем

//что-то записываем
КоличествоЗаписей = КоличествоЗаписей + 1;

Если КоличествоЗаписей = 1000 Тогда
ЗафиксироватьТранзакцию();
КоличествоЗаписей = 0;
КонецЕсли;
КонецЦикла;
Если КоличествоЗаписей <> 0 Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Вновь заносится только первая запись, но уже ровно столько раз, сколько записей в файле)

TimeDontWait, не совсем понял какой счетчик вы предлагаете обнулять?
 
T

TimeDontWait

#19
Код:
количество=1000;
сч=0;
НачатьТранзакцию();
Для k=1 по ДБФ.КоличествоЗаписей() Цикл 
сч=сч+1;
// заполнение спрвочника
Если количество=сч Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
сч=0;
КонецЕсли;
КонецЦикла;	 
ЗафиксироватьТранзакцию();