202
Views
2
Comments
Solved
SQL query takes long time to complete
Question
Application Type
Reactive
Service Studio Version
11.12.7 (Build 51940)

Hi community,

Yesterday we did roll out a new version of our application to production and since then we are experiencing slow queries (e.g. 16 seconds to complete where it was previously 0.25 seconds). 

We did add some extra lines to our SQL query so at first we thought that's where the problem started. After removing these extra lines, we see that the performance is still very bad. To give a better idea of the size of the number of orders, I would like to state that it is about 800. Also we are using a SQL query since we are using a few functions that cannot be used within aggregates. We are not sure on how to debug this process since removing lines on the SQL query does not seem to improve the performance. Also we are using a Data Action to retrieve the orders and are using a structure to minimize the number of fields fetched from the database.

Does anybody have any recommendations based on the query below (e.g. did we use any bad practice in this query? Or did we miss something in the actual query that is causing a lot of seperate (sub)queries?)? Also good to mention that we did use indexes to speed up de data retrieval.

If more information is need please let me know since this is giving me a headache to solve.

SELECT      ord.[Id],
            ord.[OrderNumber],
            ord.[OrderKindCode],
            ord.[CustomerLastName],
            ord.[CustomerFullName],
            ord.[AssemblyDate],
            ord.[AssemblyWeek],
            ord.[AssemblerCode],
            ord.[AssemblerFullName],
            ord.[CustomerManagerCode],
            ord.[CustomerManagerFullName],
            ord.[QualityManagerCode],
            ord.[QualityManagerFullName],
            ord.[ExpectedCompletionDate],
            lov.[ViewMoment],
            COUNT(vst.[Id]) As nrVisits,
            (
                SELECT  COUNT({Note}.[Id])
                FROM    {Note}
                WHERE   {Note}.[OrderId] = ord.[Id]
                AND     {Note}.[Moment] >= COALESCE(lov.[ViewMoment], '1900-01-01')
                AND     {Note}.[UserId] <> @UserId
                AND     (
                            CASE
                                WHEN (@CheckMainAssemblerRole = 1)
                                    THEN (
                                            CASE
                                                WHEN ({Note}.[VisibleForAssembler] = 1)
                                                    THEN 1
                                                ELSE 0
                                                END
                                         )
                                ELSE 1
                                END
                            ) = 1
            ) As nrUnreadNotes,
            (
                SELECT      COUNT(DISTINCT ord.[Id])
                FROM    (((  {Order} ord
                                LEFT JOIN {UserExtended} cmn
                                    ON ord.[CustomerManagerCode] = cmn.[UserNameConcent] )
                                LEFT JOIN {UserExtended} qmn
                                    ON ord.[QualityManagerCode] = qmn.[UserNameConcent] )
                                LEFT JOIN {UserExtended} acn
                                    ON ord.[AssemblerCode] = acn.[SanitaryAssemblerCodeConcent] )
                WHERE       @Where
            ) As nrOrders
        
FROM    (((((   {Order} ord
                LEFT JOIN {Visit} vst
                    ON ord.[Id] = vst.[OrderId] )
                LEFT JOIN {LastOrderView} lov
                    ON ord.[Id] = lov.[OrderId]
                    AND @UserId = lov.[UserId] )
                LEFT JOIN {UserExtended} cmn
                    ON ord.[CustomerManagerCode] = cmn.[UserNameConcent] )
                LEFT JOIN {UserExtended} qmn
                    ON ord.[QualityManagerCode] = qmn.[UserNameConcent] )
                LEFT JOIN {UserExtended} acn
                    ON ord.[AssemblerCode] = acn.[SanitaryAssemblerCodeConcent] )
                    
WHERE       @Where

GROUP BY    ord.[Id],
            ord.[OrderNumber],
            ord.[OrderKindCode],
            ord.[CustomerLastName],
            ord.[CustomerFullName],
            ord.[AssemblyDate],
            ord.[AssemblyWeek],
            ord.[AssemblerCode],
            ord.[AssemblerFullName],
            ord.[CustomerManagerCode],
            ord.[CustomerManagerFullName],
            ord.[QualityManagerCode],
            ord.[QualityManagerFullName],
            ord.[ExpectedCompletionDate],
            lov.[ViewMoment]
            
ORDER BY    ord.[AssemblyDate] ASC,
            ord.[CustomerLastName] ASC
            
OFFSET @StartIndex ROWS

FETCH NEXT @MaxRecords ROW ONLY

Thanks, 

Bart

2018-10-29 08-31-03
João Marques
 
MVP
Solution

Hi Bart,


There are several things on your query that don't contribute for its good performance. Only looking at it at a first glance, a few caught my eye:

  • Doing queries on a SELECT field which joins to a table in the FROM clause is a performance killer
  • You're sorting by AssemblyDate and CustomerLastName but you have an index on attributes AssemblerCode and DisplayOrderInScreen
  • You have a lot of LEFT JOINS, I don't know if they are really needed, but INNER JOIN is way more performant than a LEFT JOIN.
  • You're doing a lot of JOINs on strings, usually JOINs are made on ids / integers since they are more performant. Make sure that you need them and that they are indexed.

If you have access to SQL server, you can run the Execution Plan and exactly pinpoint what part of the query is hurting you more.

In any case, I do recommend you using more about SQL server good practices and anti-patterns as well as on indexing, you'll find plenty on Google or on YouTube.


Kind regards,
João

2021-04-12 11-47-04
Bart Nooijens

Hi João,

Thanks for your answer. I must say I  just start using SQL this year and trying to improve, so your answer does help me a lot.

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.