1. user1296699 17.10.19 14:50 Сейчас в теме

ПОМОГИТЕ!!! Загрузка DBF более 120 млн. строк

Добрый день. Подскажите новичку. Пишу обработку. Нужно сравнить файл ДБФ (размер 1.4 гб более 120 млн. строк) с данными из базы. Сравнение сделал все в порядке все работает но с маленьким файлом.
Вопрос как загрузить огромный ДБФ... пробовал в массив 1с пишет "недостаточно памяти", пробовал в ТЗ аналогично "Недостаточно памяти". Деление на части не подходит т.к. обрабатывает всего 3 млн. строк, а это 40 файлов ДБФ. Что делать???
Найденные решения
14. Sashares 18 17.10.19 16:20 Сейчас в теме
(13) Поправить процедуру ЗагрузитьДанныеИзФайла
Добавить реквизит номер записи и размер партии на форму.
Так будет читаться партия записей.
Потом вызывайте ваши остальные процедуры и сравнивайте с партией.

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

Если ЗначениеЗаполнено(НомерЗаписи) Тогда
ФайлDBF.Перейти(НомерЗаписи);
Иначе
ФайлDBF.Первая();
КонецЕсли; //не первую ставить, а номер записи с которой читать.

Реквизит1.Очистить();

КоличествоПрочитано = 0;

Пока НЕ ФайлDBF.ВКонце() Цикл

НоваяСтрока = Реквизит1.Добавить();
НоваяСтрока.СерияНомер = СокрЛП(СтрЗаменить(ФайлDBF.Series + "," + ФайлDBF.Number,"",""));

ФайлDBF.Следующая(); //передвигаем курсор далее

КоличествоПрочитано = КоличествоПрочитано +1;

Если КоличествоПрочитано >= РазмерПартии Тогда
Прервать;
КонецЦикла;

КонецЦикла;

НомерЗаписи = ФайлDBF.НомерЗаписи() ;

ФайлDBF.ЗакрытьФайл(); 
Показать
Остальные ответы
Избранное Подписка Сортировка: Древо
3. Sashares 18 17.10.19 14:56 Сейчас в теме
(1) А почему не подходит разделение на части?
Разделить файл части, пусть даже на 40.
Потом последовательно их сравнить.

В той же обработке можно - взял диапазон строк - прочитал - сравнил, взял следующий диапазон.
16. AlexandrSmith 46 17.10.19 22:12 Сейчас в теме
(1) Да DBF 4.0 поддерживает большие объемы данных как и DBF 1С 7.7.

Запихни в таблицу на SQL Server, а не через 1С

Но это долго объяснять, если понял о чем я, то сделаешь.

Если не понял, тогда не судьба тебе.

И так проходит жизнь!!!
2. nomad_irk 41 17.10.19 14:56 Сейчас в теме
Читать файл частями и проверять, по другому - никак. По 100к записей за одну итерацию сравнения.
6. user1296699 17.10.19 15:00 Сейчас в теме
(2) (3) еще проблемка я просто не знаю как прочитать частями последовательно(моя первая обработка) :-)
7. Sashares 18 17.10.19 15:03 Сейчас в теме
(6)Читать как сейчас пока количество прочитанных записей не будет больше 100к (условно).
Запомнить номер записи, на которой остановилось чтение.

XBase (XBase)
НомерЗаписи (RecNo)
Синтаксис:

НомерЗаписи()
Возвращаемое значение:

Тип: Число.
Номер текущей записи.
Описание:

Получает физический порядковый номер текущей записи в таблице базы данных, начиная с единицы. Результат не зависит от установки текущего индекса.
Показать


При следующем чтении начать чтение с нужной записи.

XBase (XBase)
Перейти (GoTo)
Синтаксис:

Перейти(<НомерЗаписи>)
Параметры:

<НомерЗаписи> (обязательный)

Тип: Число.
Физический порядковый номер записи в базе данных.
Возвращаемое значение:

Тип: Булево.
Истина - получена искомая запись; Ложь - в противном случае.
Описание:

Переходит на запись по ее физическому порядковому номеру в таблице базы данных.
Показать
9. nomad_irk 41 17.10.19 15:06 Сейчас в теме
(7)XBASE даже можно не закрывать/открывать - доступ к данным и так последовательный, т.е. весь файл в ОЗУ не загружается.
10. user1296699 17.10.19 15:35 Сейчас в теме
(7) Спасибо.Попробую. Только я не понял а как мне остановить чтение на 100k
12. Sashares 18 17.10.19 15:43 Сейчас в теме
(10)Выложите код обработки, будет проще советовать =)
13. user1296699 17.10.19 15:57 Сейчас в теме
(12) Вот рабочий вариант только с маленьким файлом

&НаСервере	
Процедура Сравнение()
	
		КС = Новый КвалификаторыСтроки(200);
Массив = Новый Массив;
Массив.Добавить(Тип("Строка"));
ОписаниеТиповС = Новый ОписаниеТипов(Массив, ,КС );

Массив.Очистить();

ПаспортФайл = Новый ТаблицаЗначений;

ПаспортФайл.Колонки.Добавить("СерияНомер",ОписаниеТиповС,"СерияНомер",11);

n1=1;
Для каждого СтрТаб из Реквизит1 Цикл
 
       НоваяСтрока = ПаспортФайл.Добавить();   
       НоваяСтрока.СерияНомер = СтрТаб.СерияНомер;
	 
    n1=n1+1; 
	   
КонецЦикла;

Паспорт1С = Новый ТаблицаЗначений;

Паспорт1С.Колонки.Добавить("СерияНомер",ОписаниеТиповС,"СерияНомер",11);
Паспорт1С.Колонки.Добавить("ЛицевойСчет",ОписаниеТиповС,"ЛицевойСчет",9);
Паспорт1С.Колонки.Добавить("ФИО",ОписаниеТиповС,"ФИО",60);

n2=1;
Для каждого СтрТаб из Реквизит2 Цикл
 
       НоваяСтрока = Паспорт1С.Добавить();   
       НоваяСтрока.СерияНомер = СтрТаб.СерияНомер;
	   НоваяСтрока.ЛицевойСчет = СтрТаб.ЛицевойСчет;
	   НоваяСтрока.ФИО = СтрТаб.ФИО;
	  n2=n2+1;
	      	   
КонецЦикла;
                               
	Запрос = новый запрос;
Запрос.УстановитьПараметр("ПаспортФайл",ПаспортФайл);
Запрос.УстановитьПараметр("Паспорт1С",Паспорт1С);
	
Запрос.Текст ="ВЫБРАТЬ
              |	ПаспортФайл.СерияНомер КАК СерияНомер
              |ПОМЕСТИТЬ Файл
              |ИЗ
              |	&ПаспортФайл КАК ПаспортФайл
              |;
              |
              |////////////////////////////////////////////////////////////­////////////////////
              |ВЫБРАТЬ
              |	Паспорт1С.СерияНомер КАК СерияНомер,
              |	Паспорт1С.ЛицевойСчет КАК ЛицевойСчет,
              |	Паспорт1С.ФИО КАК ФИО
              |ПОМЕСТИТЬ База
              |ИЗ
              |	&Паспорт1С КАК Паспорт1С
              |;
              |
              |////////////////////////////////////////////////////////////­////////////////////
              |ВЫБРАТЬ
              |	Файл.СерияНомер КАК СерияНомер1,
              |	База.СерияНомер КАК СерияНомер,
              |	База.ЛицевойСчет КАК ЛицевойСчет,
              |	База.ФИО КАК ФИО
              |ИЗ
              |	База КАК База
              |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Файл КАК Файл
              |		ПО База.СерияНомер = Файл.СерияНомер
              |
              |УПОРЯДОЧИТЬ ПО
              |	ЛицевойСчет";

 Реквизит3.Очистить();

Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл
             
	    НоваяСтрока =  Реквизит3.Добавить();
        НоваяСтрока.СерияНомер = СтрЗаменить(Результат.СерияНомер," ","");
		НоваяСтрока.ЛицевойСчет = СтрЗаменить(Результат.ЛицевойСчет," ","");
		НоваяСтрока.ФИО = Результат.ФИО;

		
	 КонецЦикла;

		
		         
	
			              		
	  	// НоваяСтрока =  Реквизит3.Добавить();
      //  НоваяСтрока.СерияНомер = СтрЗаменить(Результат.СерияНомер," ","");
     //   НоваяСтрока.ДокументНомер  = СтрЗаменить(Результат.ДокументНомер," ","");
     //   НоваяСтрока.ЛицевойСчет = СтрЗаменить(Результат.ЛицевойСчет," ","");
	//	НоваяСтрока.ФИО = Результат.ФИО;

		
	КонецПроцедуры
		
	 
&НаСервере
Процедура ВыбратьМодели1С()
	
	
	
Запрос = новый запрос;
   	Запрос.Текст = "ВЫБРАТЬ
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументСерия КАК ДокументСерия,
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументНомер КАК ДокументНомер,
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ФизЛицо КАК ФизЛицо,
   	               |	Абоненты.ЛицевойСчет КАК ЛицевойСчет,
   	               |	Абоненты.Ссылка КАК ФИО,
   	               |	Абоненты.Подразделения КАК Подразделения,
   	               |	Абоненты.СостояниеЛС КАК СостояниеЛС
   	               |ИЗ
   	               |	Справочник.Абоненты КАК Абоненты
   	               |		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПаспортныеДанныеФизЛиц.СрезПоследних КАК ПаспортныеДанныеФизЛицСрезПоследних
   	               |		ПО Абоненты.ВладелецЛС = ПаспортныеДанныеФизЛицСрезПоследних.ФизЛицо
   	               |ГДЕ
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументСерия <> """"
   	               |	И Абоненты.ЛицевойСчет <> """"
   	               |	И Абоненты.Предопределенный = ЛОЖЬ
   	               |	И Абоненты.Подразделения = &Подразделения
   	               |	И НЕ Абоненты.ПометкаУдаления
   	               |	И Абоненты.СостояниеЛС = &СостояниеЛС
   	               |
   	               |УПОРЯДОЧИТЬ ПО
   	               |	ЛицевойСчет";
	
     Запрос.УстановитьПараметр("Подразделения", УчастокВыбор.Ссылка);
     Запрос.УстановитьПараметр("СостояниеЛС", Реквизит5);
                Реквизит2.Очистить();
     			
        Результат = Запрос.Выполнить().Выбрать();
		                                                         
	 Пока Результат.Следующий() Цикл
            	    НоваяСтрока =  Реквизит2.Добавить();
		  НоваяСтрока.ФИО = Результат.ФИО;
        НоваяСтрока.ПодразделениеАбонента = Результат.Подразделения;
       // НоваяСтрока.ДокументНомер  = СтрЗаменить(Результат.ДокументНомер," ","");
        НоваяСтрока.ЛицевойСчет = СтрЗаменить(Результат.ЛицевойСчет," ","");
		НоваяСтрока.СерияНомер = СтрЗаменить(СокрЛП(Результат.ДокументСерия) + "," + СокрЛП(Результат.ДокументНомер)," ","");	
				
	КонецЦикла;
	         

	КонецПроцедуры
	

&НаКлиенте 
Процедура ЗагрузитьДанныеИзФайла()
	
	 ПутьКФайлу = Реквизит4;
	     Реквизит1.Очистить();

	           
ФайлDBF = Новый XBase; // создаем новый объект
ФайлDBF.ОткрытьФайл(ПутьКФайлу,,Истина); 
ФайлDBF.Первая(); 



Пока НЕ ФайлDBF.ВКонце() Цикл
	 
	НоваяСтрока =  Реквизит1.Добавить();
   	 НоваяСтрока.СерияНомер = СокрЛП(СтрЗаменить(ФайлDBF.Series + "," + ФайлDBF.Number,"",""));
	
ФайлDBF.Следующая(); //передвигаем курсор далее
КонецЦикла;

ФайлDBF.ЗакрытьФайл();



    
КонецПроцедуры
Показать
14. Sashares 18 17.10.19 16:20 Сейчас в теме
(13) Поправить процедуру ЗагрузитьДанныеИзФайла
Добавить реквизит номер записи и размер партии на форму.
Так будет читаться партия записей.
Потом вызывайте ваши остальные процедуры и сравнивайте с партией.

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

Если ЗначениеЗаполнено(НомерЗаписи) Тогда
ФайлDBF.Перейти(НомерЗаписи);
Иначе
ФайлDBF.Первая();
КонецЕсли; //не первую ставить, а номер записи с которой читать.

Реквизит1.Очистить();

КоличествоПрочитано = 0;

Пока НЕ ФайлDBF.ВКонце() Цикл

НоваяСтрока = Реквизит1.Добавить();
НоваяСтрока.СерияНомер = СокрЛП(СтрЗаменить(ФайлDBF.Series + "," + ФайлDBF.Number,"",""));

ФайлDBF.Следующая(); //передвигаем курсор далее

КоличествоПрочитано = КоличествоПрочитано +1;

Если КоличествоПрочитано >= РазмерПартии Тогда
Прервать;
КонецЦикла;

КонецЦикла;

НомерЗаписи = ФайлDBF.НомерЗаписи() ;

ФайлDBF.ЗакрытьФайл(); 
Показать
15. user1296699 17.10.19 16:29 Сейчас в теме
(14) Рабочий день заканчивается. Завтра попробую. Спасибо)
19. user1296699 18.10.19 08:42 Сейчас в теме
(14) Спасибо за помощь... Дальше сам))
8. nomad_irk 41 17.10.19 15:04 Сейчас в теме
(6)
1. Организовать счетчик "полученных" из DBF файла строк.
2. Когда счетчик сравнялся с заданным значением, отправляем полученную ТЗ на проверку.
3. По результатам проверки что-то делаем.
4. Обнуляем счетчик "полученных" из DBF файла строк. Создаем пустую ТЗ.
5. Набиваем следующую порцию строк из DBF и возвращаемся на п. 2
4. acanta 74 17.10.19 14:57 Сейчас в теме
Как вариант в базу добавить объект типа регистр сведений (или несколько), перенести данные из дбф файлов полностью в регистр сведений и сравнить внутри одной базы данных запросами.
17. Dnki 4 17.10.19 22:47 Сейчас в теме
Вы меня простите за критику, это так отразился текст программы? Или он в самом деле такой корявый?
С лишними пустыми строками, нелепыми отступами.

Вот непонятны излишние манипуляции с "Паспорт1С".
- Собрал из РегистрСведений.ПаспортныеДанныеФизЛиц в ТЗ. (взял кусок памяти)
- ТЗ поместил в Запрос (полагаю, разместил в памяти еще одну копию)
- Потом Запрос сравнил (может и быстро, т.к. данные в памяти, но, каков ее расход!)

Раз большие данные, то все делать только в базе! А СУБД с ними справится.
Как писал (4) acanta:
- переписать DBF в регистр (я бы-в справочник)
- может проиндексировать по полям сравнения ("СерияНомер" ...) для скорости
здесь можно прервать задание (т.к. "Рабочий день заканчивается")
- совсем другой обработкой (хоть Консолью) сделать Запрос на сравнение.
Именно принципиально, что есть возможность разорвать работу на 2 части. Лучше добиваться результата поэтапно.
5. platonov.e 68 17.10.19 14:57 Сейчас в теме
40 файлов и несколько потоков)
11. deGreese 17.10.19 15:36 Сейчас в теме
В конце концов всегда можно воспользоваться Native API :)
18. SlavaKron 18.10.19 07:55 Сейчас в теме
В качестве бреда, прочитать файл с помощью функций работы с двоичными данными, благо, формат дбф - очень простой и размер строк данных, насколько помню — фиксированный.
20. user1296699 18.10.19 13:22 Сейчас в теме
Ребят...все работает... но я не понимаю почему грузит всю память на сервере... попробовал реквизит 3 очистить но все равно...мне кажется что все-таки что-то не так с процедурой ЗагрузитьДанныеИзФайла()

Процедура Сравнение()
КС = Новый КвалификаторыСтроки(200);
Массив = Новый Массив;
Массив.Добавить(Тип("Строка"));
ОписаниеТиповС = Новый ОписаниеТипов(Массив, ,КС );

Массив.Очистить();

ПаспортФайл = Новый ТаблицаЗначений;

ПаспортФайл.Колонки.Добавить("СерияНомер",ОписаниеТиповС,"СерияНомер",11);
n1=1;
Для каждого СтрТаб из Реквизит1 Цикл
 
НоваяСтрока = ПаспортФайл.Добавить();   
НоваяСтрока.СерияНомер = СтрТаб.СерияНомер;
n1=n1+1; 
	   
КонецЦикла;

Паспорт1С = Новый ТаблицаЗначений;

Паспорт1С.Колонки.Добавить("СерияНомер",ОписаниеТиповС,"СерияНомер",11);
Паспорт1С.Колонки.Добавить("ЛицевойСчет",ОписаниеТиповС,"ЛицевойСчет",9);
Паспорт1С.Колонки.Добавить("ФИО",ОписаниеТиповС,"ФИО",60);

n2=1;
Для каждого СтрТаб из Реквизит2 Цикл
 
НоваяСтрока = Паспорт1С.Добавить();   
НоваяСтрока.СерияНомер = СтрТаб.СерияНомер;
НоваяСтрока.ЛицевойСчет = СтрТаб.ЛицевойСчет;
НоваяСтрока.ФИО = СтрТаб.ФИО;
n2=n2+1;
	      	   
КонецЦикла;
                               
Запрос = новый запрос;
Запрос.УстановитьПараметр("ПаспортФайл",ПаспортФайл);
Запрос.УстановитьПараметр("Паспорт1С",Паспорт1С);
Запрос.Текст ="ВЫБРАТЬ
              |	ПаспортФайл.СерияНомер КАК СерияНомер
              |ПОМЕСТИТЬ Файл
              |ИЗ
              |	&ПаспортФайл КАК ПаспортФайл
              |;
              |
              |////////////////////////////////////////////////////////////­////////////////////
              |ВЫБРАТЬ
              |	Паспорт1С.СерияНомер КАК СерияНомер,
              |	Паспорт1С.ЛицевойСчет КАК ЛицевойСчет,
              |	Паспорт1С.ФИО КАК ФИО
              |ПОМЕСТИТЬ База
              |ИЗ
              |	&Паспорт1С КАК Паспорт1С
              |;
              |
              |////////////////////////////////////////////////////////////­////////////////////
              |ВЫБРАТЬ
              |	Файл.СерияНомер КАК СерияНомер1,
              |	База.СерияНомер КАК СерияНомер,
              |	База.ЛицевойСчет КАК ЛицевойСчет,
              |	База.ФИО КАК ФИО
              |ИЗ
              |	База КАК База
              |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Файл КАК Файл
              |		ПО База.СерияНомер = Файл.СерияНомер
              |
              |УПОРЯДОЧИТЬ ПО
              |	ЛицевойСчет";

Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл
             
НоваяСтрока =  Реквизит3.Добавить();
НоваяСтрока.СерияНомер = СтрЗаменить(Результат.СерияНомер," ","");
НоваяСтрока.ЛицевойСчет = СтрЗаменить(Результат.ЛицевойСчет," ","");
НоваяСтрока.ФИО = Результат.ФИО;
		
КонецЦикла;

Реквизит6 = Реквизит3.Скопировать("ЛицевойСчет,ФИО,СерияНомер");
Реквизит3.Очистить();

КонецПроцедуры
		
	 
&НаСервере
Процедура ВыбратьМодели1С()
	
Запрос = новый запрос;
   	Запрос.Текст = "ВЫБРАТЬ
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументСерия КАК ДокументСерия,
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументНомер КАК ДокументНомер,
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ФизЛицо КАК ФизЛицо,
   	               |	Абоненты.ЛицевойСчет КАК ЛицевойСчет,
   	               |	Абоненты.Ссылка КАК ФИО,
   	               |	Абоненты.Подразделения КАК Подразделения,
   	               |	Абоненты.СостояниеЛС КАК СостояниеЛС
   	               |ИЗ
   	               |	Справочник.Абоненты КАК Абоненты
   	               |		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПаспортныеДанныеФизЛиц.СрезПоследних КАК ПаспортныеДанныеФизЛицСрезПоследних
   	               |		ПО Абоненты.ВладелецЛС = ПаспортныеДанныеФизЛицСрезПоследних.ФизЛицо
   	               |ГДЕ
   	               |	ПаспортныеДанныеФизЛицСрезПоследних.ДокументСерия <> """"
   	               |	И Абоненты.ЛицевойСчет <> """"
   	               |	И Абоненты.Предопределенный = ЛОЖЬ
   	               |	И Абоненты.Подразделения = &Подразделения
   	               |	И НЕ Абоненты.ПометкаУдаления
   	               |	И Абоненты.СостояниеЛС = &СостояниеЛС
   	               |
   	               |УПОРЯДОЧИТЬ ПО
   	               |	ЛицевойСчет";
	
     Запрос.УстановитьПараметр("Подразделения", УчастокВыбор.Ссылка);
     Запрос.УстановитьПараметр("СостояниеЛС", Реквизит5);
     Реквизит2.Очистить();
     			
     Результат = Запрос.Выполнить().Выбрать();
		                                                         
	 Пока Результат.Следующий() Цикл
        НоваяСтрока =  Реквизит2.Добавить();
		НоваяСтрока.ФИО = Результат.ФИО;
        НоваяСтрока.ПодразделениеАбонента = Результат.Подразделения;
        НоваяСтрока.ЛицевойСчет = СтрЗаменить(Результат.ЛицевойСчет," ","");
		НоваяСтрока.СерияНомер = СтрЗаменить(СокрЛП(Результат.ДокументСерия) + "," + СокрЛП(Результат.ДокументНомер)," ","");	
				
	КонецЦикла;
	
	КонецПроцедуры
	

&НаКлиенте 
Процедура ЗагрузитьДанныеИзФайла()
	
ПутьКФайлу = Реквизит4;
ВыбратьМодели1С();
          
ФайлDBF = Новый XBase; // создаем новый объект
ФайлDBF.ОткрытьФайл(ПутьКФайлу,,Истина); 

Если ЗначениеЗаполнено(НомерЗаписи) Тогда
ФайлDBF.Перейти(НомерЗаписи);
Иначе
ФайлDBF.Первая();
КонецЕсли; 

Реквизит1.Очистить();

КоличествоПрочитано = 0;

Пока НЕ ФайлDBF.ВКонце() Цикл

НоваяСтрока = Реквизит1.Добавить();
НоваяСтрока.СерияНомер = СокрЛП(СтрЗаменить(ФайлDBF.Series + "," + ФайлDBF.Number,"",""));

ФайлDBF.Следующая(); 

КоличествоПрочитано = КоличествоПрочитано +1;

Если КоличествоПрочитано >= РазмерПартии ИЛИ ФайлDBF.ВКонце() Тогда
Сравнение() ;
Реквизит1.Очистить();
КоличествоПрочитано = 0;
КоличествоПрочитано = КоличествоПрочитано +1;
КонецЕсли;

НомерЗаписи = ФайлDBF.НомерЗаписи() ;
КонецЦикла;

ФайлDBF.ЗакрытьФайл();
Показать
Оставьте свое сообщение
Новые вопросы с вознаграждением
Автор темы объявил вознаграждение за найденный ответ, его получит тот, кто первый поможет автору.

Вакансии

Программист, аналитик, эксперт 1С
Санкт-Петербург
По совместительству

Технический лидер, архитектор 1С, руководитель проектов
Санкт-Петербург
зарплата от 150 000 руб.
Полный день

Ведущий 1С консультант по БГУ
Омск
зарплата от 50 000 руб. до 95 000 руб.
Полный день

Специалист внедрения и сопровождения 1С
Омск
зарплата от 25 000 руб. до 50 000 руб.
Полный день

Автор новостных обзоров на тему 1С и бухучета
Санкт-Петербург
По совместительству