Показать сообщение отдельно
Старый 29.02.2016, 17:12   #5  
Pokersky09 is offline
Pokersky09
Участник
 
43 / 60 (3) ++++
Регистрация: 15.11.2012
Адрес: Turkey
Вопрос вновь открыт
Выявил источник проблемы:

В DimensionStorage:SavePrivate()
X++:
 new userConnection()
Притом данный коннект создается только в случае необходимости создания новой строки DimensionAttributeValueCombination , при повторной необходимости использования аналитик берется уже ранее созданная, поэтому ошибочно тему закрыли.

При создании открывается новое соединение UserConnection, и почему то соединение не снимается, а остается в пуле на некоторое время (более 10минут), настройки аосов выполнили согласно описанию выше постом.

При выполнении данного кода, часто вылетают ошибки ключа (один и тот же договор используется в двух разных журналах, одновременно выполняемых на разных потоках).

Пробовал добавлять в конце метода UserConnection.Finalize(), однако результатов не принесло, соединения копятся гораздо быстрее, чем снимаются. Подсмотрено в методах NumberSeq, там аналогично используются userConnection, и проблем не возникает.

X++:
/// <summary>
///    Saves the current information and retrieves the record ID of the persisted combination.
/// </summary>
/// <returns>
///    The record ID of the combination.
/// </returns>
private recId savePrivate()
{
    #OCCRetryCount
    #LedgerSHA1Hash
    DimensionSHA1Hash hash;

    DimensionAttributeLevelValue                dimAttrLevelValue;
    DimensionAttributeValueGroup                dimAttrValueGroup;
    DimensionAttributeValueGroupCombination     dimAttrValueGroupCombo;
    DimensionAttributeValueCombination          dimAttrValueCombo;
    DimensionHierarchy                          accountStructure;
    DimensionHierarchyLevel                     mainAccountSegment;
    DimensionAttributeValue                     mainAccountDimAttrValue;
    int                                         hierarchyIndex;
    int                                         segmentIndex;
    int                                         previousSegmentIndex;
    int                                         i;
    int                                         hierarchyCount;
    int                                         segmentCountForHierarchy;
    DimensionStorageSegment                     segment;
    XDSServices                                 xdsServices;
    UserConnection                              userConnection;
    LedgerDimensionBase                         savedComboId;

    if (Debug::debugMode())
    {
        Debug::assert(this.hierarchyCount() > 0);
        Debug::assert(segments != null);
        Debug::assert(totalSegmentCount > 0);
        DimensionStorage::validateCombinationIntegrity(this);
    }

    // Calculate the overall super-combo hash
    hash = this.getComboHash();

    if (hash == connull())
    {
        Debug::printDebug(strfmt('Warning: LedgerDimension of %1 is not created as no segments with DimensionAttributeValues exist (Is the backing entity instance missing?).', dimAttrValueCombo.DisplayValue));

        // Don't save combinations without level values
        initialComboId = 0;
        initialHash = connull();
        return 0;
    }
    else if (hash == initialHash)
    {
        // Nothing to do if nothing's changed
        Debug::assert(DimensionAttributeValueCombination::exist(initialComboId));
        return initialComboId;
    }

    // Turn off XDS to ensure the reference can be found.
    xdsServices = new XDSServices();
    xdsServices.setXDSState(0);

    savedComboId = DimensionStorage::getSavedComboRecIdByHash(hash);

    if (savedComboId)
    {
        initialComboId = savedComboId;
        initialHash = hash;

        return savedComboId;
    }

    // Create the main combination and group link in a separate transaction for smaller transaction scope to prevent blocking
    userConnection = new userConnection();
    userConnection.ttsBegin();
    dimAttrValueCombo.setConnection(userConnection);
    dimAttrValueGroupCombo.setConnection(userConnection);

    try
    {
        // A matching was not found, so now insert a new combination. This will link to any existing sub-groups found or new sub-groups are inserted and linked
        dimAttrValueCombo.DisplayValue = this.getComboDisplayValue();
        dimAttrValueCombo.LedgerDimensionType = ledgerDimensionType;
        dimAttrValueCombo.Hash = hash;

        // Look up the account structure and main account if applicable
        accountStructure = DimensionHierarchy::find(this.getHierarchyId(1));
        //Debug::assert(accountStructure.RecId);  // TODO: Enable once the unit test setup data correctly

        if (accountStructure && (accountStructure.StructureType == DimensionHierarchyType::AccountStructure))
        {
            // Denormalize the account structure and main account
            dimAttrValueCombo.AccountStructure = accountStructure.RecId;

            // Look up the main account segment, which uses the hierarchy/dimension attribute
            // index so this will be a cached lookup
            mainAccountSegment = DimensionHierarchyLevel::findByDimensionHierarchyAndDimAttribute(
                accountStructure.RecId,
                DimensionAttribute::getMainAccountDimensionAttribute());

            // If the hierarchy is an account structure, then the dimension hierarchy level
            // will be indexed the same in the storage segment collection as in the account
            // structure
            if (mainAccountSegment && this.segmentCount() >= mainAccountSegment.Level)
            {
                // Look up the main account recid from the sepecified DAV. This will
                // normally be a cached lookup since it was recently used to create the
                // DAV that was passed to the storage object.
                mainAccountDimAttrValue = DimensionAttributeValue::find(this.getSegment(mainAccountSegment.Level).parmDimensionAttributeValueId());
                dimAttrValueCombo.MainAccount = mainAccountDimAttrValue.EntityInstance;
            }
        }
        else if (accountStructure && (accountStructure.StructureType == DimensionHierarchyType::DefaultAccount))
        {
            // Denormalize the main account
            Debug::assert(this.segmentCount() == 1);

            // Look up the main account recid from the sepecified DAV. This will
            // normally be a cached lookup since it was recently used to create the
            // DAV that was passed to the storage object.
            mainAccountDimAttrValue = DimensionAttributeValue::find(this.getSegment(1).parmDimensionAttributeValueId());
            dimAttrValueCombo.MainAccount = mainAccountDimAttrValue.EntityInstance;
        }

        // Create the header value
        dimAttrValueCombo.insert();

        savedComboId = dimAttrValueCombo.RecId;
        initialComboId = savedComboId;
        initialHash = hash;
        hierarchyCount = this.hierarchyCount();

        for (hierarchyIndex = 1; hierarchyIndex <= hierarchyCount; hierarchyIndex++)
        {
            segmentCountForHierarchy = this.segmentCountForHierarchy(hierarchyIndex);
            hash = this.getGroupHash(hierarchyIndex);
            previousSegmentIndex = segmentIndex;

            try
            {
                // Try to find an existing value group that matches what we need for the specified group - use the default connection (as it would have been saved by another process's connection anyway)
                select firstOnly RecId from dimAttrValueGroup where dimAttrValueGroup.Hash == hash;
                if (dimAttrValueGroup.RecId)
                {
                    segmentIndex += segmentCountForHierarchy;
                }
                else
                {
                    // Create the group and levels in the same separate transaction
                    dimAttrValueGroup.setConnection(userConnection);
                    dimAttrLevelValue.setConnection(userConnection);

                    dimAttrValueGroup.DimensionHierarchy = this.getHierarchyId(hierarchyIndex);
                    dimAttrValueGroup.Hash = hash;
                    dimAttrValueGroup.Levels = segmentCountForHierarchy;
                    dimAttrValueGroup.insert();

                    for (i = 0; i < segmentCountForHierarchy; i++)
                    {
                        segmentIndex++;
                        segment = this.getSegment(segmentIndex);
                        if (!segment.isEmpty())
                        {
                            dimAttrLevelValue.DimensionAttributeValueGroup = dimAttrValueGroup.RecId;
                            dimAttrLevelValue.DimensionAttributeValue = segment.parmDimensionAttributeValueId();
                            dimAttrLevelValue.DisplayValue = segment.parmDisplayValue();
                            dimAttrLevelValue.Ordinal = i + 1;
                            dimAttrLevelValue.insert();
                        }
                    }
                }

                dimAttrValueGroupCombo.DimensionAttributeValueGroup = dimAttrValueGroup.RecId;
                dimAttrValueGroupCombo.DimensionAttributeValueCombination = savedComboId;
                dimAttrValueGroupCombo.Ordinal = hierarchyIndex;
                dimAttrValueGroupCombo.insert();
            }
            catch (Exception::DuplicateKeyException)    // Finding or creating the DAVG
            {
                if (xSession::currentRetryCount() < #RetryNum)
                {
                    segmentIndex = previousSegmentIndex;   // Revert to previous position, since insert failed
                    retry;
                }

                Debug::assert(dimAttrValueGroupCombo.RecId != 0);

                // Failed to insert a new group -- restart the transaction and try to find the full combination again (by outer catch)
                userConnection.ttsAbort();
                userConnection.ttsBegin();
                throw Exception::DuplicateKeyException;
            }
        }

        // Successfully inserted a completely new combination
        userConnection.ttsCommit();
    }
    catch (Exception::DuplicateKeyException)    // Finding or creating the DAVC
    {
        // Attempt to re-read the DAVC as another one was apparently inserted - use the default connection (as it would have been saved by another process's connection anyway)
        savedComboId = DimensionStorage::getSavedComboRecIdByHash(hash);

        if (savedComboId)
        {
            initialComboId = savedComboId;
            initialHash = hash;
        }
        else if (xSession::currentRetryCount() < #RetryNum)
        {
            // The retry will be a rare case where we didn't find it, tried to insert, got dup, tried to reread and didn't find it again so will attempt to re-insert
            retry;
        }
        else
        {
            // Record level security may have prevented the record from being found even with XDS off.
            Debug::assert(savedComboId != 0);
        }

        // Failed to insert a new combination
        userConnection.ttsAbort();
    }

    userConnection().finalize();//Добавлено для проверки

    return savedComboId;
}


Напомню, текущая задача является импорт строк LedgerJournalTrans в количестве более 50млн, кол-во строк в CustTable составляет порядка 2х Млн. Соответственно при импорте каждой строки вызывается метод
X++:
DimensionStorage::getDynamicAccount(custAccount , LedgerJournalACType::Cust);

Временным решением нашли предварительное создание аналитик, а уже после загрузку данных:

X++:
static server void DimAttributeValueCombCREATE_AXFORUM(Args _args)
{
    #define.maxRowCount(100000)
    
    int64           tick1 = WinAPI::getTickCount64();
    int             countCurrent;
    int             countCreate;
    int             countMax    = #maxRowCount;
    int             countCatch;
    CustAccount     custAccount;
    CustTable                           custTable;
    DimensionAttributeValueCombination  dimComb;

    return;//Снять в случае необходимости исполнения кода

    while select AccountNum from  custTable
    order by custTable.AccountNum asc
    notexists join RecId from dimComb
        where custTable.AccountNum == dimComb.DisplayValue
    {
        countCurrent++;
        if(countCurrent >= countMax)
            break;

        custAccount = custTable.AccountNum;

        if(custAccount)
        {
            try
            {
                DimensionStorage::getDynamicAccount(custAccount , LedgerJournalACType::Cust);
                countCreate++;
            }
            catch
            {
                    countCatch++;
            }
        }
    }

    info(strFmt('countCurrent: (%1)',   countCurrent));
    info(strFmt('countCreate: (%1)',    countCreate));
    info(strFmt('countCatch: (%1)',     countCatch));

    info(strFmt("%1", time2str(ms2TimeOfDay(WinAPI::getTickCount64() - tick1),1,1)));
}
За это сообщение автора поблагодарили: trud (2), Logger (5), Kabardian (2).