sqlsql-serverdynamics-ax-2012-r3

SQL WHERE clause perfromance issue AX2012R3


I am trying to optimize a query. Note that I am using Microsoft Dynamics AX and traced this query to SQL. The query except for the index hints is being generated by Dynamics and I am wondering if I have to rewrite the whole statement in AX or if I can fix this by simply adding changes to indexes. The query is as follows:

SELECT        T1.PARTITION, T1.DECIMALPRECISION, T1.RECID, T1.RECVERSION, T1.SYMBOL, T1.SYSTEMOFUNITS, T1.UNITOFMEASURECLASS
    FROM            UNITOFMEASURE AS T1 WITH(INDEX(I_4436SYMBOLIDX))
    WHERE        T1.PARTITION = 5637144576 AND EXISTS
                                 (SELECT        'x' AS Expr1
                                   FROM            UNITOFMEASURECONVERSION AS T2 WITH(INDEX(I_4438CONVERSIONIDX))  

                                   WHERE        (T2.PARTITION = 5637144576 ) 
                                   AND (T2.PRODUCT = 5637297578 OR T2.PRODUCT = 0) 
                                   AND (T1.RECID = T2.FROMUNITOFMEASURE) 
                                   AND (T2.TOUNITOFMEASURE = 0) OR
                                                             (T2.PARTITION = 5637144576) AND (T2.PRODUCT = 5637297578 OR
                                                             T2.PRODUCT = 0) AND (T1.RECID = T2.TOUNITOFMEASURE) AND (T2.FROMUNITOFMEASURE = 0))

This query returns the following execution plan: You can see it reads 5 342544 records. The corresponding tables contain 1342 and 3984 records. enter image description here

If i remove the first T1.PARTITION = 5637144576where clause, the query executes how it should. This is the updated query:

SELECT        T1.PARTITION, T1.DECIMALPRECISION, T1.RECID, T1.RECVERSION, T1.SYMBOL, T1.SYSTEMOFUNITS, T1.UNITOFMEASURECLASS
FROM            UNITOFMEASURE AS T1 WITH(INDEX(I_4436SYMBOLIDX))
WHERE        EXISTS
                             (SELECT        'x' AS Expr1
                               FROM            UNITOFMEASURECONVERSION AS T2 WITH(INDEX(I_4438CONVERSIONIDX))  

                               WHERE        (T2.PARTITION = 5637144576 ) 
                               AND (T2.PRODUCT = 5637297578 OR T2.PRODUCT = 0) 
                               AND (T1.RECID = T2.FROMUNITOFMEASURE) 
                               AND (T2.TOUNITOFMEASURE = 0) OR
                                                         (T2.PARTITION = 5637144576) AND (T2.PRODUCT = 5637297578 OR
                                                         T2.PRODUCT = 0) AND (T1.RECID = T2.TOUNITOFMEASURE) AND (T2.FROMUNITOFMEASURE = 0))

Now it uses the following execution plan: enter image description here

Here's more information about the indexes used: I_4436SYMBOLIDX

enter image description here

Can I optimize the performance by changing the indexes ? Or do I have to rewrite the functionality by building the query myself in Dynamics AX 2012.

Thanks in advance.


Solution

  • Your query is a mess. The OR in the EXISTS is going to kill performance. So, use multiple EXISTS clauses. I think this is the logic:

    SELECT . . .
    FROM UNITOFMEASURE AS T1 
    WHERE T1.PARTITION = 5637144576 AND
          (EXISTS (SELECT 1
                   FROM UNITOFMEASURECONVERSION T2
                   WHERE T2.FROMUNITOFMEASURE = T1.RECID AND
                         T2.PARTITION = 5637144576 AND
                         T2.PRODUCT IN (5637297578, 0)  AND
                         T2.TOUNITOFMEASURE = 0 
                  ) OR 
           EXISTS (SELECT 1
                   FROM UNITOFMEASURECONVERSION T2
                   WHERE T2.TOUNITOFMEASURE = T1.RECID AND
                         T2.PARTITION = 5637144576 AND
                         T2.PRODUCT IN (5637297578, 0) AND
                         T2.FROMUNITOFMEASURE = 0
                  )
          );
    

    Then you want indexes on:

    I think the second index is useful for both subqueries.

    Actually, if I interpreted the query correctly, it can be written as:

    SELECT . . .
    FROM UNITOFMEASURE AS T1 
    WHERE T1.PARTITION = 5637144576 AND
          EXISTS (SELECT 1
                  FROM UNITOFMEASURECONVERSION T2
                  WHERE T2.FROMUNITOFMEASURE = T1.RECID AND
                        T2.PARTITION = 5637144576 AND
                        T2.PRODUCT IN (5637297578, 0)  AND
                        (T2.TOUNITOFMEASURE = 0 OR T2.FROMUNITOFMEASURE = 0)
                 );
    

    And the above indexes should work.