X++ code to correct the product receipt in Microsoft Dynamics AX 2012 R3

X++ code to correct the product receipt in Microsoft Dynamics AX 2012 R3



private void cancelProductReceipt(Filename    _fileName)
{
    #File
    IO                              iO;
    Container                       con;
    boolean                         first = true;
    PurchFormLetter                 purchFormLetter;
    PurchFormletterParmData         purchFormLetterParmData;
    PurchParmUpdate                 purchParmUpdate;
    PurchParmTable                  purchParmTable;
    PurchParmLine                   purchParmLine;
    PurchTable                      purchTable;
    PurchLine                       purchLine;
    PurchId                         purchId;
    Num                             packingSlipId;
    VendPackingSlipJour             vendPackingSlipJour;
    VendPackingSlipTrans            vendPackingSlipTrans;
    ItemId                          itemId;
    Qty                             qty;
    FileIoPermission                perm;
    Line                            lineNumber;

    ;

    perm = new FileIoPermission(_fileName, #IO_Read);
    perm.assert();

    iO = new CommaTextIo(_fileName,#IO_Read);

    if (! iO || iO.status() != IO_Status::Ok)
    {
        throw error("@SYS19358");
    }

    while (iO.status() == IO_Status::Ok)
    {
        con = iO.read();//  read file
        if (con)
        {
            if (first)  //skip header
            {
                first = false;
            }
            else
            {

                purchId       = conPeek(con, 1);
                packingSlipId = conPeek(con, 2);
                itemId        = conPeek(con, 3);
                qty           = conPeek(con, 4);
                lineNumber    = conPeek(con, 5);

                purchTable = PurchTable::find(purchId);

                select firstOnly vendPackingSlipJour
                    where vendPackingSlipJour.PurchId == purchId
                        && vendPackingSlipJour.PackingSlipId == packingSlipId;

                ttsBegin;

                // Instantiate PurchFormLetterParmData
                purchFormLetterParmData = PurchFormletterParmData::newData(
                    DocumentStatus::PackingSlip,
                    VersioningUpdateType::Correction);

                purchFormLetterParmData.parmOnlyCreateParmUpdate(true);
                purchFormLetterParmData.createData(false);
                purchParmUpdate = purchFormLetterParmData.parmParmUpdate();

                // Set PurchParmTable table
                purchParmTable.clear();
              //  purchParmTable.TransDate             = SystemDateGet();
                purchParmTable.Ordering              = DocumentStatus::PackingSlip;
                purchParmTable.ParmJobStatus         = ParmJobStatus::Waiting;
                purchParmTable.ParmId                = purchParmUpdate.ParmId;
                purchParmTable.Num                   = packingSlipId;
                purchParmTable.ReCalculate           = true;
                purchParmTable.PurchId               = purchTable.PurchId;
                purchParmTable.PurchName             = purchTable.PurchName;
                purchParmTable.DeliveryName          = purchTable.DeliveryName;
                purchParmTable.OrderAccount          = purchTable.OrderAccount;
                purchParmTable.InvoiceAccount        = purchTable.InvoiceAccount;
                purchParmTable.CurrencyCode          = purchTable.CurrencyCode;
                purchParmTable.DeliveryPostalAddress = purchTable.DeliveryPostalAddress;
                purchParmTable.VendPackingSlipJour   = vendPackingSlipJour.RecId;
                purchParmTable.insert();

                // Set PurchParmLine table
                select purchLine
                    where purchLine.PurchId == purchTable.purchId
                    &&    purchLine.ItemId  == itemId
                    &&    PurchLine.LineNumber == 1;

                if (purchLine.PurchId)
                {
                    select firstOnly OrigPurchid,PurchaseLineLineNumber,Qty,InventQty from vendPackingSlipTrans
                        where vendPackingSlipTrans.OrigPurchid == purchLine.PurchId
                            && vendPackingSlipTrans.PurchaseLineLineNumber == purchLine.LineNumber;

                    purchParmLine.ParmId = purchParmTable.ParmId;
                    purchParmLine.TableRefId = purchParmTable.TableRefId;
                    purchParmLine.InitFromPurchLine(purchLine);
                    purchParmLine.ReceiveNow = -qty;
                    purchParmLine.modifiedReceiveNow();
                    purchParmLine.PreviousReceiveNow = vendPackingSlipTrans.Qty;
                    purchParmLine.PreviousInventNow = vendPackingSlipTrans.InventQty;
                    purchParmLine.setQty(DocumentStatus::PackingSlip, false);
                    purchParmLine.setLineAmount();
                    purchParmLine.insert();
                }


                purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
                purchFormLetter.parmVersioningUpdateType(VersioningUpdateType::Correction);
                purchFormLetter.purchParmUpdate(purchFormLetterParmData.parmParmUpdate());
                purchFormLetter.parmCallerTable(vendPackingSlipJour);
                purchFormLetter.parmParmTableNum(purchParmTable.ParmId);
                purchFormLetter.parmId(purchParmTable.ParmId);
                purchFormLetter.specQty(PurchUpdate::ReceiveNow);
               // purchFormLetter.transDate(systemDateGet());
                purchFormLetter.proforma(false);
                purchFormLetter.run();

                ttsCommit;

            }
        }

    }


}

X++ code to create CustVendExternalItem from csv import in Microsoft Dynmics AX 2012 R3

X++ code to create CustVendExternalItem from csv import in Microsoft Dynmics AX 2012 R3


 static void  RB_ExternalItemImport(Args _args)
{
    #File
    IO                                          iO;
    FilenameOpen                       filename = "c:\\ExternalItem.csv";//file name here
    CustVendExternalItem          CustVendExternalItem;
    InventTable                           inventTable;
    VendTable                             vendTable;
    VendAccount                         supplierId;
    ItemId                                    itemId;
    ExternalItemId                      ExternalItemId;
    Container                              con;
    boolean                                 first = true;
    FileIoPermission                  perm;
    int                                          created,error;
    InventDim                            inventDim = InventDim::find('AllBlank');


    iO = new CommaTextIo(filename,#IO_Read);

    if (! iO || iO.status() != IO_Status::Ok)
    {
        throw error("@SYS19358");
    }


    while (iO.status() == IO_Status::Ok)
    {
        con = iO.read();//  read file
        if (con)
        {
            if (first)  //skip header
            {
                first = false;
            }
            else
            {
                supplierId          =   conPeek(con,1);
                ItemId                =   conPeek(con,2);
                ExternalItemId  =   conPeek(con,3);

                inventTable = inventTable::find(ItemId);
                VendTable   = VendTable::find(supplierId);

                if (inventTable &&  VendTable)
                {
                    CustVendExternalItem.clear();
                    CustVendExternalItem.initValue();
                    CustVendExternalItem.ABCCategory = ABC::None;
                    CustVendExternalItem.CustVendRelation = supplierId;
                    CustVendExternalItem.ExternalItemId = ExternalItemId;
                    CustVendExternalItem.ItemId       = inventTable.ItemId;
                    CustVendExternalItem.InventDimId  = inventDim.inventdimid;
                    CustVendExternalItem.ModuleType = ModuleInventPurchSalesVendCustGroup::Vend;
                    CustVendExternalItem.insert();
                    created++;
                }
                else
                {
                    error++;
                    info(strFmt("%1,%2 not created",  ItemId, supplierId));
                }
            }
        }
    }

    info("Mission Accomplished");
}

X++ code to move the file in batch process - Microsoft Dynamics AX2012 R3

X++ code to move the file in batch process - Microsoft Dynamics AX2012 R3


public server static void moveFile(FileName  fileName,FileName  destinationPath)
{

    FileName            newFileName;
    Filename            fPath;
    Filename            fName;
    Filename            fType;
    System.Exception    exception;

 
    #File

    try
    {

        [fPath, fName, fType] = fileNameSplit(fileName);

        newFileName = strFmt("%1%2%3", destinationPath, fName, fType);

 
        if (!System.IO.File::Exists(newFileName))
        {
            System.IO.File::Move(fileName, newFileName);
        }
        else
        {
            System.IO.File::Delete(fileName);
        }

    }
    catch (Exception::CLRError)
    {

        exception = ClrInterop::getLastException();
        if (exception != null)
        {
            exception = exception.get_InnerException();
            if (exception != null)
            {
                error(exception.ToString());
            }
        }
    }
    catch (Exception::Error)
    {
        info(strFmt("Errored",exception.ToString()));
        retry;
    }

}

X++ Code To Generate Ledger Dimension Based On The Company Accounting Structure.

X++ Code To Generate Ledger Dimension Based On The Company Accounting Structure.



public static RefRecId  generateLedgerDimension(MainAccountNum  _mainAccountId,
DimensionValue _costCentre,DimensionValue _division,DimensionValue _location,
DimensionValue _supplier, DimensionValue _products,DimensionValue _customer,
DimensionValue _interCompany)
{
    container                                                conData;
    int                                                           hierarchyCount;
    int                                                           hierarchyIdx;
    LedgerRecId                                          ledgerRecId;
    MainAccount                                         mainAccount;
    RefRecId                                                recordvalue;
    DimensionAttribute                               dimensionAttribute;
    DimensionAttributeValue                      dimensionAttributeValue;
    DimensionSetSegmentName                  DimensionSet;
    DimensionStorage                                  dimStorage;
    DimensionAttributeValueContract         ValueContract;
    LedgerAccountContract                          LedgerAccountContract;
    DimensionAttributeValueCombination  dimensionAttributeValueCombination;
    List                                                          valueContracts;

    #define.MainAccount('MainAccount')
    #define.Division('Division')
    #define.CostCentre('CostCentre')
    #define.Location('Location')
    #define.Supplier('Supplier')
    #define.Products('Products')
    #define.Intercompany('Intercompany')
    #define.Customer('Customer')
    #define.Language('en-gb')


    LedgerAccountContract   = new LedgerAccountContract();
    valueContracts          = new List(Types::Class);

    conData =[_mainAccountId];


    mainAccount     =   MainAccount::findByMainAccountId(_mainAccountId);
    recordvalue     =       DimensionHierarchy::getAccountStructure(mainAccount.RecId,Ledger::current());
    hierarchyCount  =   DimensionHierarchy::getLevelCount(recordvalue);
    DimensionSet    =   DimensionHierarchyLevel::getDimensionHierarchyLevelNames(recordvalue);

    if (recordvalue)
    {
        for(hierarchyIdx = 1;hierarchyIdx<=hierarchyCount;hierarchyIdx++)
        {

            if(hierarchyIdx == 1)
            continue;

            dimensionAttribute = DimensionAttribute::findByLocalizedName(DimensionSet[hierarchyIdx],false,#Language);

            if (dimensionAttribute.Name == #Division)
            {
                conData += [_division];
            }
            if (dimensionAttribute.Name == #CostCentre)
            {
                conData += [_costCentre];
            }
            if (dimensionAttribute.Name == #Supplier)
            {
                conData += [_supplier];
            }
            if (dimensionAttribute.Name == #Location)
            {
                conData += [_location];
            }
            if (dimensionAttribute.Name == #Products)
            {
                conData += [_products];
            }
            if (dimensionAttribute.Name == #Intercompany)
            {
                conData += [_interCompany];
            }
            if (dimensionAttribute.Name == #Customer)
            {
                conData += [_customer];
            }

            if(dimensionAttribute)
            {
                dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,conPeek(conData,hierarchyIdx));

                if(dimensionAttributeValue)
                {

                    ValueContract = new DimensionAttributeValueContract();
                    ValueContract.parmName(dimensionAttribute.Name) ;
                    ValueContract.parmValue(dimensionAttributeValue.CachedDisplayValue);
                    valueContracts.addEnd(ValueContract);
                }
            }

        }

        LedgerAccountContract.parmMainAccount(_mainAccountId);
        LedgerAccountContract.parmValues(valueContracts);

        dimStorage = DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
        dimensionAttributeValueCombination = DimensionAttributeValueCombination::find(dimStorage.save());
        ledgerRecId = dimensionAttributeValueCombination.RecId;
    }
    else
    {
        warning (strfmt("Ledger dimension Issue for main account %1", _mainAccountId));
    }

    return  ledgerRecId;

}

How to use Dynamics Perf 2.0 to monitor and improve the AX 2012 Performance



Please find the List of Queries to monitor and improve the performance of AX from Dyanmics Perf 2.0.

Once you complete  the installation of Dynamics Perf  2.0  from the below link.


It will start collecting the data and store it in the DynamicsPerf database.  

To identify the below list , please query the DynamicsPerf Database name and not AX database as shown below.


  • Ø  INDEXES_BY_SIZE
  • Ø  INDEX_ACTIVITY
  • Ø  INDEX_STATISTICS
  • Ø  TOO_LARGE_INDEXES
  • Ø  HIGH_COST_INDEXES
  • Ø  COMPRESSED_INDEXES
  • Ø  UNIQUE_INDEXES_NOT_DEFINED_UNIQUE
  • Ø  EXACT_DUPLICATE_INDEXES
  • Ø  SUBSET_DUPLICATE_INDEXES
  • Ø  INCLUDED_COLUMN_INDEXES
  • Ø  UNUSED_INDEXES
  • Ø  TABLES_WITHOUT_CLUSTERED_INDEX
  • Ø  ADJUST_CLUSTERED_INDEXES
  • Ø  ANALYZE_INDEX_KEY_ORDER
  • Ø  INDEXES_BEING_SCANNED
  • Ø  SEARCH_QUERY_PLANS_FOR_INDEX_USAGE





To Find The Index by size

USE DynamicsPerf
SELECT TOP 100 DATABASE_NAME,
TABLE_NAME,
SUM(CASE
WHEN ISV.INDEX_ID IN (0,1)  THEN PAGE_COUNT * 8 / 1024
END)   AS SIZEMB_DATA,
SUM(CASE
WHEN ISV.INDEX_ID > 1 THEN PAGE_COUNT * 8 / 1024
END)   AS SIZEMB_INDEXES,
COUNT(CASE
WHEN ISV.INDEX_ID > 1 THEN TABLE_NAME
END) AS NO_OF_INDEXES,
MAX(CASE
WHEN ( DATA_COMPRESSION > 0 )
AND ( ISV.INDEX_ID IN (0,1)  ) THEN 'Y'
ELSE 'N'
END)   AS DATA_COMPRESSED,
MAX(CASE
WHEN ( DATA_COMPRESSION > 0 )
AND ( ISV.INDEX_ID > 1) THEN 'Y'
ELSE 'N'
END)   AS INDEXES_COMPRESSED
FROM   INDEX_STATS_CURR_VW ISV
--WHERE DATABASE_NAME = 'Your AX Database Name'
--AND SERVER_NAME = 'Database Server Name'
GROUP  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME
ORDER  BY 3 DESC
___________________________________________________________________________________

Index Activity

SELECT DATABASE_NAME,
TABLE_NAME,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) ) END   AS ratioofreads,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_UPDATES) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) ) END       AS ratioofwrites,
SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS totalreadoperations,
SUM(USER_UPDATES)                           AS totalwriteoperations,
SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS)                         AS totaloperations
FROM   INDEX_STATS_CURR_VW /*sys.dm_db_index_usage_stats*/
--WHERE DATABASE_NAME = 'XXXXXXXXXXXX'
-- AND SERVER_NAME = 'XXXXXXXX'
GROUP  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME
--ORDER BY TotalOperations DESC
--ORDER BY TotalReadOperations DESC
ORDER  BY TotalWriteOperations DESC
_____________________________________________________________________________________


INDEX_STATISTICS

SELECT DATABASE_NAME,
SERVER_NAME,
TABLENAME,
INDEXNAME,
UPDATED
FROM   INDEX_STAT_HEADER ISH
WHERE  UPDATED IS NOT NULL
-- AND SERVER_NAME = 'XXXXXXXXX'
-- AND DATABASE_NAME = 'XXXXXXXX'
ORDER  BY UPDATED DESC
___________________________________________________________________________________________

TOO_LARGE_INDEXES 

;WITH TABLE_SIZE (SERVER_NAME, DATABASE_NAME, TABLE_NAME, SIZE)
AS (SELECT SERVER_NAME,DATABASE_NAME,
TABLE_NAME,
PAGE_COUNT * 8 / 1024 AS size
FROM   INDEX_STATS_CURR_VW
WHERE  INDEX_ID IN (0,1) )
SELECT DISTINCT ISV.DATABASE_NAME,
ISV.TABLE_NAME,
TS.SIZE,
ISV.INDEX_NAME,
( ( PAGE_COUNT * 8 / 1024 ) / TS.SIZE ) * 100 AS [%_of_table],
ISV.INDEX_DESCRIPTION,
ISV.INDEX_KEYS,
ISV.INCLUDED_COLUMNS
FROM   INDEX_STATS_CURR_VW ISV
INNER JOIN TABLE_SIZE TS
ON ISV.SERVER_NAME = TS.SERVER_NAME
AND ISV.DATABASE_NAME = TS.DATABASE_NAME
AND ISV.TABLE_NAME = TS.TABLE_NAME
AND TS.SIZE > 0
WHERE  ISV.INDEX_ID > 1
AND USER_UPDATES > 100 -- index must be getting update
AND PAGE_COUNT > 100 -- small parameter tables are ok
AND ( ( PAGE_COUNT * 8 / 1024 ) / TS.SIZE ) * 100 > 25 --25%
ORDER  BY TS.SIZE DESC

__________________________________________________________________________________________


 HIGH_COST_INDEXES

SELECT SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME,
PAGE_COUNT*8/1024 AS SIZE_MB,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) ) END  AS RatioOfReads,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_UPDATES) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) ) END       AS RatioOfWrites,
SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS TotalReadOperations,
SUM(USER_UPDATES)                           AS TotalWriteOperations,
SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS)                         AS TotalOperations
FROM   INDEX_STATS_CURR_VW /*sys.dm_db_index_usage_stats*/
WHERE   USER_UPDATES > (USER_SEEKS + USER_SCANS + USER_LOOKUPS)
AND INDEX_DESCRIPTION NOT LIKE '%UNIQUE%' and INDEX_DESCRIPTION NOT LIKE 'CLUSTERED%'
-- AND SERVER_NAME = ‘XXXXXXXXX’
-- AND DATABASE_NAME = ‘XXXXXXXX’
GROUP  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME,
PAGE_COUNT
--ORDER BY TotalOperations DESC
--ORDER BY TotalReadOperations DESC
ORDER  BY TotalWriteOperations DESC

_____________________________________________________________________________________________


COMPRESSED_INDEXES

SELECT *
FROM   INDEX_STATS_CURR_VW
WHERE  DATA_COMPRESSION > 0
ORDER  BY USER_UPDATES DESC

________________________________________________________________________________________


 UNIQUE_INDEXES_NOT_DEFINED_UNIQUE

;WITH RECORDS_CTE (SERVER_NAME, DATABASE_NAME, TABLENAME, INDEX_NAME, INDEX_KEYS, ROW_COUNT, READS)
AS
-- Define the CTE query.
(SELECT DISTINCT SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME,
INDEX_KEYS,
ROW_COUNT,
USER_SEEKS + USER_SCANS + USER_LOOKUPS AS reads
FROM   INDEX_STATS_CURR_VW)
SELECT DISTINCT dv.SERVER_NAME,
dv.DATABASE_NAME,
dv.TABLENAME,
rows.INDEX_NAME,
DS.TYPE_DESC AS index_desc,
rows.INDEX_KEYS,
rows.ROW_COUNT
FROM   INDEX_DENSITY_VECTOR dv
INNER JOIN RECORDS_CTE rows
ON dv.TABLENAME = rows.TABLENAME
AND dv.DATABASE_NAME = rows.DATABASE_NAME
AND dv.SERVER_NAME = rows.SERVER_NAME
INNER JOIN DYNSYSINDEXES DS
ON DS.DATABASE_NAME = dv.DATABASE_NAME
AND DS.RUN_NAME LIKE dv.SERVER_NAME + '%'
AND DS.NAME = rows.INDEX_NAME
WHERE  DS.IS_UNIQUE = 0
AND ROW_COUNT / ( 1 / DENSITY ) = 1.000000000000000000
AND rows.READS > 1000 -- relatively used tables
AND rows.ROW_COUNT > 10000 -- larger tables only
ORDER  BY ROW_COUNT DESC

__________________________________________________________________________________________

EXACT_DUPLICATE_INDEXES

SELECT SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_KEYS,
COUNT(*),
STUFF ((SELECT ', ' + 'INDEX_NAME = ' + ISV.INDEX_NAME
+ ' KEYS= ' + ISV.INDEX_KEYS
+ ' INCLUDED_COLUMNS= '
+ ISV.INCLUDED_COLUMNS
FROM   INDEX_STATS_CURR_VW ISV
WHERE  ISV.DATABASE_NAME = A.DATABASE_NAME
AND ISV.SERVER_NAME = A.SERVER_NAME
AND ISV.TABLE_NAME = A.TABLE_NAME
AND ISV.INDEX_KEYS = A.INDEX_KEYS
FOR xml path('')), 1, 1, '''') AS indexes
FROM   INDEX_STATS_CURR_VW A
WHERE  INDEX_DESCRIPTION NOT LIKE '%primary key%'
GROUP  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_KEYS
HAVING COUNT(INDEX_KEYS) > 1
ORDER  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME

__________________________________________________________________________________________________


SUBSET_DUPLICATE_INDEXES

SELECT DISTINCT O.SERVER_NAME,
O.DATABASE_NAME,
O.TABLE_NAME,
O.INDEX_NAME            AS subset_index,
O.INDEX_KEYS            AS subset_index_keys,
O.INDEX_DESCRIPTION     AS subset_index_description,
O.PAGE_COUNT * 8 / 1024 AS subset_size_mb,
I.INDEX_NAME            AS superset_index,
I.INDEX_KEYS            AS superset_keys
FROM   INDEX_STATS_CURR_VW O
LEFT JOIN INDEX_STATS_CURR_VW I
ON I.SERVER_NAME = O.SERVER_NAME
AND I.DATABASE_NAME = O.DATABASE_NAME
AND I.TABLE_NAME = O.TABLE_NAME
AND I.INDEX_KEYS <> O.INDEX_KEYS
AND I.INDEX_KEYS LIKE O.INDEX_KEYS + ',%'
WHERE  O.INDEX_DESCRIPTION NOT LIKE '%UNIQUE%'
AND O.INDEX_DESCRIPTION NOT LIKE 'CLUSTERED%'
AND I.INDEX_NAME IS NOT NULL
AND O.PAGE_COUNT > 0
ORDER  BY O.SERVER_NAME,
O.DATABASE_NAME,
O.TABLE_NAME,
O.INDEX_KEYS

____________________________________________________________________________________________

INCLUDED_COLUMN_INDEXES

SELECT TOP 100 *
FROM   INDEX_STATS_CURR_VW
WHERE  INCLUDED_COLUMNS <> 'N/A'
AND PAGE_COUNT > 0
ORDER  BY len(INCLUDED_COLUMNS) DESC

_____________________________________________________________________________________________________


UNUSED_INDEXES

SELECT SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME,
MAX(PAGE_COUNT * 8 / 1024)         AS SIZE_MB,
SUM(USER_SEEKS_DELTA + USER_SCANS_DELTA
+ USER_LOOKUPS_DELTA)          AS READ_COUNT,
MIN(DATEDIFF(DD, DATE, GETDATE())) AS DAYS
FROM   INDEX_HISTORY
WHERE  FLAG = 'M'
AND INDEX_DESCRIPTION NOT LIKE '%UNIQUE%'
AND INDEX_DESCRIPTION NOT LIKE 'CLUSTERED%'
AND INDEX_DESCRIPTION NOT LIKE '%FILTERED%'
GROUP  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME
HAVING SUM(USER_SEEKS_DELTA + USER_SCANS_DELTA
+ USER_LOOKUPS_DELTA) = 0
AND MAX(PAGE_COUNT * 8 / 1024) > 0
ORDER  BY 5 DESC
--Indexes not used this month but used last month
SELECT TMH.*
FROM   INDEX_HISTORY TMH
INNER JOIN INDEX_HISTORY LMH
ON TMH.SERVER_NAME = LMH.SERVER_NAME
AND TMH.DATABASE_NAME = LMH.DATABASE_NAME
AND TMH.TABLE_NAME = LMH.TABLE_NAME
AND TMH.INDEX_NAME = LMH.INDEX_NAME
AND TMH.DATE = Dateadd(MONTH, 1, LMH.DATE)
WHERE  TMH.FLAG = 'M'
AND LMH.FLAG = 'M'
AND TMH.INDEX_DESCRIPTION NOT LIKE '%UNIQUE%'
AND TMH.INDEX_DESCRIPTION NOT LIKE 'CLUSTERED%'
AND ( TMH.USER_SEEKS_DELTA
+ TMH.USER_LOOKUPS_DELTA
+ TMH.USER_SCANS_DELTA ) = 0 --REH Not used this month
AND ( LMH.USER_SEEKS_DELTA
+ LMH.USER_LOOKUPS_DELTA
+ LMH.USER_SCANS_DELTA ) > 0 --REH was used last month

 ______________________________________________________________________________________

TABLES_WITHOUT_CLUSTERED_INDEX

SELECT CLUS.SERVER_NAME,
CLUS.DATABASE_NAME,
CLUS.TABLE_NAME,
CLUS.INDEX_NAME                                      AS heap_table,
CLUS.INDEX_KEYS                                      AS clustered_keys,
NONCLUS.INDEX_NAME                                   AS nonclustered_index,
NONCLUS.INDEX_KEYS,
( NONCLUS.RANGE_SCAN_COUNT - CLUS.RANGE_SCAN_COUNT ) AS nonclustered_vs_clustered_range_count,
CLUS.USER_SEEKS                                      AS clustered_user_seeks,
CLUS.USER_SCANS                                      AS clustered_user_scans,
CLUS.SINGLETON_LOOKUP_COUNT                          AS clustered_single_lookups,
CLUS.RANGE_SCAN_COUNT                                AS clustered_range_scan,
NONCLUS.USER_SEEKS                                   AS nonclustered_user_seeks,
NONCLUS.USER_SCANS                                   AS nonclustered_user_scans,
NONCLUS.SINGLETON_LOOKUP_COUNT                       AS nonclustered_single_lookups,
NONCLUS.RANGE_SCAN_COUNT                             AS nonclustered_range_scans,
NONCLUS.USER_UPDATES                                 AS nonclustered_user_updates
FROM   INDEX_STATS_CURR_VW CLUS
INNER JOIN INDEX_STATS_CURR_VW NONCLUS
ON CLUS.TABLE_NAME = NONCLUS.TABLE_NAME
AND CLUS.DATABASE_NAME = NONCLUS.DATABASE_NAME
AND CLUS.SERVER_NAME = NONCLUS.SERVER_NAME
AND CLUS.INDEX_NAME <> NONCLUS.INDEX_NAME
WHERE  CLUS.INDEX_DESCRIPTION LIKE 'HEAP%'
AND ( ( NONCLUS.RANGE_SCAN_COUNT > CLUS.RANGE_SCAN_COUNT )
OR ( NONCLUS.SINGLETON_LOOKUP_COUNT > CLUS.SINGLETON_LOOKUP_COUNT ) )
AND CLUS.PAGE_COUNT > 0
ORDER  BY CLUS.USER_LOOKUPS DESC,
CLUS.TABLE_NAME,
( NONCLUS.RANGE_SCAN_COUNT - CLUS.RANGE_SCAN_COUNT ) DESC

_____________________________________________________________________________________________

ADJUST_CLUSTERED_INDEXES

SELECT CLUS.SERVER_NAME,
CLUS.DATABASE_NAME,
CLUS.TABLE_NAME,
CLUS.INDEX_NAME                                      AS CLUSTERED_INDEX,
CLUS.INDEX_KEYS                                      AS CLUSTERED_KEYS,
NONCLUS.INDEX_NAME                                   AS NONCLUSTERED_INDEX,
NONCLUS.INDEX_KEYS,
( NONCLUS.RANGE_SCAN_COUNT - CLUS.RANGE_SCAN_COUNT ) AS NONCLUSTERED_VS_CLUSTERED_RANGE_COUNT,
CLUS.USER_SEEKS                                      AS CLUSTERED_USER_SEEKS,
CLUS.USER_SCANS                                      AS CLUSTERED_USER_SCANS,
CLUS.SINGLETON_LOOKUP_COUNT                          AS CLUSTERED_SINGLE_LOOKUPS,
CLUS.RANGE_SCAN_COUNT                                AS CLUSTERED_RANGE_SCAN,
NONCLUS.USER_SEEKS                                   AS NONCLUSTERED_USER_SEEKS,
NONCLUS.USER_SCANS                                   AS NONCLUSTERED_USER_SCANS,
NONCLUS.SINGLETON_LOOKUP_COUNT                       AS NONCLUSTERED_SINGLE_LOOKUPS,
NONCLUS.RANGE_SCAN_COUNT                             AS NONCLUSTERED_RANGE_SCANS,
NONCLUS.USER_UPDATES                                 AS NONCLUSTERED_USER_UPDATES
FROM   INDEX_STATS_CURR_VW CLUS
INNER JOIN INDEX_STATS_CURR_VW NONCLUS
ON CLUS.TABLE_NAME = NONCLUS.TABLE_NAME
AND CLUS.DATABASE_NAME = NONCLUS.DATABASE_NAME
AND CLUS.SERVER_NAME = NONCLUS.SERVER_NAME
AND CLUS.INDEX_NAME <> NONCLUS.INDEX_NAME
WHERE  CLUS.INDEX_DESCRIPTION LIKE 'CLUSTERED%'
AND ( ( NONCLUS.RANGE_SCAN_COUNT > CLUS.RANGE_SCAN_COUNT )
OR ( NONCLUS.SINGLETON_LOOKUP_COUNT > CLUS.SINGLETON_LOOKUP_COUNT ) )
ORDER  BY CLUS.USER_LOOKUPS DESC,
CLUS.TABLE_NAME,
( NONCLUS.RANGE_SCAN_COUNT - CLUS.RANGE_SCAN_COUNT ) DESC

______________________________________________________________________________________________________

ANALYZE_INDEX_KEY_ORDER

SELECT ISV.SERVER_NAME, ISV.DATABASE_NAME,
ISV.TABLE_NAME, ISV.INDEX_NAME,
ISV.INDEX_KEYS AS CURRENT_INDEX_ORDER,
Stuff ((SELECT ', ' + KEYCOLUMN
FROM   INDEX_KEY_ORDER_VW IKO
WHERE  ISV.SERVER_NAME = IKO.SERVER_NAME
AND ISV.DATABASE_NAME = IKO.DATABASE_NAME
AND ISV.TABLE_NAME = IKO.TABLENAME
AND ISV.INDEX_NAME = IKO.INDEXNAME
ORDER  BY TABLENAME,
INDEXNAME,
TOTAL_ROWS DESC
FOR xml path('')), 1, 1, '') AS POTENTIAL_INDEX_ORDER
FROM   INDEX_STATS_CURR_VW ISV
WHERE  ISV.ROW_COUNT > 1000
AND ISV.USER_SEEKS > 1000
--AND ISV.TABLE_NAME = 'AX Table Name'
-- AND ISV.DATABASE_NAME = 'AX Database Name'
--AND ISV.SERVER_NAME = 'AX Database Server Name'

 ____________________________________________________________________________________________


 INDEXES_BEING_SCANNED

SELECT TOP 100 *
FROM   INDEX_STATS_CURR_VW
WHERE  USER_SCANS > 0
AND INDEX_DESCRIPTION LIKE 'NONCLUSTERED%'
ORDER  BY USER_SCANS DESC


____________________________________________________________________________________________________

SEARCH_QUERY_PLANS_FOR_INDEX_USAGE

;WITH FT_CTE2 (QUERY_PLAN_HASH, QUERY_PLAN)
AS
(SELECT QUERY_PLAN_HASH, QUERY_PLAN
FROM   QUERY_PLANS
WHERE  CONTAINS (C_QUERY_PLAN, '"INVENTDIM" AND "INDEX SCAN"') -- find all statements scanning a specific table
--WHERE  CONTAINS (C_QUERY_PLAN, '"I_6143RECID"') — find all SQL statements that contain a specific index
)
SELECT TOP 100 *
FROM   QUERY_STATS_CURR_VW QS -- Queries from last data collection only
--FROM   QUERY_STATS_VW QS -- Review queries for all data collections
INNER JOIN FT_CTE2 FT2
ON QS.QUERY_PLAN_HASH = FT2.QUERY_PLAN_HASH
WHERE  1 = 1
-- AND LAST_EXECUTION_TIME > 'XXXXXXX'   -- find all queries that have executed after a specific time
ORDER  BY TOTAL_ELAPSED_TIME DESC





Install and Configure Zpl Printer on D365 F&O

  Setup Zpl Printer On D365 F&O Posted on Recently, I have had an opportunity review the possibilities to print license plates within D3...