AXForum  
Вернуться   AXForum > Прочие обсуждения > Курилка
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 18.01.2023, 16:05   #461  
trud is offline
trud
Участник
Лучший по профессии 2017
 
1,038 / 1629 (57) ++++++++
Регистрация: 07.06.2003
Записей в блоге: 1
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Хотя в данном случае, вроде бы, речь идет не об идентификаторе записи (RecId), а о некоем общем идентификаторе "процесса" вроде ParmId. Т.е. вроде бы, и не выбивается из общих принципов построения приложения в данном случае.
Ну да, собственно Владимир ответил. Т.е. в системе есть некие принципы, если что-то нумеровать, можно использовать номерную серию. Номерные серии - это довольно крутой механизм, заложенный в системе, как раз для проблемы нумерации.
Если использовали GUID - опять же, могу ошибаться, но тут скорее всего пришли люди которые с системой до этого не работали(не знают что такое номерные серии), и начали проектировать данные таблицы.
Можно конечно предположить, ну ладно, системы не знают, но наверное технически специалисты хорошие. Но в этом заставляет сомневаться вот такие графики в презентации (нет подписей для оси Х и У, непонятно что вообще проверяли)
Нажмите на изображение для увеличения
Название: PerformanceImpr.png
Просмотров: 47
Размер:	41.5 Кб
ID:	13536
Плюс я немного работал над оптимизаций складов, и я никогда не видел в топе нагрузки запросы связанные именно с InventTrans, а те что были, они бы к примеру выиграли от денормализации InventTrans, добавления к примеру туда всех полей аналитик(но тут явно обратный процесс)

Что они запроектируют - даже страшно представить, но будем надеяться на лучшее
Старый 18.01.2023, 17:24   #462  
ТРЕНЕР is offline
ТРЕНЕР
Участник
Аватар для ТРЕНЕР
 
584 / 47 (3) +++
Регистрация: 11.06.2003
Адрес: Москва
Цитата:
Сообщение от trud Посмотреть сообщение
(у которой по видимому есть "фатальный недостаток")
На скриншоте в первой таблице написано Tranasctions вместо Transactions.
Это фатальный недостаток команды в целом.
За это сообщение автора поблагодарили: gl00mie (2).
Старый 18.01.2023, 21:07   #463  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,816 / 3011 (108) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от ТРЕНЕР Посмотреть сообщение
На скриншоте в первой таблице написано Tranasctions вместо Transactions.
Это фатальный недостаток команды в целом.
Ну мы же жили много лет с PostingProgile - ом и никто не умер.
Но конечно тоже резануло глаз.
За это сообщение автора поблагодарили: axm2017 (12).
Старый 01.03.2023, 11:28   #464  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,816 / 3011 (108) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от fed Посмотреть сообщение
GUID проще выделить до записи в БД. То есть - в принципе UnitOfWork или махинации с suspendRecId() решают проблему, но MkGuid() все равно проще написать.
Проще конечно, но если хочется упрощения то можно также еще задействовать готовый
\Data Dictionary\Tables\EventInbox\Methods\nextEventId

или свой системный счетчик 64-битных идентификаторов сделать один раз по аналогии. И вести его в разрезе TableId.
За это сообщение автора поблагодарили: fed (5).
Старый 27.03.2023, 09:34   #465  
axm2017 is offline
axm2017
Участник
 
1,715 / 293 (13) ++++++
Регистрация: 15.05.2017
X++:
        public void delete()
        {
            super();

            element.updateWorkflowButtonEnabled();
            element.updateWorkflowButtonForLineVisibility();

            element.close();
        }
На форме PurchReqTable непонятное при удалении записи. Ок смирился что закрывают форму но зачем перед этим менять кнопки?
Старый 31.03.2023, 14:38   #466  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
639 / 300 (12) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от axm2017 Посмотреть сообщение
X++:
        public void delete()
        {
            super();

            element.updateWorkflowButtonEnabled();
            element.updateWorkflowButtonForLineVisibility();

            element.close();
        }
На форме PurchReqTable непонятное при удалении записи. Ок смирился что закрывают форму но зачем перед этим менять кнопки?
Возможно, до этого не закрывали форму, потом просто добавили close().

Метод delete() на датасорсе PurchReqTable, верно?
Посмотрел на R3, присутствует только вызов close().
__________________
// no comments

Последний раз редактировалось dech; 31.03.2023 в 14:52.
Старый 31.03.2023, 15:28   #467  
axm2017 is offline
axm2017
Участник
 
1,715 / 293 (13) ++++++
Регистрация: 15.05.2017
На 365
Старый 26.04.2023, 14:01   #468  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,422 / 1768 (65) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
В классе Global метод con2Str
В стандарте, если в контейнере значения первых позиций будут пустыми строками, то метод их проигнорирует и не добавит после них разделитель. Из-за этого количество элементов в контейнере и в результирующей строке будет разным. Может быть в этом и была какая-то логика, если бы это работало со всеми пустыми элементами. Но вот "пустые" значения идущие после первого "не пустого" элемента контейнера уже будут обрамлены разделителем. Я считаю что это явно ошибка и в строке должны быть представлены все элементы контейнера и пустые и не пустые.

Причина ошибки и собственно исправление:
X++:
static str 1000 con2Str(container c, str 10 sep = ',')
{
    int         idx = 0;
    int         len = conlen(c);
    str  100    tmp;
    str 1000    retStr;
;
    while (idx < len)
    {
        idx += 1;
// KSM fix empty string -->>
//        if (retStr)
        if (idx > 1)
// KSM fix empty string <<--
            retStr += sep;

        tmp = conpeek(c,idx);
        retStr += tmp;
    }
    return retStr;
}

Здесь интересен ещё один момент. Как значения типа anytype преобразуется в строку? По каким правилам происходит такое преобразование?
Например дата:
X++:
static void TestAnytype2StrConvert(Args _args)
{
    date t = today();
    anyType a = t;
    str 100 s = a;
    ;
    
    info(s);
}
За это сообщение автора поблагодарили: Logger (1).
Старый 27.04.2023, 20:36   #469  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
639 / 300 (12) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Здесь интересен ещё один момент. Как значения типа anytype преобразуется в строку? По каким правилам происходит такое преобразование?
Например дата:
X++:
static void TestAnytype2StrConvert(Args _args)
{
    date t = today();
    anyType a = t;
    str 100 s = a;
    ;
    
    info(s);
}
В AnyType также присутствует дополнительная информация о базовом типе. В зависимости от этого типа используется уже конкретное преобразование. В strFmt() также используется anytype в качестве аргументов (кроме первого, который должен быть строкой). strFmt корректно преобразует любой переданный аргумент в строку, будь то число, енум или дата.
__________________
// no comments
Старый 27.04.2023, 20:40   #470  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
639 / 300 (12) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
P.S. Я думаю, во всех таких случаях используется функция any2str().
__________________
// no comments
Старый 28.04.2023, 07:55   #471  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,816 / 3011 (108) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от dech Посмотреть сообщение
P.S. Я думаю, во всех таких случаях используется функция any2str().
Там все немного заморочнее

X++:
static void Job287(Args _args)
{
    str     sDate;
    anytype aDate = 11\12\2023;
    str     sReal;
    anytype aReal = 1024.5678;
    ;
    
    sDate = aDate;
    sReal = aReal;
    
    info(strFmt("sAdate = %1", sDate));
    info(strFmt("aDate  = %1", aDate));
    info(strFmt("sReal  = %1", sReal));
    info(strFmt("aReal  = %1", aReal));
    
    // info(strFmt("any2str(aDate)  = %1", any2str(aDate))); // ошибка
    // info(strFmt("any2str(aReal)  = %1", any2str(aReal))); // ошибка
}
выводит :
Цитата:
sAdate = 2023.12.11
aDate = 11.12.2023
sReal = 1024.5678
aReal = 1 024,57
В общем присваивание anytype к строке делает преобразование без учета региональных настроек юзера.

А any2str - никакого реального преобразования не делает. Эта функция - что-то типа Debug::assert() - только она проверяет что реально передана переменная строкового типа иначе выбрасывает исключение. Ну и конечно подсказывает компилятору какой имелся в виду тип, подавляя тем самым предупреждения компилятора. Поэтому для реального преобразования в строку мы писали свою функцию. strFmt не всегда подходит из-за строгого округления до 2 знаков после запятой для вещественных чисел.

Последний раз редактировалось Logger; 28.04.2023 в 07:58.
За это сообщение автора поблагодарили: S.Kuskov (5).
Старый 28.04.2023, 17:25   #472  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,155 / 1286 (47) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от Logger Посмотреть сообщение
Поэтому для реального преобразования в строку мы писали свою функцию. strFmt не всегда подходит из-за строгого округления до 2 знаков после запятой для вещественных чисел.
Это вы еще "по детски"
У меня целая иерархия классов-атрибутов. По классу почти для каждого базового типа. В нужном месте [классатрибутСпараметрами] и его взрослая обработка.
За это сообщение автора поблагодарили: Logger (1).
Старый 19.05.2023, 11:22   #473  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,682 / 5778 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Разбирался тут с "тяжелыми" запросами и в том числе обнаружил там такое:
PHP код:
UPDATE T1 SET ACCOUNTINGEVENT=5665953399,RECVERSION=4567933
FROM ACCOUNTINGDISTRIBUTION T1 WITH 
(INDEX(I_7452SOURCEDOCUMENTHEADERIDX))
CROSS JOIN SOURCEDOCUMENTLINE T2
WHERE 
(((T1.PARTITION=5637144576) AND (T1.ACCOUNTINGEVENT=0)
AND (
T1.ACCOUNTINGDATE={ d'2023-05-19'}))
AND (
T1.SOURCEDOCUMENTHEADER=5669290320))
AND ((
T2.RECID=T1.SOURCEDOCUMENTLINE)
AND (
T2.ACCOUNTINGSTATUS=OR T2.ACCOUNTINGSTATUS=6))
AND (
T2.PARTITION=5637144576
Казалось бы, что с ним не так? А то, что он не использует параметры и плодит, собака, сотни одинаковых планов запроса, которые вымывают из кэша другие более полезные планы запросов. С помощью "триангуляции" обнаружил, что такие запросы генерятся (в DAX2012 R3) из AccountingEventSourceDocumentProcessor::updateDistributionsForEvent(). Спрашивается, что мешало смастерить там прямой SQL-запрос с параметрами, чтобы он не плодил кучу одинаковых планов запросов?..
Старый 19.05.2023, 12:53   #474  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,879 / 5617 (193) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Цитата:
Сообщение от gl00mie Посмотреть сообщение
Казалось бы, что с ним не так? А то, что он не использует параметры и плодит, собака, сотни одинаковых планов запроса, которые вымывают из кэша другие более полезные планы запросов. С помощью "триангуляции" обнаружил, что такие запросы генерятся (в DAX2012 R3) из AccountingEventSourceDocumentProcessor::updateDistributionsForEvent(). Спрашивается, что мешало смастерить там прямой SQL-запрос с параметрами, чтобы он не плодил кучу одинаковых планов запросов?..
Нет под рукой DAX2012, поэтому хочу спросить - там что - реально forceliterals стоял в коде ? (Просто я наверное и не вспомню на вскидку, где в стандарте forceliterals прописан был в DAX2012...)
Старый 19.05.2023, 13:58   #475  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,636 / 1144 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от fed Посмотреть сообщение
Нет под рукой DAX2012, поэтому хочу спросить - там что - реально forceliterals стоял в коде ? (Просто я наверное и не вспомню на вскидку, где в стандарте forceliterals прописан был в DAX2012...)
Там напрямую строка запроса формируется и выполняется "как есть"

X++:
AccountingEventSourceDocumentProcessor::executeSQL(sqlStatementText);
Т.е. приведенный UPDATE - это значение переменной sqlStatementText, которая там сформирована.

Еще и комментарий написан

X++:
    // Do the update as direct SQL as there is a deadlock on AccountingDistribution due to a clustered
    // index scan operator in the query plan. This operator appears only in low data volume scenarios.
    // In higher volume scenarios, the plan includes a seek operator using the index I_7452SOURCEDOCUMENTHEADERIDX.
    // Testing in SSMS indicates an index hint will correct the plan at low volumes and represents minimal
    // risk at high volumes. In order to enable the index hint on the update_recordset, direct SQL must be used.
    // Also note that xGlobal::randomPositiveInt32() is the method used by the kernel to populate the
    // recversion field.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 19.05.2023, 14:02   #476  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,636 / 1144 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от gl00mie Посмотреть сообщение
Спрашивается, что мешало смастерить там прямой SQL-запрос с параметрами, чтобы он не плодил кучу одинаковых планов запросов?..
Могу ошибаться, но, по-моему, это от версии MS SQL зависит. Будет ли в случае добавления DECLARE использован ранее созданный план запроса или в любом случае будет создан новый.

Т.е. на момент написания кода вполне могло быть, что добавление DECLARE все-равно приводило к созданию нового плана запроса
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 19.05.2023, 20:25   #477  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,816 / 3011 (108) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от fed Посмотреть сообщение
Нет под рукой DAX2012, поэтому хочу спросить - там что - реально forceliterals стоял в коде ? (Просто я наверное и не вспомню на вскидку, где в стандарте forceliterals прописан был в DAX2012...)
Не, там прямой запрос к БД.

X++:
private static server boolean updateDistributionsForEvent(recId _accountingEventRecId, AccountingDate _accountingDate, recId _sourceDocumentRecId)
{
    str                             sqlStatementText;
    str                             sqlDate = date2str(_accountingDate, 321, 2, 3, 2, 3, 4, DateFlags::None); // 'YYYY-MM-DD'

    // Do the update as direct SQL as there is a deadlock on AccountingDistribution due to a clustered
    // index scan operator in the query plan. This operator appears only in low data volume scenarios.
    // In higher volume scenarios, the plan includes a seek operator using the index I_7452SOURCEDOCUMENTHEADERIDX.
    // Testing in SSMS indicates an index hint will correct the plan at low volumes and represents minimal
    // risk at high volumes. In order to enable the index hint on the update_recordset, direct SQL must be used.
    // Also note that xGlobal::randomPositiveInt32() is the method used by the kernel to populate the
    // recversion field.

    sqlStatementText = strFmt('UPDATE T1 SET ACCOUNTINGEVENT=%1,RECVERSION=%2 FROM ACCOUNTINGDISTRIBUTION T1 WITH (INDEX(I_7452SOURCEDOCUMENTHEADERIDX)) CROSS JOIN SOURCEDOCUMENTLINE T2 ', _accountingEventRecId, xGlobal::randomPositiveInt32());

    sqlStatementText += strFmt('WHERE (((T1.PARTITION=%1) AND (T1.ACCOUNTINGEVENT=0) AND (T1.ACCOUNTINGDATE={ d\'%2\'})) AND (T1.SOURCEDOCUMENTHEADER=%3)) AND ', getcurrentpartitionrecid(), sqlDate, _sourceDocumentRecId);
    sqlStatementText += strFmt('((T2.RECID=T1.SOURCEDOCUMENTLINE) AND (T2.ACCOUNTINGSTATUS=%1 OR T2.ACCOUNTINGSTATUS=%2)) AND (T2.PARTITION=%3)', enum2int(SourceDocumentLineAccountingStatus::Completed), enum2int(SourceDocumentLineAccountingStatus::Canceled), getcurrentpartitionrecid());

    return AccountingEventSourceDocumentProcessor::executeSQL(sqlStatementText);
}
Старый 19.05.2023, 22:02   #478  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,682 / 5778 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Т.е. на момент написания кода вполне могло быть, что добавление DECLARE все-равно приводило к созданию нового плана запроса
В моем случае - не приводит
Старый 12.09.2023, 14:32   #479  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,816 / 3011 (108) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от Logger Посмотреть сообщение
Это да.
Но если их инкрементно выделять, то пропадают все вкусности GUID и он становится ничем не лучше обычного RecId. Даже хуже, так как RecId всего 8 байт занимает.
Оказывается подготовлен стандарт UUIDv7, свободный от перечисленных мной недостатков.

https://habr.com/ru/articles/658855/

Комменты, как обычно, еще интереснее.
За это сообщение автора поблагодарили: S.Kuskov (2).
Старый 03.11.2023, 13:07   #480  
Pandasama is offline
Pandasama
Участник
 
446 / 133 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Не сдержусь и в который раз пошлю лучи всего плохого авторам метода CompanyInfo::find()
X++:
public static CompanyInfo find(boolean _forupdate = false, RecId _recId = 0, boolean _initializePartyNumberSeq = false, boolean useGuid = false)
Который зачем-то первым аргументом принимает boolean _forUpdate, а значит, совершенно не ругается при попытке вызова его, например, так
X++:
int64 refRecId;
CompanyInfo::find(refRecId);
Теги
axapta, cil, d365fo, guid, rasset, uuid, uuidv7, баг

 

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 19:29.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.