Показать сообщение отдельно
Старый 22.01.2025, 18:29   #23  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,968 / 3266 (116) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Поразбирались еще в проблеме.

Что было у нас.

Включили 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 ...
т.е. ядро где-то теряет инфу об имени индекса или инфу о реальном имени SQL временной таблицы, подставляя вместо имени 0152F6081B43458B87857CD84D429941 значение (null) т.е. что-то недоинициализировано.

Стали разбираться, оказалось что это происходит после вызова метода 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).