10.11.2008, 11:27 | #1 |
Участник
|
Вопрос по force*
Есть класс InventSumOpenTransact\setValueQty()
В нём код X++: while select forcePlaceholders forceSelectOrder forceNestedLoop inventTrans index hint OpenItemIdx where inventTrans.itemId == itemId && inventTrans.valueOpen == InventTransOpen::Yes && inventTrans.statusReceipt >= StatusReceipt::None && inventTrans.statusReceipt <= StatusReceipt::Purchased && inventTrans.statusIssue >= StatusIssue::None && inventTrans.statusIssue <= StatusIssue::Sold && inventTrans.dateFinancial <= perDate #inventDimJoin(inventTrans.inventDimId,inventDim,inventDimCriteria,inventDimParm,dimIdIdx) { this.add(inventTrans); } Если делаю убираю force*, правильное значение X++: while select inventTrans index hint OpenItemIdx where inventTrans.itemId == itemId && inventTrans.valueOpen == InventTransOpen::Yes && inventTrans.statusReceipt >= StatusReceipt::None && inventTrans.statusReceipt <= StatusReceipt::Purchased && inventTrans.statusIssue >= StatusIssue::None && inventTrans.statusIssue <= StatusIssue::Sold && inventTrans.dateFinancial <= perDate #inventDimJoin(inventTrans.inventDimId,inventDim,inventDimCriteria,inventDimParm,dimIdIdx) { this.add(inventTrans); } X++: inventTrans.disableCache(true); while select forcePlaceholders forceSelectOrder forceNestedLoop inventTrans index hint OpenItemIdx where inventTrans.itemId == itemId && inventTrans.valueOpen == InventTransOpen::Yes && inventTrans.statusReceipt >= StatusReceipt::None && inventTrans.statusReceipt <= StatusReceipt::Purchased && inventTrans.statusIssue >= StatusIssue::None && inventTrans.statusIssue <= StatusIssue::Sold && inventTrans.dateFinancial <= perDate #inventDimJoin(inventTrans.inventDimId,inventDim,inventDimCriteria,inventDimParm,dimIdIdx) { this.add(inventTrans); } Только тогда не обратил внимание что это из-за force* Код был мой и за результаты был уверен спокойно поставил inventTrans.disableCache(true) и всё ок. Может кто-то обяснит почему с использованием force* могут данные не актуальные вернуться. Может на Oracle какие-нибудь дополнительные настройки поставить, чтоб правильно запрос отрабатывал.
__________________
Энергия молодых и неравнодушных способна изменить мир к лучшему. |
|
10.11.2008, 11:47 | #2 |
Участник
|
По идее - force не должен влиять. Это же только подсказка оптимизатору, как лучше выполнить запрос. Результат отличаться не должен.
Возможно причина в том что Аксапта в случае с force - кеширует запрос. А когда вы ставите без force - то она видит что запрос отличается от того который был ранее и кеш не использует. В общем правильнее принудительно отключить кеширование X++: inventTrans.disableCache(true); Последний раз редактировалось Logger; 10.11.2008 в 11:51. |
|
10.11.2008, 11:51 | #3 |
Участник
|
Если бы у InventTrans не было бы recId (группировка какая нибудь была), я бы тоже подумал, что может запрос не правильный ушёл.
Но ведь recId есть. Я даже find по нему пробовал перед запросом делать. find возвращает правильное значение, а запрос нет.
__________________
Энергия молодых и неравнодушных способна изменить мир к лучшему. |
|
10.11.2008, 11:55 | #4 |
Участник
|
Похожий глюк
Глюки RecordViewCache |
|
10.11.2008, 11:56 | #5 |
Участник
|
Вы сперва профайлером посмотрите- запрос на БД какой-нить уходит вообще или нет.
В случае когда глючит кеширование - запрос на БД вообще не уходит. |
|
10.11.2008, 13:33 | #6 |
Member
|
Наблюдал похожий глюк именно на Oracle (на MS SQL не удалось тогда воспроизвести).
Запрос был простенький типа select currency where currency.CurrencyCode == "XXXY" Когда в качестве кода валюты передавался код несуществующей валюты длиной в 4 символа (тестировалась проверка на некорректное значение валюты при импорте из другой системы), то возвращалась запись, код которой совпадал с первыми тремя символами неправильного кода. Ожидалось же, что запись не вернется и система выругается. Дальше из-за этого получался какой-то конфуз. Т.е. в режиме FORCEPLACEHOLDERS Oracle как-то умудрялся резать значение переменной, и в запрос уходило уже не то значение, которое запрашивалось, а подрезанное. select forceliterals currency where currency.CurrencyCode == "XXXY" Дал ожидаемый результат (ничего не вернул). Возможно, и в вашем случае можно поближе докопаться до причины.
__________________
С уважением, glibs® |
|
10.11.2008, 13:53 | #7 |
Участник
|
Цитата:
X++: SELECT /*+ INDEX(A I_177OPENITEMIDX) INDEX(B I_698DIMIDIDX) ORDERED */A.ITEMID,A.STATUSISSUE,A.DATEPHYSICAL,A.QTY,A.COSTAMOUNTPOSTED,A.CURRENCYCODE,A.TRANSTYPE,A.TRANSREFID,A.INVOICEID,A.VOUCHER,A.DATEEXPECTED,A.DATEFINANCIAL,A.COSTAMOUNTPHYSICAL,A.INVENTTRANSID,A.STATUSRECEIPT,A.PACKINGSLIPRETURNED,A.INVOICERETURNED,A.PACKINGSLIPID,A.VOUCHERPHYSICAL,A.COSTAMOUNTADJUSTMENT,A.QTYSETTLED,A.COSTAMOUNTSETTLED,A.VALUEOPEN,A.DIRECTION,A.DATESTATUS,A.COSTAMOUNTSTD,A.DATECLOSED,A.DEL_CONFIGID,A.INVENTTRANSIDFATHER,A.COSTAMOUNTOPERATIONS,A.ITEMBOMID,A.INVENTTRANSIDRETURN,A.PROJID,A.PROJCATEGORYID,A.INVENTDIMID,A.INVENTDIMFIXED,A.DATEINVENT,A.CUSTVENDAC,A.TRANSCHILDREFID,A.TRANSCHILDTYPE,A.REVENUEAMOUNTPHYSICAL,A.ASSETID,A.PROJADJUSTREFID,A.DEL_TAXAMOUNTPHYSICAL,A.ASSETBOOKID,A.INVENTREFTRANSID,A.CORRECT,A.GM_LEDGERCORRECT,A.COMPENSATE,A.IMPRESERVETYPE,A.MRD_INVENTREFTRANSID,A.MODIFIEDDATE,A.MODIFIEDTIME,A.MODIFIEDBY,A.CREATEDDATE,A.CREATEDTIME,A.CREATEDBY,A.RECVERSION,A.RECID FROM INVENTTRANS A,INVENTDIM B WHERE ((SUBSTR(NLS_LOWER(A.DATAAREAID),1,3)=NLS_LOWER(:IN1)) AND (((((((SUBSTR(NLS_LOWER(A.ITEMID),1,30)=NLS_LOWER(:IN2)) AND (A.VALUEOPEN=:IN3)) AND (A.STATUSRECEIPT>=:IN4)) AND (A.STATUSRECEIPT<=:IN5)) AND (A.STATUSISSUE>=:IN6)) AND (A.STATUSISSUE<=:IN7)) AND (A.DATEFINANCIAL<=:IN8))) AND ((SUBSTR(NLS_LOWER(B.DATAAREAID),1,3)=NLS_LOWER(:IN9)) AND (((SUBSTR(NLS_LOWER(B.INVENTDIMID),1,30)=SUBSTR(NLS_LOWER(A.INVENTDIMID),1,30)) AND (SUBSTR(NLS_LOWER(B.INVENTLOCATIONID),1,18)=NLS_LOWER(:IN10))) AND (SUBSTR(NLS_LOWER(B.INVENTDIMDEFECT),1,10)=NLS_LOWER(:IN11))))
__________________
Энергия молодых и неравнодушных способна изменить мир к лучшему. |
|
10.11.2008, 14:21 | #8 |
Участник
|
Я думал у вас результат из кеша берется. В таком случае возможно получение результата без обращения к БД.
|
|
10.11.2008, 14:24 | #9 |
Участник
|
Вообще-то, смысл хинта forcePlaceholders заключается в том, что SQL-сервер должен использовать ранее сформированный план для аналогичного запроса изменяя только параметр.
Соответственно хинт forceLiterals имеет противоположный смысл. Не использовать ранее сформированный план запроса, а каждый раз заново формировать этот план. Т.е. эти хинты должны влиять только на повторные запросы и только в том случае, если на сервере еще сохранился план выполнения аналогичного запроса исполненного ранее. Имеет смысл при выполнении запросов в цикле. Запрос, разумеется, будет посылаться на сервер в любом случае. Вопрос в том, с какими параметрами. Т.е. смотреть надо не на запрос, а на переданные параметры. Вероятно, Oracle в плане запроса как-то кеширует еще и возможные значения параметров (тип, размер)? |
|
10.11.2008, 14:26 | #10 |
Участник
|
Цитата:
Либо возможно глюк в этом и состоял, что из неправильного кода путем усечения в условии currency.CurrencyCode == "XXXY" на месте "XXXY" стояла переменная со значением "ХХХ" - но это уже глюк программиста X++ |
|
10.11.2008, 15:08 | #11 |
Member
|
Цитата:
Сообщение от Logger
...
Запрос наверно как Query был составлен ? ... Цитата:
Сообщение от Logger
...
но это уже глюк программиста X++ ...
__________________
С уважением, glibs® |
|
10.11.2008, 15:34 | #12 |
Участник
|
Цитата:
Сообщение от glibs
Нет.
Я тестировал на джобе. Иначе фиг такое отловишь. В условии писал строку, а не переменную. Это какая-то особенность Ораклиного движка. Код валюты в БД определен как трехсимвольная строка. И при placeholders, видать, он режет input. Если это знать и учесть, то в принципе не проблема. Просто нужно знать. Мне кажется что когда указываешь константу он просто приводит её неявным преобразованием типов к нужной длине, как например при присваивании строковых переменных с разной длиной. |
|
10.11.2008, 17:46 | #13 |
Участник
|
Цитата:
Цитата:
Сообщение от gl00mie
Был аналогичный косяк, правда, на Oracle с его NSL_LOWER(), SUBSTR() и прочими функциями. В частности, при работе с Oracle из строковых полей вырезаются подстроки длины EDT. Так вот, пытался я join'ить по InventTrans.TransRefId = InventJournalTable.JournalId, и тоже ничего не работало; дело оказалось в том, что у EDT JournalId и InventTransRefId разная длина, в результате на СУБД уходил запрос вида
PHP код:
Последний раз редактировалось petergunn; 10.11.2008 в 17:51. |
|
10.11.2008, 19:42 | #14 |
Участник
|
Неее. Там немного другой случай.
Там джоин двух таблиц, а с точки зрения SQL строковые типы разной длины - это разные типы. А здесь именно параметр запроса. |
|