简体   繁体   中英

SQL Server 2008 R2 stored procedure is slow

I am joining 3 different tables for an auto-complete functionality and it has to be quick. The suggestions have to come back nice and prompt. I need to look through 3 different fields for the answer with a LIKE operator. See details below.

DECLARE @Space AS CHAR(1) = ' ';

 SELECT TOP (@QuantityToReturn) * 
 FROM
     (SELECT
          C.CMPID, C.CMPNAME, C.CMPTHEIRCODE, AD.ADTOWN
      FROM COMPANY C
      JOIN [dbo].[COMPADDRESS] CA ON CA.CMPID = C.CMPID
      JOIN [dbo].[ADDRESS] ad ON AD.ADID = CA.ADID
      JOIN [dbo].SUPPLIER SUP ON C.CMPID = SUP.CMPID
      WHERE 
          (C.CMPID = @LoggedInUserId
           OR @LoggedInUserId = dbo.fnIsAParentCompanyOf(@LoggedInUserId, C.CMPID) 
           OR @LoggedInUserId = 12345)

      UNION 

      SELECT
          C.CMPID, C.CMPNAME, C.CMP_THEIRCODE, AD.ADTOWN
      FROM COMPANY C
      JOIN [dbo].[COMPADDRESS] CA ON ca.CMPID = C.CMPID
      JOIN [dbo].[ADDRESS] AD ON AD.ADID = CA.ADID
      JOIN [dbo].CUSTOMER CUS ON C.CMPID = CUS.CMPID AND CUS.CUSTISTHIS = 1
      WHERE 
          (C.CMPID = @LoggedInUserId
           OR @LoggedInUserId = dbo.fnIsAParentCompanyOf(@LoggedInUserId, C.CMPID) 
           OR @LoggedInUserId = 12345)
      ) AS Results
      WHERE 
          (CMPNAME + @Space + ADTOWN + @Space + CMPTHEIRCODE) LIKE '%' + @Query + '%'

The above code is slow (~ 9sec)

  • If I use: WHERE CMPNAME LIKE '%' + @Query + '%' = quick;
  • If I use: WHERE ADTOWN LIKE '%' + @Query + '%' = quick;
  • If I use: WHERE CMPTHEIRCODE LIKE '%' + @Query + '%' = quick;

It is just when I concatenate them that goes slow?

What I would try is this:

WHERE 
    LEN(@Query) <> LEN(REPLACE(@Query, CMPNAME, ''))

    AND (LEN(@Query) <> LEN(REPLACE(@Query, ADTOWN, ''))
         AND CHARINDEX(CMPNAME, @Query) = (CHARINDEX(ADTOWN, @Query) - 1 - LEN(CMPNAME)) 
        ) -- making sure that the value of ADTOWN comes after CMPNAME

    AND (LEN(@Query) <> LEN(REPLACE(@Query, CMPTHEIRCODE, ''))
         AND CHARINDEX(ADTOWN, @Query) = (CHARINDEX(CMPTHEIRCODE, @Query) - 1 - LEN(ADTOWN))
        ) -- making sure that the value of CMPTHEIRCODE comes after ADTOWN

I've tried re-implementing the logic of your 3 conditions to run on the parameters and not on the columns on which you have indexes. My assumption is that in this scenario the indexes will be used.

PS: Small adjustments migth be needed when finding / substracting charindex's results, in case i made some mistakes in my calculations, but hopefully you got the idea. - SQLFiddle to validate that the CHARINDEX() comparisons are correct .

Also, I would recommend / try some additional changes to the top part of the query so in the end your script would look like this:

DECLARE @Space AS CHAR(1) = ' ';

SELECT TOP (@QuantityToReturn) *
FROM (
    SELECT C.CMPID
        ,C.CMPNAME
        ,C.CMPTHEIRCODE
        ,AD.ADTOWN
    FROM COMPANY C
    INNER JOIN [dbo].[COMPADDRESS] CA
        ON CA.CMPID = C.CMPID
    INNER JOIN [dbo].[ADDRESS] ad
        ON AD.ADID = CA.ADID
    WHERE (
            C.CMPID = @LoggedInUserId
            OR @LoggedInUserId = dbo.fnIsAParentCompanyOf(@LoggedInUserId, C.CMPID)
            OR @LoggedInUserId = 12345
            )
        AND EXISTS (
            SELECT 1
            FROM [dbo].SUPPLIER SUP
            WHERE C.CMPID = SUP.CMPID
            )

    UNION

    SELECT C.CMPID
        ,C.CMPNAME
        ,C.CMP_THEIRCODE
        ,AD.ADTOWN
    FROM COMPANY C
    INNER JOIN [dbo].[COMPADDRESS] CA
        ON ca.CMPID = C.CMPID
    INNER JOIN [dbo].[ADDRESS] AD
        ON AD.ADID = CA.ADID
    WHERE (
            C.CMPID = @LoggedInUserId
            OR @LoggedInUserId = dbo.fnIsAParentCompanyOf(@LoggedInUserId, C.CMPID)
            OR @LoggedInUserId = 12345
            )
        AND EXISTS (
            SELECT 1
            FROM [dbo].CUSTOMER CUS
            WHERE C.CMPID = CUS.CMPID
                AND CUS.CUSTISTHIS = 1
            )
    ) AS Results
WHERE LEN(@Query) <> LEN(REPLACE(@Query, CMPNAME, ''))
    AND (
        LEN(@Query) <> LEN(REPLACE(@Query, ADTOWN, ''))
        AND CHARINDEX(CMPNAME, @Query) = (CHARINDEX(ADTOWN, @Query) - 1 - LEN(CMPNAME))
        ) -- making sure that the value of ADTOWN comes after CMPNAME
    AND (
        LEN(@Query) <> LEN(REPLACE(@Query, CMPTHEIRCODE, ''))
        AND CHARINDEX(ADTOWN, @Query) = (CHARINDEX(CMPTHEIRCODE, @Query) - 1 - LEN(ADTOWN))
        ) -- making sure that the value of CMPTHEIRCODE comes after ADTOWN

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM