0

I have a very strange issue where depending on the query parameters the database call from the code below will fail with:

Exception.Message = Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
System.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out

The code is:

        public IList<ProductCommissionMinimal> FindProductCommissionMinimal(string premiumTypeCode, string sellerId, string eposProductId, string singlePremiumPolicy)
        {
            var sql = @"
SELECT distinct
        CSP.ProductSubtypeId, PC.ProductFamilyId, PC.ProductId
    FROM
        ProductCommission PC,
        CommissionTemplate CT,
        Seller S,
        Product P,
        CoreSystemProduct CSP
    WHERE
        PC.ProductFamilyId = CSP.ProductFamilyId AND PC.ProductId = CSP.ProductId
        AND P.ProductFamilyId = CSP.ProductFamilyId AND P.ProductId = CSP.ProductId
        AND CT.PremiumTypeCd = @premiumTypeId
        AND S.SellerId = @sellerId
        AND CT.CommissionTemplateSeq = PC.CommissionTemplateSeq
        AND CT.StatusCd = 'O'
        AND PC.DistributionId = S.DistributionId
        AND CT.AvailabilityCd <> 'I'
        AND CSP.CoreProductId = @eposProductId";

            var parameters = new Dictionary<string, object>
            {
                { "@premiumTypeId", premiumTypeCode },
                { "@sellerId", sellerId },
                { "@eposProductId", eposProductId },
            };

            if (premiumTypeCode == "1")
            {
                sql = sql + " AND P.IsSinglePremiumOnlyCd = @singlePremiumPolicy";
                parameters["@singlePremiumPolicy"] = singlePremiumPolicy;
            }

            return Query<ProductCommissionMinimal>(sql, parameters);
        }

The Query method executes a generic method which ultimately executes System.Data.Common.DbCommand.ExecuteReader() This same generic method is used throughout our code base in hundreds of different inline queries without issue so I don't think there is any issue there. This generic method also uses the default command timeout i.e. none is specified so 30 seconds. However this SQL query should return almost immediately so I would not think that this is just simply a long running query.

The issue I'm seeing is that for some parameter combinations this works fine but errors for others. For example it seems to error for: premiumTypeCode=5&sellerId=NQ49&eposProductId=UPR3SAA&singlePremiumPolicy=Y but not premiumTypeCode=5&sellerId=NQ49&eposProductId=ABC3SAA&singlePremiumPolicy=Y

The one unique thing about this particular method is that it is the only one in our code base that uses the CoreProductId column. It seems to be if I change that parameter value by a few letters it works fine.

I'm losing my mind with this. Any insight would help greatly. The backend database is SQL Server 2016.

EDIT I've updated the query to this:

    public IList<ProductCommissionMinimal> FindProductCommissionMinimal(string premiumTypeCode, string sellerId, string eposProductId, string singlePremiumPolicy)
    {
        var sql = @"
SELECT distinct CSP.ProductSubtypeId, PC.ProductFamilyId, PC.ProductId
                    FROM
                        ProductCommission PC
                    INNER JOIN
                           CommissionTemplate CT 
                    ON 
                           CT.CommissionTemplateSeq = PC.CommissionTemplateSeq
                    INNER JOIN
                        Seller S 
                    ON 
                           PC.DistributionId = s.DistributionId
                    INNER JOIN
                        CoreSystemProduct CSP 
                    ON  
                           PC.ProductFamilyId = CSP.ProductFamilyId AND PC.ProductId = CSP.ProductId
                    INNER JOIN
                        Product P 
                    ON 
                           P.ProductId = CSP.ProductId AND P.ProductFamilyId = CSP.ProductFamilyId  
                    WHERE
                        CT.PremiumTypeCd = @premiumTypeId
                        AND S.SellerId = @sellerId       
                        AND CT.StatusCd = 'O'
                        AND PC.DistributionId = S.DistributionId
                        AND CT.AvailabilityCd <> 'I'
                        AND CSP.CoreProductId = @eposProductId";

        var parameters = new Dictionary<string, object>
        {
            { "@premiumTypeId", premiumTypeCode },
            { "@sellerId", sellerId },
            { "@eposProductId", eposProductId },
        };

        if (premiumTypeCode == "1")
        {
            sql = sql + " AND P.IsSinglePremiumOnlyCd = @singlePremiumPolicy";
            parameters["@singlePremiumPolicy"] = singlePremiumPolicy;
        }

        return Query<ProductCommissionMinimal>(sql, parameters);
    }

As recommended. However this is still failing for certain parameter combinations e.g. premiumTypeCode=1&sellerId=TC99&eposProductId=UPO2SAA&singlePremiumPolicy=N

Ben
  • 2,518
  • 4
  • 18
  • 31
  • Did you try to run the query directly inside sql management studio? Just to check the duration? Also I'm not a huge SQL expert, but maybe you should use JOINs here? – Rafalon Apr 14 '21 at 13:39
  • @Rafalon Yes I did. Works absolutely fine there. It returns almost instantly. In that test I just substituted the parameter values directly in single quotes in the query. I agree the query could be improved but in theory it should work and it does for most scenarios. – Ben Apr 14 '21 at 13:44
  • You should construct your query using proper `join` syntax that's existed since 1992 – Stu Apr 14 '21 at 13:44
  • 1
    Have you tried executing `dbcc freeproccache` and rerunning? – Stu Apr 14 '21 at 13:45
  • Does the timeout occur every time for a given set of parameters? – Rafalon Apr 14 '21 at 13:45
  • 2
    [Parameter-Sniffing](https://www.brentozar.com/sql/parameter-sniffing/) – Stu Apr 14 '21 at 13:49
  • Just like your previous question - check the execution plans. And it is long past time to evolve and stop using [old-style joins](https://sqlblog.org/2009/10/08/bad-habits-to-kick-using-old-style-joins). – SMor Apr 14 '21 at 14:19
  • I understand that the SQL is outdated style but I'm clueless as to why it works with some parameters and not others. I've updated SQL anyway still seeing similar issues – Ben Apr 14 '21 at 14:39
  • The join syntax won't be the root cause, it's a parameterized query and potentially will have parameter sniffing issues. When a query is compiled for the first time, its execution plan is built using the parameters supplied at the time; when you invoke it with different parameters the same plan is used but may be sub-optimal. If you add `option (recompile)` to the end of the query, do you still see a timeout? – Stu Apr 14 '21 at 14:43
  • Amending `option (recompile)` has done the trick alright. However if I remove this and retry it times out again. Is this something that needs to be left in the query? Is this safe to leave in the query? I'm a bit confused why is only affected in certain scenarios. – Ben Apr 14 '21 at 15:22
  • Did you visit the above link – Stu Apr 14 '21 at 16:41

0 Answers0