Имя: Пароль:
1C
 
Как ускорить поиск по реквизиту
0 vde69
 
05.02.10
14:44
есть сторонняя система, в 1с из нее получаем таблицу ТЗ примерно в 50 тыс строк, далее надо связать контрагентов и договора (по доп полю), сейчас в базе примерно 200тыс договоров, текущий алгоритм стал долго работать (1-2 часа).

Сейчас алгоритм такой:
из ТЗ выгружаем колоку с кодами контрагентов и сворачиваем, далее ее дополняем колонкой и заполняем эту колонку (получаем кеш таблицу),

проходим основную ТЗ и заполняем поле Контрагент (на основании кеш таблицы), алгоритм заполнения однопроходный цикл.

далее так-же заполняем договора, банки, счета и т.д.
на сколько я понимаю сейчас у нас проблеммы в размере ТЗ


нужна идея какой-то хитрой связи, я пока склоняюсь к варианту создания временной таблицы в скуле и прямом джойне,
1 Sadovnikov
 
05.02.10
14:47
(0) "я пока склоняюсь к варианту создания временной таблицы в скуле и прямом джойне" - сдается мне, что это самое правильное решение...
2 vde69
 
05.02.10
14:49
(1)от тебя другого и не ожидал :)

есть еще такой вариант - хранить внутренний_ID обьекта в сторонней системе, и после получения ТЗ востанавливать ссылку по ID
3 DrZombi
 
гуру
05.02.10
14:56
(0)А поподробнее, про запрос?
Что именно ты хочешь получить в итоге?
И зачем все в одной? Разве не проще все поручить самому скулю, а там ужо только результат получить?
4 kiruha
 
05.02.10
14:56
скидывай во временную таблицу дбф или sql .
Индексируем.
Потом прямыми - максимум 2 минуты.
5 vde69
 
05.02.10
14:59
(3) стороння база на другом серваке, а прямые джойны для разных серверов не гуд.
6 Жан Пердежон
 
05.02.10
15:01
(0) >> получаем таблицу ТЗ примерно в 50 тыс строк, далее надо связать контрагентов и договора;
чего с чем связать, что в таблице то?
7 Mikeware
 
05.02.10
15:02
(6) Веревкой связать контрагентов. И бирку (договор о погребении) к пятке...
8 DrZombi
 
гуру
05.02.10
15:04
(5)Да... согласен, но зато быстро :)
А чем не через ОЛЕ + в олешной базе запрос?
9 vde69
 
05.02.10
15:06
(6)
// вот эта функция вызывается 1 раз для каждого УНИКАЛЬНОГО договора
// примерно 10 тысяч раз
//
// подобных полей связи около 10
//
Функция СвязатьДоговор(ТабДоговоров, Контрагент, НомерДоговора, ДатаДоговора, НазваниеДокумента, Connection,УИД,ТипД,ДатаСчФ="")
   Договор = "";
   
   Если ПустоеЗначение(Контрагент) = 1 Тогда
       _Сообщить("Пустой Контрагент");            
   Иначе
       Если НомерДоговора = "" Тогда
           _Сообщить("Пустой номер договора, для контрагента <" + Контрагент + ">","!");            
       Иначе  
           Договор = СоздатьОбъект("Справочник.Договоры");    

           ТабДоговоров.ВыбратьСтроки();
           _УИД = Число(УИД);
           Пока ТабДоговоров.ПолучитьСтроку() = 1 Цикл
               Если ТабДоговоров.УИД = _УИД Тогда
                   Договор.НайтиЭлемент(ТабДоговоров.Ссылка);
                   
                   Если  (СокрЛП(Договор.НомерДоговора) = НомерДоговора)    //отменил для скорости, по сколько расхождения типа Договор.НомерДоговора = "67-F/08" НомерДоговора = "67-F/08 от 17.03.2008"
                   И
                   (Договор.ДатаДоговора = ДатаДоговора)
                   И
                   (Договор.Владелец = Контрагент.ТекущийЭлемент()) Тогда
                   Иначе
                       _Сообщить("есть расхождения по договору с ID="+УИД+" ["+Договор+";"+Договор.Владелец+"]","!");
                   КОнецЕсли;
                   Прервать;
               КонецЕсли;

           КонецЦикла;
           
//            Если    (СокрЛП(Договор.НомерДоговора) <> НомерДоговора)
//                ИЛИ (Договор.ДатаДоговора <> ДатаДоговора)
//                ИЛИ (Договор.Владелец <> Контрагент.ТекущийЭлемент()) Тогда
           Если (Договор.УИД<>Число(УИД)) ИЛИ (Договор.ТипД<>ТипД) Тогда        
               // не нашли, надо создать
               // сначало получим данные по нему
               Попытка
                   Command = СоздатьОбъект("ADODB.Command");
                   Command.ActiveConnection = Connection;
                   Command.CommandType=1;
                   Command.CommandTimeOut = 300;
                   
                   ДатаД = "" + ДатаЧисло(ДатаДоговора) + "." + ДатаМесяц(ДатаДоговора) + "." + ДатаГод(ДатаДоговора);
                   
                   Command.CommandText=" EXEC fk_prDocs " + Уид + ","+ТипД;
                   Set = Command.Execute();
               Исключение  
                   _Сообщить("Ошибка получения данных по договору! №" + НомерДоговора + " от " + ДатаД,"!");
                   _Сообщить(ОписаниеОшибки()+" m2","!");
                   Возврат "";
               КонецПопытки;

               Договор.Новый();                
               Договор.Владелец=Контрагент;
               Договор.УстановитьНовыйКод();
               Договор.АвтоОбработкаНДС                            = ?(Константа.АвтоКнигаПокупокПродаж = Да, 1, 0);
               Если ДатаСчф<>"" тогда
                   Договор.Наименование                                  = НазваниеДокумента + " №" + НомерДоговора + " от " + ДатаСчФ;
               Иначе
                   Договор.Наименование                                  = НазваниеДокумента + " №" + НомерДоговора + " от " + ДатаДоговора;
               КонецЕсли;
               Договор.НомерДоговора                                = НомерДоговора;
               Договор.ДатаДоговора                                  = ДатаДоговора;
               Договор.ВидДоговора                                    = глЗначениеПоУмолчанию("ОсновнойВидДоговоров");
               Договор.УИД=Число(УИД);
               Договор.ТипД=ТипД;
               
               Пока Set.EOF()<>-1 Цикл

                   Договор.ДатаВозникновенияОбязательства                =  Дата(Set.Fields("DateEnd").Value);

                   Прервать;
               КонецЦикла;          
               
               Договор.Записать();
               
               ТабДоговоров.НоваяСтрока();
               ТабДоговоров.Ссылка = Договор.ТекущийЭлемент();
               ТабДоговоров.УИД = Договор.УИД;
               
               _Сообщить ("Создан новый договор <" + Договор + "> для контрагента <" + Контрагент + ">");
           КонецЕсли;
           
           
           Если (Договор.УИД<>Число(УИД)) ИЛИ (Договор.ТипД<>ТипД) Тогда                    
               _Сообщить("Не связался договор <" + НомерДоговора + "> для контрагента <" + Контрагент + ">","!");    
               Договор =  "";
           КонецЕсли;

       КонецЕсли;
   КонецЕсли;
   
   Если Договор="" Тогда
       Возврат ""
   Иначе
       Возврат Договор.ТекущийЭлемент();
   КонецЕсли;    

КонецФункции
10 vde69
 
05.02.10
15:06
(8) другая база дельфовая :)
11 Mikeware
 
05.02.10
15:08
(9) Букв много. Что сделать-то надо?
12 Жан Пердежон
 
05.02.10
15:08
(9) а чего с чем связывать и что в таблице - так и не ясно)
пока только запрос в цикле виден
13 vde69
 
05.02.10
15:14
(12) запрос в цикле - это только для вновь создаваемых элементов получение данных из сторонней системы
14 genosse
 
05.02.10
15:15
(0) Перефразируй (точнее сформулируй) сам вопрос. Понять тут вообще ничего не реально.
получаем таблицу 50000 -> нужно связать контрагентов с договорами их 200000 -> текущий механизм долгий :)
15 vde69
 
05.02.10
15:18
вот что я получаю из сторонней системы:

/*Объект: fk_prKomis1C
Тип: Процедура
Описание: Формирует данные для создания в 1С проводок  "Начисление комиссии", "Удержание комиссии"
Идентификатор: 10021

Использование:
Параметры:
  Входные:
    @dt_Beg char(10) дата начала,
    @dt_End char(10) дата завершения
 формат 'dd.mm.yyyy'
  Выходные:

Возврат: таблица данных  
 id_ac - id счёт-фактуры
 ndoc - номер счёт-фактуры
 nds - ндс по счёт-фактуре
 id_Cli - id клиента
 id_Deb - id дебитора
 clinn - инн клиента
 debinn - инн дебитора
 Rekvizit - номер договора с клиентом
 DateBeg - дата начала договора
 DateEnd - дата завершения договора (если нет - то NULL)
 Schet - банковский счёт факторинга
 Ident - идентификатор (начисленные комиссии)
 sm_AU_Nach - КомАУ
 sm_AUFin_Nach КомАУфин
 sm_PrcZaFin_Nach КомФН
 sm_StrafNach - штрафы (оплаченные комиссии)
 sm_AU_Opl - КомАУ
 sm_AUFin_Opl КомАУфин
 sm_PrcZaFin_Opl КомФН
 sm_StrafOpl - штрафы
 dt_inp - дата создания с.ф. в нашей системе

---------------------------------------------------
нужно создать документы, для этого нужно по ИНН найти контрагентов, по дате иномеру договора найти договора
16 genosse
 
05.02.10
15:21
(15) Замер производительности в каком месте дает наибольший процент?
Что оптимизируем? Надо сузить круг подозреваемых .)
17 orefkov
 
05.02.10
15:21
тз во врем.табличку и запросом ее, запросом.
18 vde69
 
05.02.10
15:27
(16) явных лидеров нету, код и так оптимизировали несколько раз
19 genosse
 
05.02.10
15:31
(18) Обе базы скуль? Документы все новые или нужно проверить на наличие изменений в старых + залить новые?
20 vde69
 
05.02.10
15:33
(19) обе SQL, но разные 2000 и 2005, при ждойне между серверами индексы не используются, по этому все сделать на одном сервере нельзя.

алгоритм пересоздания документов вполне нормально работает, медлено поиск и создание справочников
21 genosse
 
05.02.10
15:36
(20) Можно сделать тригер на источнике и переносить только созданные и измененые. Опять же и структуру базы не затронет.
22 Asirius
 
05.02.10
15:38
(15) Зачем нужна таблица ТабДоговоров? Почему не сделать индекс по Договор.УИД?
23 vde69
 
05.02.10
16:05
(22) для того, что-бы по несколько раз не искать
24 Asirius
 
05.02.10
16:25
(23) Так ты и каждый раз договор выбираещь
>>Договор.НайтиЭлемент(ТабДоговоров.Ссылка);

Договор.НайтиПоРеквизиту("УИД",Уид) будет практически с такой же скоростью работать
25 vde69
 
05.02.10
17:16
(24) проверь :)

кроме того у меня таблица сильно меньше всего справочника
26 МихаилМ
 
05.02.10
17:55
тормоза от подхода решения задачи.
обрабатвайте данные множествами а не записями.

сответственно желательно иметь метод получения из другой ИБ
не обной записи, а множества.

и опять же сопоставления (формировани выборки) удобней сделать на сервере
а запись на клиенте из сображений понятности кода .
27 vde69
 
07.02.10
20:28
(26) получаем выборку одним запросом, далее обращения к базе идут только для НОВЫХ элементов

сопостовление на сервере для 7.7 это КАК?
28 leshikkam
 
07.02.10
20:32
(27) linked server может быть?
29 Garkin
 
07.02.10
21:03
(9) Спрошу на всякий случай.


_УИД = Число(УИД);
Пока ТабДоговоров.ПолучитьСтроку() = 1 Цикл
   Если ТабДоговоров.УИД = _УИД Тогда
     ........

         Прервать;
   КонецЕсли;
КонецЦикла;

Это точно работает быстрее  чем ТабДоговоров.НайтиЗначение(    ?
30 Garkin
 
07.02.10
21:23
+(29)
Еще непонятно зачем надо
  Договор.НайтиЭлемент(ТабДоговоров.Ссылка);

Разве Договор=ТабДоговоров.Ссылка недостаточно?
31 Garkin
 
07.02.10
22:32
(0) Отсортируй ТЗ по "доп - полю" - избавься от кэш таблицы.

Да еще непонятно, сначала ищем клиентов, потом ищем договора. Договор разве не определяет однозначно клиента?
32 vde69
 
08.02.10
08:34
(31) в 1с - да, но в сторонней системе нет, и тут идет контроль сторонней системы
(30) если договор надо записать, то все равно нужна такая конструкция
(29) принимается, посмотрю подробнее
33 Garkin
 
08.02.10
09:06
(32)
"в 1с - да, но в сторонней системе нет, и тут идет контроль сторонней системы "
Ну и фик с ним, найди договор, а потом контролируй совпадает ли владелец договора в 1С с клиентом в сторонней система.

"если договор надо записать, то все равно нужна такая конструкция "  - что-то я не наблюдаю где ты в (9) записываешь найденный договор, ты от нас что-то скрываешь?

"принимается, посмотрю подробнее" - в топку, см (31). Избавься от кэш таблицы.
Программист всегда исправляет последнюю ошибку.