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

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

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

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

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

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

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

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

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

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

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

КонецЦикла;

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

Переходит на запись по ее физическому порядковому номеру в таблице базы данных.
Показать
9. nomad_irk 71 17.10.19 15:06 Сейчас в теме
(7)XBASE даже можно не закрывать/открывать - доступ к данным и так последовательный, т.е. весь файл в ОЗУ не загружается.
10. user1296699 17.10.19 15:35 Сейчас в теме
(7) Спасибо.Попробую. Только я не понял а как мне остановить чтение на 100k
12. Sashares 34 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 34 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 71 17.10.19 15:04 Сейчас в теме
(6)
1. Организовать счетчик "полученных" из DBF файла строк.
2. Когда счетчик сравнялся с заданным значением, отправляем полученную ТЗ на проверку.
3. По результатам проверки что-то делаем.
4. Обнуляем счетчик "полученных" из DBF файла строк. Создаем пустую ТЗ.
5. Набиваем следующую порцию строк из DBF и возвращаемся на п. 2
4. acanta 17.10.19 14:57 Сейчас в теме
Как вариант в базу добавить объект типа регистр сведений (или несколько), перенести данные из дбф файлов полностью в регистр сведений и сравнить внутри одной базы данных запросами.
17. Dnki 4 17.10.19 22:47 Сейчас в теме
Вы меня простите за критику, это так отразился текст программы? Или он в самом деле такой корявый?
С лишними пустыми строками, нелепыми отступами.

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

Раз большие данные, то все делать только в базе! А СУБД с ними справится.
Как писал (4) acanta:
- переписать DBF в регистр (я бы-в справочник)
- может проиндексировать по полям сравнения ("СерияНомер" ...) для скорости
здесь можно прервать задание (т.к. "Рабочий день заканчивается")
- совсем другой обработкой (хоть Консолью) сделать Запрос на сравнение.
Именно принципиально, что есть возможность разорвать работу на 2 части. Лучше добиваться результата поэтапно.
5. platonov.e 158 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С аналитик
Москва
зарплата от 210 000 руб.
Полный день

Руководитель направления 1С
Москва
зарплата от 350 000 руб.
Полный день

1С Программист
Москва
зарплата от 180 000 руб.
Полный день

Программист 1С
Москва
зарплата от 180 000 руб. до 220 000 руб.
Полный день

Аналитик 1С / Бизнес-аналитик
Нижний Новгород
зарплата от 100 000 руб. до 250 000 руб.
Временный (на проект)