18.11.2009, 16:22 | #1 |
Участник
|
Проблема с CustTrans
Доброго времени суток, уважаемые программисты, гуру Аксапты
У нас существует отчет "Оплата по группам финансирования", выбирающий данные из таблиц Custtrans, CustInvoiceJour и LedgerJournalTrans (Axapta 3.0 SP5). Работал он работал, и вот однажды утром снова стал работать гораздо медленнее. Включив мониторинг запросов, выяснил, что очень долго проходит кверик по custtrans. Привожу код метода: X++: void insertTmpFromCustTrans() { CustTrans qCustTrans; RContractTable qContractTable, contractTable; ; queryRun.query().dataSourceTable(tableNum(CustTrans)).addRange(fieldNum(CustTrans,TransDate)).value(queryRange(dateNull(),datefrom-1)); if (accountNum) queryRun.query().dataSourceTable(tableNum(CustTrans)).addRange(fieldNum(CustTrans,AccountNum)).value(accountNum); if (contractAccount) { queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractCode)).value(contractCode); queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractAccount)).value(contractAccount); queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractPartnerCode)).value(accountNum); } while (queryRun.next()) { qCustTrans = queryRun.get(tableNum(CustTrans)); qContractTable = queryRun.get(tableNum(RContractTable)); if (qCustTrans) { tmpTable.clear(); tmpTable.GroupFinancName = GroupsFinancTable::find(qContractTable.GroupFinancId).GroupFinancName; tmpTable.AccountNum = qCustTrans.AccountNum; tmpTable.AccountName = CustTable::find(qCustTrans.AccountNum).NameAlias; tmpTable.ContractNumberDate = qContractTable.contractNumberDate; tmpTable.Voucher = qCustTrans.Voucher; tmpTable.Advance = NoYes::No; tmpTable.DebtBeginPeriod = qCustTrans.AmountCur; tmpTable.CurrentPayTotal = tmpTable.BPayCurrent + tmpTable.PayCurrent; tmpTable.PayPeriodTotal = tmpTable.BPay + tmpTable.Pay + tmpTable.CurrentPayTotal; tmpTable.CurrentDebt = tmpTable.AddAmount + tmpTable.CurrentPayTotal; tmpTable.EndDebt = tmpTable.DebtBeginPeriod + tmpTable.AddAmount + tmpTable.PayPeriodTotal; tmpTable.insert(); } } queryRun.query().addDataSource(tableNum(TmpGroupFinancingTable)); } Реиндексацию индексов custtrans делал, не помогло..
__________________
..в каждой программе есть хотя бы одна ошибка.. Последний раз редактировалось Alexanderrrr; 18.11.2009 в 16:53. |
|
18.11.2009, 16:27 | #2 |
Участник
|
Скорее всего тормозит не запрос, а вставка во временную таблицу. Попробуйте закомментировать вот этот блок кода
X++: if (qCustTrans)
{
tmpTable.clear();
tmpTable.GroupFinancName = ICLGroupsFinancTable::find(qContractTable.GroupFinancId).GroupFinancName;
tmpTable.AccountNum = qCustTrans.AccountNum;
tmpTable.AccountName = CustTable::find(qCustTrans.AccountNum).NameAlias;
tmpTable.ContractNumberDate = qContractTable.contractNumberDate;
tmpTable.Voucher = qCustTrans.Voucher;
tmpTable.Advance = NoYes::No;
tmpTable.DebtBeginPeriod = qCustTrans.AmountCur;
tmpTable.CurrentPayTotal = tmpTable.BPayCurrent + tmpTable.PayCurrent;
tmpTable.PayPeriodTotal = tmpTable.BPay + tmpTable.Pay + tmpTable.CurrentPayTotal;
tmpTable.CurrentDebt = tmpTable.AddAmount + tmpTable.CurrentPayTotal;
tmpTable.EndDebt = tmpTable.DebtBeginPeriod + tmpTable.AddAmount + tmpTable.PayPeriodTotal;
tmpTable.insert();
} |
|
18.11.2009, 16:43 | #3 |
Участник
|
А еще - странно смотрятся последние 4 строчки в заполнении полей, когда в tmptable суммируются НЕЗАПОЛНЕННЫЕ поля из той же записи. Ну то есть:
tmpTable.CurrentPayTotal = tmpTable.BPayCurrent + tmpTable.PayCurrent; поля BPayCurrent и PayCurrent ранее заполнены не были, в чем смысле заполнения tmpTable.CurrentPayTotal ? Похоже, что или код кривой, или вы привели код метода не целиком. |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
18.11.2009, 16:47 | #4 |
Участник
|
Спасибо за ответ!
Попробовал закомментить так, как вы посоветовали, ситуация не изменилась..если комментить вместе с квериком, то отчет отрабатывает быстро.. дело в нем..
__________________
..в каждой программе есть хотя бы одна ошибка.. |
|
18.11.2009, 16:50 | #5 |
Участник
|
Цитата:
А еще - странно смотрятся последние 4 строчки в заполнении полей, когда в tmptable суммируются НЕЗАПОЛНЕННЫЕ поля из той же записи. Ну то есть:
tmpTable.CurrentPayTotal = tmpTable.BPayCurrent + tmpTable.PayCurrent; поля BPayCurrent и PayCurrent ранее заполнены не были, в чем смысле заполнения tmpTable.CurrentPayTotal ? Похоже, что или код кривой, или вы привели код метода не целиком. только от этого не легче
__________________
..в каждой программе есть хотя бы одна ошибка.. |
|
18.11.2009, 16:52 | #6 |
Участник
|
В методе, который Вы привели нет кода, где строится query.
|
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
18.11.2009, 16:53 | #7 |
Участник
|
Попробуйте разбить Join CustTrans и RСontractTable на два разных запроса, т.е. сначала идем по проводкам, потом, внутри, по договорам.
upd: И еще вот эта строка насторожила: X++: queryRun.query().addDataSource(tableNum(TmpGroupFinancingTable)); Последний раз редактировалось Lemming; 18.11.2009 в 17:26. |
|
18.11.2009, 21:15 | #8 |
Участник
|
Можно привести параметры запуска, т.е. какие из условий запроса действительно подхватываются?
Как много проводок по клиентам у вас в базе? Просто устрашает условие (просмотр CustTrans с начала времен?) X++: queryRun.query().dataSourceTable(tableNum(CustTrans)).addRange(fieldNum(CustTrans,TransDate)).value(queryRange(dateNull(),datefrom-1)); Что потом происходит с tmpTable ? Насколько критичен параметр Voucher - а, т.е. нет ли в дальнейшем просто группировки скажем по группе финансирования, клиенту, договору и нахождения общей суммы в поле tmpTable.DebtBeginPeriod? Просто, судя по имени поля tmpTable.DebtBeginPeriod, таким образом вы пытатесь определить сумму проводок на начало периода?
__________________
Sergey Nefedov |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 08:27 | #9 |
Участник
|
Код написан не мной и написан видимо плохо..
Цитата:
Только мы закончили проход по QueryRun, как начинаем модифицировать его запрос, что бы, по всей вероятности, потом снова запустить. Не знаю каков будет эффект от такого фокуса, т.к. не приходило такого в голову, но вообще это и листинг в целом оставляют впечатление типичного bad design.
X++: public boolean fetch() { boolean ret; MapIterator itGroupFinanc; MapIterator itAccount; MapIterator itContract; MapIterator itRecord; MapIterator itGroupTotal; if (paymentGroupFinancing && this.queryRun()) this.queryRun().setRecord(paymentGroupFinancing.parmTmpTable()); if(paymentGroupFinancing.parmDocuments() == NoYes::No) { TmpGroupFinancingTable_Body.height(0,Units::Char); if (paymentGroupFinancing.parmTotalContract() == NoYes::No) { ContractNameFooter.height(0,Units::Char); ContractNameHeader.height(0,Units::Char); } if (paymentGroupFinancing.parmTotalAccount() == NoYes::No) { AccountNameFooter.height(0,Units::Char); AccountNameHeader.height(0,Units::Char); } } mapGroupTotal = new Map(Types::String,Types::Container); itGroupFinanc = new MapIterator(mapGroupFinanc); itGroupFinanc.begin(); while (itGroupFinanc.more()) { groupFinanc = itGroupFinanc.key(); this.execute(10); mapAccount = itGroupFinanc.value(); itAccount = new MapIterator(mapAccount); itAccount.begin(); while (itAccount.more()) { account = itAccount.key(); this.execute(11); mapContract = itAccount.value(); itContract = new MapIterator(mapContract); itContract.begin(); while (itContract.more()) { contract = itContract.key(); this.execute(12); mapRecord = itContract.value(); itRecord = new MapIterator(mapRecord); itRecord.begin(); while (itRecord.more()) { tmpTable = itRecord.value(); this.send(tmpTable); itRecord.next(); } this.execute(22); itContract.next(); } this.execute(21); itAccount.next(); } this.execute(20); itGroupFinanc.next(); } itGroupTotal = new MapIterator(mapGroupTotal); itGroupTotal.begin(); while (itGroupTotal.more()) { contract = itGroupTotal.key(); [#ContainerSumsGroup] = itGroupTotal.value(); itGroupTotal.next(); } this.execute(30); return true; } Привожу код метода run этого класса: X++: public void run() { rangeDimension = queryRun.query().dataSourceTable(tableNum(CustTrans)).rangeField(fieldId2ext(fieldnum(CustTrans, Dimension),2)).value(); rangeGroupFinanc = queryRun.query().dataSourceTable(tableNum(RContractTable)).rangeField(fieldnum(RContractTable,GroupFinancId)).value(); this.insertTmpFromCustTrans(); this.insertTmpFromCustInvoiceJour(); this.insertTmpFromLedgerJournalTrans(); this.prepareMaps(); super(); } по последним двум кверики проходят быстро.. Убрал заполнении полей, когда в tmptable суммируются незаполненные поля из той же записи. Теперь выглядит так: X++: void insertTmpFromCustTrans() { CustTrans qCustTrans; RContractTable qContractTable, contractTable; ; queryRun.query().dataSourceTable(tableNum(CustTrans)).addRange(fieldNum(CustTrans,TransDate)).value(queryRange(dateNull(),datefrom-1)); if (accountNum) queryRun.query().dataSourceTable(tableNum(CustTrans)).addRange(fieldNum(CustTrans,AccountNum)).value(accountNum); if (contractAccount) { queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractCode)).value(contractCode); queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractAccount)).value(contractAccount); queryRun.query().dataSourceTable(tableNum(RContractTable)).addRange(fieldNum(RContractTable,RContractPartnerCode)).value(accountNum); } while (queryRun.next()) { qCustTrans = queryRun.get(tableNum(CustTrans)); qContractTable = queryRun.get(tableNum(RContractTable)); if (qCustTrans) { tmpTable.clear(); tmpTable.GroupFinancName = GroupsFinancTable::find(qContractTable.GroupFinancId).GroupFinancName; tmpTable.AccountNum = qCustTrans.AccountNum; tmpTable.AccountName = CustTable::find(qCustTrans.AccountNum).NameAlias; tmpTable.ContractNumberDate = qContractTable.contractNumberDate; tmpTable.Voucher = qCustTrans.Voucher; tmpTable.Advance = NoYes::No; tmpTable.DebtBeginPeriod = qCustTrans.AmountCur; tmpTable.insert(); } } queryRun.query().addDataSource(tableNum(TmpGroupFinancingTable)); } Цитата:
Можно привести параметры запуска, т.е. какие из условий запроса действительно подхватываются?
datefrom 01.01.2009, dateto-сегодняшний день, договора отбираются только с нужным нам кодом группы финансирования. Цитата:
Как много проводок по клиентам у вас в базе?
Цитата:
Что потом происходит с tmpTable ? Насколько критичен параметр Voucher - а, т.е. нет ли в дальнейшем просто группировки скажем по группе финансирования, клиенту, договору и нахождения общей суммы в поле tmpTable.DebtBeginPeriod?
X++: private void prepareMaps() { str KeyMap; Int standardSort; GroupFinancName curGroupFinanc; Name curAccount; Name curContract; ; mapGroupFinanc = new Map(Types::String,Types::Class); mapAccount = new Map(Types::String,Types::Class); mapContract = new Map(Types::String,Types::Class); mapRecord = new Map(Types::Integer,Types::Record); while select * from tmpTable order by ContractNumberDate { standardSort++; curGroupFinanc = tmpTable.GroupFinancName; curAccount = strFmt('@SYS26868', tmpTable.AccountNum, tmpTable.AccountName); curContract = tmpTable.ContractNumberDate; if (mapGroupFinanc.exists(curGroupFinanc)) { mapAccount = mapGroupFinanc.lookup(curGroupFinanc); if (mapAccount.exists(curAccount)) { mapContract = mapAccount.lookup(curAccount); if (mapContract.exists(curContract)) mapRecord.insert(standardSort,tmpTable); else { mapRecord = new Map(Types::Integer,Types::Record); mapRecord.insert(standardSort,tmpTable); mapContract.insert(curContract,mapRecord); } } else { mapRecord = new Map(Types::Integer,Types::Record); mapRecord.insert(standardSort,tmpTable); mapContract = new Map(Types::String,Types::Class); mapContract.insert(curContract,mapRecord); mapAccount.insert(curAccount,mapContract); } } else { mapRecord = new Map(Types::Integer,Types::Record); mapContract = new Map(Types::String,Types::Class); mapAccount = new Map(Types::String,Types::Class); mapRecord.insert(standardSort,tmpTable); mapContract.insert(curContract,mapRecord); mapAccount.insert(curAccount,mapContract); mapGroupFinanc.insert(curGroupFinanc,mapAccount); } } }
__________________
..в каждой программе есть хотя бы одна ошибка.. Последний раз редактировалось Alexanderrrr; 19.11.2009 в 08:44. |
|
19.11.2009, 08:43 | #10 |
Участник
|
Что-то я запутался, так что у Вас сейчас тормозит, "кверик по custtrans" или что-то еще?
p.s. Мощный, надо сказать отчет, судя по листингам в последнем посте upd: Пожалуй стоит уточнить, что значит стал медленней работать? Сколько примерно данных(строк) выводится в отчет и сколько он строится, просто тут все так навернуто, немудрено что рано или поздно, при росте БД, такой отчет начнет тормозить. Последний раз редактировалось Lemming; 19.11.2009 в 08:51. Причина: Опубликовали метод fetch, тушите свет =)) |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 08:45 | #11 |
Участник
|
Цитата:
Что-то я запутался, так что у Вас сейчас тормозит, "кверик по custtrans" или что-то еще?
__________________
..в каждой программе есть хотя бы одна ошибка.. |
|
19.11.2009, 09:31 | #12 |
Участник
|
Покажите запрос, на базе которого создается queryRun, это можно сделать в том методе где тормозит с помощью: info(queryRun.query().dataSourceTable(tableNum(CustTrans)).toString());
p.s. И все таки, как я уже писал выше, я попробовал бы для начала разделить на два запроса связку проводок и договоров. |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 09:32 | #13 |
Участник
|
По-моему, всё просто: в CustTrans нет индекса поTransDate. Сделайте индекс где TransDate было бы первым полем, и всё будет хорошо.
|
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 14:46 | #14 |
Участник
|
Цитата:
Покажите запрос, на базе которого создается queryRun, это можно сделать в том методе где тормозит с помощью: info(queryRun.query().dataSourceTable(tableNum(CustTrans)).toString());
Цитата:
По-моему, всё просто: в CustTrans нет индекса поTransDate. Сделайте индекс где TransDate было бы первым полем, и всё будет хорошо.
__________________
..в каждой программе есть хотя бы одна ошибка.. |
|
19.11.2009, 14:55 | #15 |
Участник
|
на тестовом сервере отчет летает..на рабочем же тормозит..
может дело в блокировках..?
__________________
..в каждой программе есть хотя бы одна ошибка.. Последний раз редактировалось Alexanderrrr; 19.11.2009 в 15:05. |
|
19.11.2009, 15:11 | #16 |
Участник
|
какой план запроса на рабочем сервере?
|
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 15:26 | #17 |
Участник
|
на CustTrans сохранился индекс, в который входили бы поля TransDate и AccountNum одновременно?
действительно интересно, изменяется ли скорость, если убрать join'ы (зафиксировав параметры)? и еще интересно, что показывает аксаптовский профайлер кода? |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 16:11 | #18 |
Участник
|
Цитата:
Мне кажется SQLServer пытается сначала выбрать все 1,2 млн. записей из CustTrans а уже потом сцепить их c отфильтрованым по GroupFinancId RContractTable. Попробуйте перевернуть Query верх ногами. Либо ещё вариант: заменить Join на ExistsJoin. А уже потом в цикле выбирать RContractTable. И ещё увидел у вас в коде X++: rangeDimension = queryRun.query().dataSourceTable(tableNum(CustTrans)).rangeField(fieldId2ext(fieldnum(CustTrans, Dimension),2)).value(); |
|
|
За это сообщение автора поблагодарили: Alexanderrrr (1). |
19.11.2009, 16:15 | #19 |
Участник
|
Так..выгнал всех с рабочего сервера, переиндексировал используемые в коде индексы, синхронизировал..стало также быстро, как на тестовом сервере..только у меня есть подозрения, что к этому вопросу еще придется возвращаться..таблицы постоянно растут..видимо и правда необходимо пересмотреть логику построения отчета, может использовать вьюшки?
Цитата:
на CustTrans сохранился индекс, в который входили бы поля TransDate и AccountNum одновременно?
Цитата:
действительно интересно, изменяется ли скорость, если убрать join'ы (зафиксировав параметры)?
Цитата:
и еще интересно, что показывает аксаптовский профайлер кода?
время заполнения темповой таблички из custtrans, custinvoicejour и ledgerjournaltrans приблизительно одинаковое..
__________________
..в каждой программе есть хотя бы одна ошибка.. Последний раз редактировалось Alexanderrrr; 19.11.2009 в 16:18. |
|
19.11.2009, 16:23 | #20 |
Участник
|
Цитата:
какой план запроса на рабочем сервере?
A.SETTLEAMOUNTMST,A.CURRENCYCODE,A.DELPOSSIBLECASHDISC,A.DELUTILIZEDCASHDISC,A.DELCASHDISCDATE, A.DUEDATE,A.LASTSETTLEVOUCHER,A.LASTSETTLEDATE,A.CLOSED,A.TRANSTYPE,A.APPROVEDBY,A.APPROVED, A.DIMENSION,A.DIMENSION2_,A.DIMENSION3_,A.EXCHADJUSTMENT,A.DOCUMENTNUM,A.DOCUMENTDATE,A.LASTEXCHADJ, A.CORRECT,A.SETTLEMENT,A.DEL_OPENTRANS,A.INTEREST,A.COLLECTIONLETTER,A.POSTINGPROFILECLOSE,A.FROMACCOUNT,A.TOACCOUNT, A.DELOPEN,A.PAYMMODE,A.PAYMREFERENCE,A.PAYMMETHOD,A.CASHPAYMENT,A.CONTROLNUM,A.DELIVERYMODE,A.POSTINGPROFILE, A.OFFSETRECID,A.EUROTRIANGULATION,A.ORDERACCOUNT,A.CASHDISCCODE,A.PREPAYMENT,A.DEL_EXCHADJUSTMENTTOTAL,A.PAYMSPEC, A.CUSTEXCHADJUSTMENTREALIZED,A.CUSTEXCHADJUSTMENTUNREALIZED,A.OCRLINE,A.PAYMMANLACKDATE,A.PAYMMANBATCH,A.PAYMID, A.BILLOFEXCHANGEID,A.BILLOFEXCHANGESTATUS,A.BILLOFEXCHANGESEQNUM,A.BANKREMITTANCEFILEID,A.COLLECTIONLETTERCODE,A.PREPAYMENTINVOICE_RU, A.CASHPAYMENT_RU,A.SETTLESALESTAXONPAYMENT_RU,A.SALESTAXONPAYMENT_RU,A.RTAX25AMORTISATION,A.RCONTRACTCODE, A.RCONTRACTACCOUNT,A.MODIFIEDDATE,A.MODIFIEDTIME,A.MODIFIEDBY,A.MODIFIEDTRANSACTIONID,A.CREATEDDATE,A.CREATEDTIME, A.CREATEDBY,A.CREATEDTRANSACTIONID,A.RECVERSION,A.RECID,B.RCONTRACTPARTNERTYPE,B.RCONTRACTACCOUNT,B.RCONTRACTNUMBER, B.CONTRACTDATE,B.CONTRACTSTARTDATE,B.CONTRACTENDDATE,B.CONTRACTAMOUNT,B.CONTRACTVATAMOUNT,B.CURRENCYCODE, B.CONTRACTPAYMCODE,B.RCONTRACTPARTNERCODE,B.RCONTRACTSTATUS,B.CONTRACTPOSTINGPROGILE,B.CONTRACTPREPAYMENTPOSTING16014, B.CONTRACTRESPONSIBLEPERSON,B.CONTACTPERSONID,B.CONTRACTPAYMMODE,B.CONTRACTPAYMSPEC,B.CONTRACTPAYMENTSCHED, B.CONTRACTCASHDISC,B.CONTACTPHONE,B.LINEOFBUSSENESID,B.CONTACTTELEX,B.CONTACTURL,B.CONTACTEMAIL,B.CONTACTTELEFAX, B.CONTACTCELLULARPHONE,B.CONTACTPHONELOCAL,B.CONTRACRTHRMORGANISATIONID,B.RCONTRACTCODE,B.RCONTRACTPAYMDAYID, B.RCONTRACTACCOUNTBASIC,B.RCONTRACTCODEBASIC,B.RCONTRACTPARTNERCODEBASIC,B.PERIODEXPOSINVOICE4PAYM, B.PERIODGRANTEVIDENCE,B.DAYSHOOTEVIDENCE,B.PERIODADVANCEPAYMENT,B.FACTOREXCESS,B.BANKACCOUNTID, B.GROUPFINANCID,B.DECEMBER,B.NOVEMBER,B.OCTOBER,B.SEPTEMBER,B.AUGUST,B.JULY,B.JUNE,B.MAY,B.APRIL,B.MARCH, B.FEBRUARY,B.JANUARY,B.PERCENTADVANCE,B.SOURCE,B.PARAMETERWARNING,B.TYPECONTRACT,B.CONTRACTNUMBERDATE, B.EXPOSEPAYMENT,B.ACCEPTANCE,B.PERIODACCEPT,B.TERMPAYMENT,B.PERIODPAYMENT,B.DELIVERY,B.CONTRACTFORM,B.PROLONG, B.VIEWWARNING,B.ISWARN,B.PARMADVANCECALC,B.REGIONNETID,B.PRINTMARK,B.SPGESCONTRACTADD,B.SPGESGRUZOPOKUP,B.SPGESSITE, B.MODIFIEDDATE,B.MODIFIEDTIME,B.MODIFIEDBY,B.CREATEDDATE,B.CREATEDTIME,B.CREATEDBY,B.RECVERSION,B.RECID,B.RCONTRACTSUBJECT FROM CUSTTRANS A,RCONTRACTTABLE B WHERE ((A.DATAAREAID='Company') AND (A.TRANSDATE<={TS '2008-12-31 00:00:00.000'})) AND ((B.DATAAREAID='Company') AND (((((B.GROUPFINANCID='ТСЖ 1') AND (B.RCONTRACTPARTNERTYPE=0)) AND (A.ACCOUNTNUM=B.RCONTRACTPARTNERCODE)) AND (A.RCONTRACTACCOUNT=B.RCONTRACTACCOUNT)) AND (A.RCONTRACTCODE=B.RCONTRACTCODE))) ORDER BY A.DATAAREAID,A.TRANSDATE,A.ACCOUNTNUM,A.VOUCHER OPTION(FAST 7) Цитата:
И ещё увидел у вас в коде
X++: rangeDimension = queryRun.query().dataSourceTable(tableNum(CustTrans)).rangeField(fieldId2ext(fieldnum(CustTrans, Dimension),2)).value(); Вы этот фильтр не используете. он пустой во время тестирования?
__________________
..в каждой программе есть хотя бы одна ошибка.. |
|
|
|