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)
WHERE CMPNAME LIKE '%' + @Query + '%'
= quick; WHERE ADTOWN LIKE '%' + @Query + '%'
= quick; 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.