|
20.11.2024, 12:40 | #1 |
Участник
|
Ax 2012 строит запрос с ошибкой в синтаксисе
Добрый день!
Сколько не искал, похожих проблем как-будто ни у кого не было. Время от времени аксапта делает до этого работавшие запросы неправильно - с ошибкой в синтаксисе. И получаем ошибку: Цитата:
Невозможно выбрать запись в Акции по приоритетам (PublicityPriorTempDb). Код акции: 0.
База данных SQL обнаружила ошибку. Описание ошибки SQL: [Microsoft][SQL Server Native Client 11.0][SQL Server]Неправильный синтаксис около конструкции "(". Оператор SQL: SELECT TOP 1 T1.PUBLICITYJOURNALRECID,T1.ITEMID,T1.PARTITION,101090 FROM tempdb."DBO".t106966_ACAE536E796A4D7783471D261AF32F8E T1 WITH ( INDEX(i106966_I_106966PUBLICITYJOURNALRECIDX_(null))) WHERE (((PARTITION=?) AND (DATAAREAID=?)) AND (PUBLICITYJOURNALRECID=?)) (null) - быть не должно. Сам запрос в аксапте выглядит так: X++: select firstOnly PublicityJournalRecId from PublicityPriorTempDb where PublicityPriorTempDb.PublicityJournalRecId == PublicityJournalTableCurrent.RecId https://ibb.co/vZtBQc1 И свойства таблицы: https://ibb.co/P5BX7Hj Ошибка исправляется, если удалить индекс. А потом создать другой с другим именем. Встречалась и на обычных таблицах, не TempDb. Подскажите, что это может быть? Баг в ядре? Куда вообще смотреть? Последний раз редактировалось Gibrid; 20.11.2024 в 12:46. |
|
20.11.2024, 13:32 | #2 |
Участник
|
- Ребут АОСа не помогает ? Те запросы работали, работали, а потом хоп и перестали работать и всегда падает на одной и той же строчке и так до тех пор пока не переименуешь индекс ?
- перед запросом с курсором никакие манипуляции не делаем ? те он просто объявлен, заполнен и потом запрос или все таки что-то есть ? with означает явную подсказку какой индекс использовать, но в 2012 насколько я знаю такое по умолчанию отключено (есть недокументированная возможность активации, но официальной поддержки такой штуки нет), возможно для tempDB такое работает всегда при использовании инструкций, но как то не верится. какая у вас версия 2012 ? вместо null по идее должно быть имя экземпляра таблички, т.е. что то типа 106966_I_106966PUBLICITYJOURNALRECIDX_ACAE536E796A4D7783471D261AF32F8E - а поскольку null то каким то образом ссылка на экземпляр исчезает - запрос генерит ядро, поэтому скорее всего ошибка в нём. а что с постоянным таблицами, как выглядит текст ошибки - дословно такой же? просто там название индекса всегда фиксированно и _ добавлять не надо в конце
__________________
Sergey Nefedov |
|
20.11.2024, 14:56 | #3 |
Участник
|
Цитата:
Цитата:
Цитата:
Сообщение от SRF
with означает явную подсказку какой индекс использовать, но в 2012 насколько я знаю такое по умолчанию отключено (есть недокументированная возможность активации, но официальной поддержки такой штуки нет), возможно для tempDB такое работает всегда при использовании инструкций, но как то не верится.
2012 R3 6.3.164.0 Цитата:
Точного текста сейчас нет, но смысл тот же, в скобках индекса null |
|
20.11.2024, 17:53 | #4 |
Участник
|
Странный номер
Посмотрите в свойствах для файла Ax32Serv.exe Должно быть что-то более информативное, типа 6.3.6000.8144 если же все равно показывает 6.3.164.0 то это какая-то ерунда. Проверяйте свою инсталляцию. Возможно не все нормально установлено, обновлено. |
|
21.11.2024, 09:31 | #5 |
Участник
|
В свойствах файла 6.3.6000.151
|
|
21.11.2024, 12:24 | #6 |
Участник
|
Судя по
https://www.microsoft.com/en-us/dyna...urce=axsupport у вас голый CU13 не самый свежий билд, но детских багов там уже не должно бы быть. Странно. |
|
20.11.2024, 14:16 | #7 |
Участник
|
А сама таблица в базе TempDB на момент выполнения запроса существует? Окончание индекса ведь строится по реальному физическому имени таблицы в базе данных TempDB. Если таблицы нет, то какое имя добавлять?
При работе с временными таблицами TempDB рекомендуется сначала выполнить их инициализацию X++: // Force instantiation of Temp DB table. select generateonly firstonly RecId from PublicityPriorTempDb; Это делается в методе RetailUtilities::getPhysicalTableName(). Т.е. код такой получается X++: RetailUtilities::getPhysicalTableName(PublicityPriorTempDb);
// Далее код по наполнению временной таблицы PS: Ну и добавление хинта в запросе - это настойки AOS. Лучше этого не делать. По умолчанию, в dax2012 они отключены.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Pandasama (3). |
20.11.2024, 14:59 | #8 |
Участник
|
Цитата:
Цитата:
Сообщение от Владимир Максимов
При работе с временными таблицами TempDB рекомендуется сначала выполнить их инициализацию
X++: // Force instantiation of Temp DB table. select generateonly firstonly RecId from PublicityPriorTempDb; Это делается в методе RetailUtilities::getPhysicalTableName(). Т.е. код такой получается X++: RetailUtilities::getPhysicalTableName(PublicityPriorTempDb);
// Далее код по наполнению временной таблицы Хинты выключены, и в самом запросе их нет. |
|
20.11.2024, 14:42 | #9 |
Участник
|
Цитата:
При работе с временными таблицами TempDB рекомендуется сначала выполнить их инициализацию
А какой это эффект дает? каких проблем помогает избежать? |
|
20.11.2024, 18:50 | #10 |
Участник
|
А, еще интересно какой уровень совместимости на SQL базе стоит.
Если выставить SQL2016 проблема пропадет или нет. |
|
21.11.2024, 08:25 | #11 |
Участник
|
Цитата:
Окончание индекса ведь строится по реальному физическому имени таблицы в базе данных TempDB. Если таблицы нет, то какое имя добавлять?
Сейчас немного смущают следующие моменты - в примере в запросе один ID, а на скринах ID таблички другой - запрос с одной инсталляции, скрины AOT с другой ? - в коде мы выбираем только одно поле, в запросе присутствуют все поля - хотя индексы не кластерные, кеширование отключено, интересно почему выбираются все поля, мб потому что tempDB. - не помогает ребут, те это меняется что-то в каких-то постоянных характеристиках системы, а не кеш\память и т.д. - так а на всех ли инсталляциях проявляется проблема, на разных АОСах, в пакетном режиме ? - что в EV на АОСе ? Там эта ошибка есть, другие ? - если снять трассировки SQL запросов (например через TraceParser) в этом функционале после исправления проблемы и просто в других местах системы - все ли запросы уходят с with ? (опять таки если несколько АОСов то попробовать снять трассировки на разных)
__________________
Sergey Nefedov |
|
21.11.2024, 09:50 | #12 |
Участник
|
Цитата:
Цитата:
Сразу не посмотрел, а сейчас почему-то не вижу на этом аосе события старше 1 дня. Не пойму почему. |
|
21.11.2024, 12:10 | #13 |
Участник
|
Цитата:
Сообщение от Gibrid
Вылезает проблема не так часто, раз в пол года может... Статистики еще не набралось. Единственное, в последний раз, когда появилась проблема ночью, чуть позже перезагрузился кластер со всеми аосами и скулем... После этого пакетник с этим запросом 1 раз отработал, а потом опять начал падать в ошибку.
Сразу не посмотрел, а сейчас почему-то не вижу на этом аосе события старше 1 дня. Не пойму почему. - в логах (batchlog) работы пакетника можно глянуть на каких АОСах были падения - разные там или не разные, но так скорее для статистики - попробуйте поснимать трейсы своего процесса и посмотреть запрос на котором падает, трейсы можно снимать через счетчики windows - https://www.microsoft.com/en-us/down....aspx?id=27549, т.е. можете прямо пакетные задачи посмотреть - настраивать надо будет на всех АОСах где может выполняться пакетное задание. посмотрите на разных аосах\окружениях одни и те же запросы, одинаковые ли хинты там. - еще про with - часть запросов без with - а там есть хинт top 1, что то подозрение возникает о том, что with появляется, если в запросе есть firstOnly - попробуйте поменять ваш запрос на count() и посмотреть будет ли with в запросе (понятно что это как закат солнца вручную, но как костыль возможно подойдет) - насколько я понимаю билды у вас не последние, как MS в этом случае рекомендует - обновите ядро - а что вы делаете с постоянными табличками - там тоже название индекса меняете или делаете синхронизацию\пересоздание индекса? помогает ли просто пересоздание индекса ?
__________________
Sergey Nefedov |
|
21.11.2024, 13:30 | #14 |
Участник
|
|
|
21.11.2024, 13:32 | #15 |
Участник
|
Цитата:
Сообщение от SRF
- это к админам, скорее всего могли настроить так хранение логов.
- в логах (batchlog) работы пакетника можно глянуть на каких АОСах были падения - разные там или не разные, но так скорее для статистики - попробуйте поснимать трейсы своего процесса и посмотреть запрос на котором падает, трейсы можно снимать через счетчики windows - https://www.microsoft.com/en-us/down....aspx?id=27549, т.е. можете прямо пакетные задачи посмотреть - настраивать надо будет на всех АОСах где может выполняться пакетное задание. посмотрите на разных аосах\окружениях одни и те же запросы, одинаковые ли хинты там. - еще про with - часть запросов без with - а там есть хинт top 1, что то подозрение возникает о том, что with появляется, если в запросе есть firstOnly - попробуйте поменять ваш запрос на count() и посмотреть будет ли with в запросе (понятно что это как закат солнца вручную, но как костыль возможно подойдет) - насколько я понимаю билды у вас не последние, как MS в этом случае рекомендует - обновите ядро |
|
21.11.2024, 10:08 | #16 |
Участник
|
Цитата:
|
|
21.11.2024, 10:55 | #17 |
Участник
|
Цитата:
К примеру: X++: SELECT TOP 1 T1.BATCHJOBCANCELED, T1.BATCHJOBENDED, T1.BATCHJOBERROR, T1.BATCHJOBID, T1.USERID, 101090 FROM BATCHJOBALERTS T1 WITH ( INDEX(I_2004BATCHJOBID)) WHERE ((BATCHJOBID=5639649525) |
|
21.11.2024, 09:36 | #18 |
Участник
|
|
|
21.11.2024, 10:19 | #19 |
Administrator
|
Он у Вас стоит - Средства разработки-Синтаксический анализатор журнала. Посмотрите в Program Files папки
__________________
Возможно сделать все. Вопрос времени |
|
|
За это сообщение автора поблагодарили: Gibrid (1). |
22.01.2025, 18:29 | #20 |
Участник
|
Поразбирались еще в проблеме.
Что было у нас. Включили index hint в конфигурации аоса (ключ hint в реестре, поменяли значение с 2 на 3) После этого ядро стало ставить в запросах index hint там где они указаны в коде явно. А там, где явно в коде не указаны, ядро может подставить их по своему усмотрению в зависимости от условий фильтрации (если сочтет какой-либо индекс подходящим под условия). Или оставит бех хинтов. В общем, поведение как в Ax3.0 KR1 Правда там (в Ax3) был еще флажок 512 который позволял отключать автоматический подбор хинтов. Обсуждался тут : Кто использует KR3 ? Но в 2012-й он не работает. При попытке явно указать такой флаг конфигурационная утилита пишет что: Цитата:
An unsupported value for the hints option has been detected. The default value has been restored, which affects the following settings: - Allow INDEX hints in queries (off by default) - Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems (off by default) - Include LTRIM in all SELECT statements to remove leading space from right-aligned columns (off by default). If you do not change the settings now, they will be saved with default values.
В конкретном запросе автоподбор хинта ядром можно подавить, указав index имя индекса тогда добавится сортировка по указанному индексу но хинтов не будет. Либо (как подсказал Glibs, за что ему respect) можно завести на табличке пустой выключенный индекс, например с именем NoHintIdx и указать его явно как хинта index hint NoHintIdx тогда никакого хинта не будет. Мы явно указали индексы хинт, поэтому ядро прекращает самодеятельность, но поскольку реального индекса такого в БД нет, то ничего не ставит. Про кривое формирование текста запроса, я заметил что в одних случаях запрос к времянке идет нормально с таким именем X++: SELECT TOP 1 ... FROM tempdb."DBO".t105707_0152F6081B43458B87857CD84D429941 T1 WITH ( INDEX(i105707_I_105707PHONEIDX_0152F6081B43458B87857CD84D429941)) WHERE ... X++: SELECT TOP 1 ... FROM tempdb."DBO".t105707_0152F6081B43458B87857CD84D429941 T1 WITH ( INDEX(i105707_I_105707PHONEIDX_(null))) WHERE ... Стали разбираться, оказалось что это происходит после вызова метода xRecord.linkPhysicalTableInstance(). Похоже linkPhysicalTableInstance переназначает в ядре ссылки с одной таблички на другую, но не все данные копирует правильно. Что-то остается непроинициализированным. И проявляется это не всегда, а только при стечении обстоятельств. А вот если для тех же целей воспользоваться парой методов xRecord.getPhysicalTableName() / xRecord.useExistingTempDBTable() то все хорошо. Хинты с правильными именами формируются. Поэтому сделали на SysDictTable свой метод и используем его вместо xRecord.linkPhysicalTableInstance() X++: /// <summary> /// _thisRecord начинает ссылаться на данные _record /// Метод сделан как замена стандартному xRecord.linkPhysicalTableInstance() чтобы обойти его ошибки. /// подробнее см. /// [url=https://axforum.info/forums/showthread.php?p=443440#post443440]Ax 2012 строит запрос с ошибкой в синтаксисе[/url] /// [url=https://axforum.info/forums/showthread.php?p=437193#post437193]Работа с TempDB-таблицами[/url] /// </summary> /// <param name="_thisRecord"> /// Таблица, у которой переназначаются данные. /// </param> /// <param name="_record"> /// Таблица, на чьи данные теперь будут ссылаться /// </param> /// <returns> /// Успешно или нет /// </returns> /// <remarks> /// /// </remarks> // CustCrmClientActivityDocTmp_MRC_Fix "Исправляем ошибку WITH ( INDEX(i105707_I_105707PHONEIDX_(null)))", PKoz3 22.01.2025 public static boolean linkPhysicalTableInstance_MRC(Common _thisRecord, Common _record) { Common tmpRecord; str tableName; boolean ret; ; tableName = _record.getPhysicalTableName(); if (!tableName) // значит табличку не сохраняли еще { tmpRecord = _record.data(); // см. RetailUtilities::getPhysicalTableName(_record); // Force instantiation of Temp DB table. select generateonly firstOnly RecId from _record; tableName = _record.getPhysicalTableName(); _record.data(tmpRecord); } ret = _thisRecord.useExistingTempDBTable(tableName); // ret = _thisRecord.linkPhysicalTableInstance(_record); // такой вариант вместо вызова useExistingTempDBTable() не работает // проверяли предположение что проблема была в том, что вызвали linkPhysicalTableInstance для непроинициализированного параметра // в котором еще нет физического имени таблицы (не в этом ли корень проблем ? Поэтому сперва принудительно инициализируем буфер, // чтобы вызов linkPhysicalTableInstance гарантированно шел на проинициализированном TempDb буфере) // Оказалось что нет - ошибка с хинтом воспроизводится после любого вызова linkPhysicalTableInstance // т.е. сам по себе linkPhysicalTableInstance - какой то кривой и что-то портит в xRecord, поэтому лучше // избегать вызовов linkPhysicalTableInstance return ret; } linkPhysicalTableInstance - вообще какой-то стремный и глючный. Работа с TempDB-таблицами Работа с TempDB-таблицами поэтому сделали еще проверку BP. Класс SysBPCheckMemberFunction добавили метод checkSourceLinkPhysicalTableInstance X++: /// /// <summary> /// Делаем запрет на вызов common.linkPhysicalTableInstance /// </summary> // CustCrmClientActivityDocTmp_MRC_Fix "Исправляем ошибку WITH ( INDEX(i105707_I_105707PHONEIDX_(null)))", PKoz 22.01.2025 protected boolean checkSourceLinkPhysicalTableInstance(xRefTmpReferences _thisRefererences) { boolean ret = true; ; while select _thisRefererences where _thisRefererences.Kind == xRefKind::TableInstanceMethod && _thisRefererences.Reference == XRefReference::Call && _thisRefererences.Name == methodStr(xRecord, linkPhysicalTableInstance) { this.addSuppressableError(#BPErrorTableLinkPhysicalTableInstance_MRC, // так удобнее _thisRefererences.Line, _thisRefererences.Column, strFmt(@'Вызов метода "%1.%2" лучше заменить на вызов метода %3::%4 Подробности в исходном коде %3::%4.', _thisRefererences.ParentName, // 1 _thisRefererences.Name, // 2 classStr(SysDictTable), // 3 staticMethodStr(SysDictTable, linkPhysicalTableInstance_MRC) // 4 ) ); ret = false; } return ret; } |
|
|
За это сообщение автора поблагодарили: raz (10). |
Теги |
index hint, linkphysicaltableinstance |
|
|