![]() |
|
| Правила Форума редакция от 22.06.2020 |
|
|||||||
|
|
Окажите посильную поддержку, мы очень надеемся на вас. Реквизиты для переводов ниже. |
|
![]() |
|
|
Опции темы | Опции просмотра |
Language
|
|
|
#1
|
|
1. Имеем 1С, в нем справочник ТМЦ порядка 20 тыс. наименований, из них порядка 800 - группы.
2. Имеем БД фаербирд с таблицами: а) Группы товаров (2 колонки - ид группы и наименование группы, ид группы праймари кей, значение ид группы равно значению кода в 1С) б) Товары (9 колонок, ид товара равно коду товара в 1С) в) Цены (4 колонки - ид цены /ставится через тригер БИ + генератор/, ид товара /значение код а товара из таблицы Товары/,Дата цены, значение цены на дату). Задача: перебросить группы товаров, товары и цены товаров из 1С в фаирбирдовскую таблицу, а также, отслеживать изменения наименований, реквизитов и цен и проводить синхронизацию по этим изменениям. Моя реализация: 1. Подключаюсь к 1С через ОЛЕ 2. Методом перебора справочника товара в 1С выгребаю группы и передаю нужные значения в процедуру добавления в фаербирд -- Spr.selectitems(1); while Spr.GetItem(1) > 0 do Begin Progress.StepBy(1); if Spr.IsGroup('')=0 then Continue; Group_Code:=Spr.getAttrib('Код'); Group_Lvl:=OLE1C.EvalExpr('ПолучитьУровеньГруппы(' +IntToStr(Group_Code)+')'); Group_Rod:=0; if Group_Lvl<>1 then Group_Rod:=OLE1C.EvalExpr('ПолучитьРодителяГруппы( '+IntToStr(Group_Code)+')'); if Length(Spr.getAttrib('Наименование'))>24 then Group_Name:=Copy(Spr.getAttrib('Наименование'),1,2 4) Else Group_Name:=Spr.getAttrib('Наименование'); Add_Group(Group_Code ,Group_Name,Group_Rod); -- , где ид:=Group_Code,Group_Name - имя группы, Group_Rod - код родительской группы для подгрупп. 3. процедурка Add_Group -- procedure TMain_Form.Add_Group(G_Code:Integer;G_Name:String; G_Rod:Integer); Var Need_Upd:Boolean; BEgin Need_Upd:=False; Proc.StoredProcName:=''; Sel.Close; Sel.SQL.Text:='Select * from SPR_TMC_G where ID_GROUP='+IntToStr(G_Code); Sel.Open; Sel.FetchAll; if Sel.RecordCount=0 then Begin Need_Upd:=True; Proc.StoredProcName:='SPR_TMC_G_INS'; end Else Begin Sel.First; if trim(Sel.FieldByName('name_group').AsString)<>trim (G_Name) then Need_Upd:=True; if Sel.FieldByName('rod_group').AsInteger<>G_Rod then Need_Upd:=True; end; if Need_Upd=True then Begin if Proc.StoredProcName<>'SPR_TMC_G_INS' then Proc.StoredProcName:='SPR_TMC_G_UPD'; Tr_Proc.StartTransaction; Proc.ParamByName('id_group').AsInteger:=G_Code; Proc.ParamByName('name_group').AsString:=G_Name; Proc.ParamByName('rod_group').AsInteger:=G_Rod; Proc.ExecProc; Tr_Proc.Commit; End; -- На этом этапе в принципе все норм, при 20К позиций в справочнике за минуту -две идет оновление БД файербирда. 4. Дальше тем же перебором отбираю именно элементы справочника товаров в 1С -- Tr_Proc.StartTransaction; Str_Sost.Caption:='Синхронізація елементів товарів...'; Progress.Min:=0; Progress.Max:=OLE1C.EvalExpr('ПолучитьКоличествоЭл ементов()'); Progress.Position:=0; Main_Form.Refresh; Spr.selectitems(1); while Spr.GetItem(1) > 0 do Begin Progress.StepBy(1); if Spr.IsGroup('')=1 then Continue; //Если розничной цены нету - нафиг такой товар Cena_R:=OLE1C.EvalExpr('ПолучитьРЦену('+Spr.getAtt rib('Код')+')'); IF Cena_R=0 Then Continue; Group_Code:=Spr.getAttrib('Код'); Group_Lvl:=OLE1C.EvalExpr('ПолучитьУровеньГруппы(' +IntToStr(Group_Code)+')'); Group_Rod:=0; if Group_Lvl<>1 then Group_Rod:=OLE1C.EvalExpr('ПолучитьРодителяГруппы( '+IntToStr(Group_Code)+')'); if Length(Spr.getAttrib('Наименование'))>128 then Group_Name:=Copy(Spr.getAttrib('Наименование'),1,1 28) Else Group_Name:=Spr.getAttrib('Наименование'); Add_Tovar(Group_Code,Group_Name,Group_Rod,Spr.getA ttrib('Штрихкод'),Cena_R); end; Tr_Proc.Commit; -- Отличия от предыдущей процедурки для груп - транзакцию всунул тут ибо, имхо, лучше фиксировать транзакцию после выполнения встроеных процедур 5. Процедура Add_Tovar имеет следующий вид: - procedure TMain_Form.Add_Tovar(T_Code:Integer;T_Name:String; T_Rod:Integer;T_Shtrihcode:String;T_Cena:Real); var Need_Set_Cena:Integer; Need_upd:Boolean; BEgin Need_upd:=False; Proc.StoredProcName:=''; Sel.Close; Sel.SQL.Text:='Select * from SPR_TMC where ID_TMC='+IntToStr(T_Code); Sel.Open; Sel.FetchAll; if Sel.RecordCount=0 then Begin Need_upd:=True; Proc.StoredProcName:='SPR_TMC_INS'; end Else Begin Sel.First; if trim(Sel.FieldByName('name').AsString)<>Trim(T_Nam e) Then Need_upd:=True; if trim(Sel.FieldByName('shtrihkod').AsString)<>Trim( T_Shtrihcode) Then Need_upd:=True; if Sel.FieldByName('id_group').AsInteger<>T_Rod Then Need_upd:=True; end; if Need_upd=True then Begin if Proc.StoredProcName<>'SPR_TMC_INS' then Proc.StoredProcName:='SPR_TMC_UPD'; Proc.ParamByName('id_tmc').AsInteger:=T_Code; Proc.ParamByName('name').AsString:=T_Name; Proc.ParamByName('vid_tmc').AsInteger:=0; Proc.ParamByName('art').AsString:=''; Proc.ParamByName('shtrihkod').AsString:=T_Shtrihco de; Proc.ParamByName('id_group').AsInteger:=T_Rod; Proc.ParamByName('dop_name').AsString:=LowerRCase( T_Name); Proc.ParamByName('skidka').AsInteger:=0; Proc.ParamByName('Edit_Ceny').AsInteger:=0; Proc.ExecProc; end; Need_Set_Cena:=1; Sel.Close; Sel.SQL.Text:='Select * from SPR_CENY where ID_TMC='+IntToStr(T_Code); Sel.Open; Sel.FetchAll; Sel.First; while not Sel.Eof do Begin if sel.FieldByName('DATE_CENA').AsDateTime=Now then Begin if sel.FieldByName('CENA').AsFloat<>T_Cena then Begin Proc.StoredProcName:='SPR_CENY_UPD'; Proc.ParamByName('id_cena').AsInteger:=Sel.FieldBy Name('id_Cena').AsInteger; Proc.ParamByName('id_tmc').AsInteger:=T_Code; Proc.ParamByName('date_cena').AsDate:=Now; Proc.ParamByName('cena').AsFloat:=T_Cena; Proc.ExecProc; Need_Set_Cena:=0; end; Break; end; Sel.Next; end; if Need_Set_Cena=1 then Begin Proc.StoredProcName:='SPR_CENY_INS'; Proc.ParamByName('id_tmc').AsInteger:=T_Code; Proc.ParamByName('date_cena').AsDate:=Now; Proc.ParamByName('cena').AsFloat:=T_Cena; Proc.ExecProc; end; end; -- Где в указаном болдом тексте происходит проверка/вставка/апдейт цены. и собственно, проблема: При отключении проверки/вставки/апдейта цен время выполнения (имею ввиду именно синхронизация элементов справочника) около 15-18 мин, с ценами - минут 30-40. Присоветуйте коллективным разумом - может возможен другой алгоритм проверок/апдейтов? З.Ы. Думал, может селект на ИД товара/цены делать не на каждый элемент из справочника, а в общем, и потом искать по готовому набору записей, но вариант 20К раз перебирать набор записей в 20К не кажется более быстрым.... |
|
|
|
|
| Реклама: | бытовые холодильники | из москвы в петербург на теплоходе | телевизор hisense 65e7kq | циркуляционный насос grundfos magna3 25-60 | Заходите на сайт MebelStol.ru: стол на кухню с одной ножкой купить - отличные цены и большой выбор! |
|
|
#2
|
|
Постоялец
![]() ![]() ![]() Пол:
Регистрация: 02.07.2009
Сообщений: 393
Репутация: 79
|
Вот не читал код до конаца... но имхо как-то сложно ты делаешь всё это...
1с какой? 7.7/8.х? и на чём? на файл-сервере или на sql? не проще ли напрямую через ADO цепляться к базе из программы и забирать что нужно. + в самом 1с есть возможность работы с нешними БД через COM объекты. Работате на много быстрее чем OLE
__________________
Каждый человек, которому вы ответили на форуме "гугл в помощь" - потенциальный "возвращенец" в винды. (ц) |
|
|
|
|
|
#3
|
|
1С 77. ДБФ.
синхронизация с самой 1С не покатит, ибо оператор-менеждер пришел/не пришел приход сделал/не зделал, на кнопку нажал/ненажал... А так приблуда службой по таймеру висит... Добавлено через 3 минуты плюс закачка прихода в 1С возможна и без учатия человека - пришла электронка, в ней накладная с новыми ценами... Последний раз редактировалось Leser; 29.01.2010 в 16:18.. Причина: Добавлено сообщение |
|
|
|
|
|
|
#4
|
|
Постоялец
![]() ![]() ![]() Пол:
Регистрация: 02.07.2009
Сообщений: 393
Репутация: 79
|
Ну тогда всё просто.
Подцепляешься ADODB connectionom к базе 1с-ной (прям мастером можно настроиться) и оттуда дёргаешь что тебе нужно. Структуру базы данных можно почитать в файлике 1Cv7.DD который лежит в каталоге с конфигурацией. Работать будет в разы быстрее чем OLE. Если не разберёшься - спрашивай...
__________________
Каждый человек, которому вы ответили на форуме "гугл в помощь" - потенциальный "возвращенец" в винды. (ц) |
|
|
|
|
|
#5
|
|
Дык в том то и вопрос, что скорость чтения через оле меня устраивает - не устраивает скорость проверки и записи/апдейта в файербирде.... Я когда на форму выношу к примеру название взятые из справочника 1С, то порядка 10% - то чтение даных с 1С, и порядка 90% - проверки и апдейты в файрбирде... |
|
|
|
|
|
|
#6
|
|
Постоялец
![]() ![]() ![]() Пол:
Регистрация: 02.07.2009
Сообщений: 393
Репутация: 79
|
Хм... ну что я могу сказать... с фаербёрдом не работл честно говоря и не знаю по какому принципу организовано...
Помоему проблема именно в том, что перебирать нужно слишком много из того, что есть уже в фаербёрде... Как работало у меня в торговом центре (достаточно крупном для нашего города) подобная весчь: при проведении накладной, устанавливающей цены автоматом происходил запрос к целевой базе, который и определял нужно ли добавлять/апдейтить что-то. Т.е. примерно так я бы сделал: При проведении документа прошёлся бы в 1с по табличной части: ВыбратьСтроки(); Пока получитьСтроку() = 1 Цикл Код = Номенклатура.Код; Группа = Номенклатура.Родитель.Код; Цена = ПолучитьЦену(Номенклатура); ..... //остальные данные, нужные в фаербёрде получить //Запро выполнить запрос; КонецЦикла; А запрос принимал бы такой вид: "if exist(select * from tovari were tovari.id = '" + СокрЛП(Код) + "') update ...... else insert .... " Аналогично для групп и для цен.... Это "рыба" для sql сервера. Если не на сервере крутится - в ручную придётся выполнять сравнение. Т.е. сделать выборку по коду и проверить, сколько кортежей в рекордсете и если ниодного тогда инсертить иначе апдейтить... Если нужно могу прислать 1с-ную процедуру, работающую с sql прислать При этом человеческий фактор отпадает - если не провелся документ то ничего выгружать не надо а если провелся - выгружается автоматом, не нужно доп. кнопку жать. + у тебя, как я понял, постоянно открывается и закрывается соединение с базой (читал не внимательно могу ошибаться) что есть дополнительные затраты по времени. попробуй один раз его открывать/закрывать а запросы все повесить на Query и/или Command'ы
__________________
Каждый человек, которому вы ответили на форуме "гугл в помощь" - потенциальный "возвращенец" в винды. (ц) |
|
|
|
|
|
#7
|
|
Помоему проблема именно в том, что перебирать нужно слишком много из того, что есть уже в фаербёрде...
Я тоже к этому склоняюсь.... Получается, что на каждый взятый с 1С элемент выполняется Select * from SPR_TMC where ID_TMC='+IntToStr(T_Code); - тоесть количество выполнений равно количеству элементов справочника. Если же выполнить просто Select * from SPR_TMC , то выйдет, что количество выполнений селекта одно, но зато придется в цикле бегать по этому набору записей столько раз, сколько есть елементов в справочнике 1С )). Не факт, что быстрее выйдет ... у тебя, как я понял, постоянно открывается и закрывается соединение с базой - не, с базой, как с файербирдовской, так и с 1С-совской соединение один раз - при начале синхронизации устанавливается, после окончания - разрывается. Кстати, может в этом проблема? Не может ли такого быть, что на каждое обращение к процедуре 1С через оле открывается новый поток, и, как следствие, тормоза в системе? Добавлено через 1 минуту Заметил, что первые пару К элементов синхронизируются быстрей, а чем дальше - тем больше тормоза... Последний раз редактировалось Leser; 29.01.2010 в 18:10.. Причина: Добавлено сообщение |
|
|
|
|
|
|
#8
|
|
Пользователь
Пол:
Регистрация: 11.05.2007
Сообщений: 48
Репутация: 21
|
а если сделать так: из 1С получаем одним запросом все необходимые элементы/группы (можно из delphi запрос послать, можно вызвать из 1С функцию, которая возвращает набор данных из запроса) - это дело можно, например поместить в TMemoryTable (RX компоненты). А затем тоже одним запросом получаем разницу между набором из 1С и Firebird-базой.
|
|
|
|
![]() |
Похожие темы
|
||||
| Тема | Автор | Раздел | Ответов | Последнее сообщение |
| Подскажите плиз коммуникатор с хорошим звуком | APEXik | КПК | 5 | 11.10.2010 17:52 |
| Подскажите плиз что за индикатор Renault Kangoo | deamon_t | Автосервис | 2 | 11.05.2009 09:35 |
| Подскажите,плиз!!! | васька59 | Ноутбуки, Нетбуки, Планшеты | 23 | 13.06.2008 10:08 |
| подскажите плиз ! | Bimbo | PHP | 2 | 22.08.2007 07:10 |
| Софт для видеокарты с ТВ-тюнером: подскажите, плиз! | LeXXiK | Архив | 7 | 13.02.2007 19:31 |
|
|