Най-доброто, което успях да направя, е да опростя част от заявката и да я променя на функция с таблица. Скаларните функции са известни с лошо представяне и предимството на вградения TVF е, че дефиницията на заявката се разширява в основната заявка, подобно на изглед.
Това намалява значително времето за изпълнение на тестовете, които направих.
ALTER FUNCTION dbo.FuzySearchTVF (@Reference VARCHAR(200), @Target VARCHAR(200))
RETURNS TABLE
AS
RETURN
( WITH N (n) AS
( SELECT TOP (ISNULL(CASE WHEN DATALENGTH(@Reference) > DATALENGTH(@Target)
THEN DATALENGTH(@Reference)
ELSE DATALENGTH(@Target)
END, 0))
ROW_NUMBER() OVER(ORDER BY n1.n)
FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) AS N1 (n)
CROSS JOIN (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) AS N2 (n)
CROSS JOIN (VALUES (1), (1)) AS N3 (n)
WHERE @Reference IS NOT NULL AND @Target IS NOT NULL
), Src AS
( SELECT Reference = CASE WHEN DATALENGTH(@Reference) > DATALENGTH(@Target) THEN @Reference
ELSE @Reference + REPLICATE('_', DATALENGTH(@Target) - DATALENGTH(@Reference))
END,
Target = CASE WHEN DATALENGTH(@Target) > DATALENGTH(@Reference) THEN @Target
ELSE @Target + REPLICATE('_', DATALENGTH(@Target) - DATALENGTH(@Reference))
END,
WordLength = CASE WHEN DATALENGTH(@Reference) > DATALENGTH(@Target) THEN DATALENGTH(@Reference) ELSE DATALENGTH(@Target) END
WHERE @Reference IS NOT NULL
AND @Target IS NOT NULL
AND @Reference != @Target
), Scores AS
( SELECT seq = t1.n ,
Letter = SUBSTRING(s.Reference, t1.n, 1),
s.WordLength ,
LetterScore = s.WordLength - ISNULL(MIN(ABS(t1.n - t2.n)), s.WordLength)
FROM Src AS s
CROSS JOIN N AS t1
INNER JOIN N AS t2
ON SUBSTRING(@Target, t2.n, 1) = SUBSTRING(s.Reference, t1.n, 1)
WHERE @Reference IS NOT NULL
AND @Target IS NOT NULL
AND @Reference != @Target
GROUP BY t1.n, SUBSTRING(s.Reference, t1.n, 1), s.WordLength
)
SELECT [Score] = 100
WHERE @Reference = @Target
UNION ALL
SELECT 0
WHERE @Reference IS NULL OR @Target IS NULL
UNION ALL
SELECT CAST(SUM(LetterScore) * 100.0 / MAX(WordLength * WordLength) AS NUMERIC(5, 2))
FROM Scores
WHERE @Reference IS NOT NULL
AND @Target IS NOT NULL
AND @Reference != @Target
GROUP BY WordLength
);
И това ще се нарича:
SELECT f.Score
FROM dbo.Customer AS c
CROSS APPLY [dbo].[FuzySearch]('First Name Middle Name Last Name', c.FirstName) AS f
Все пак това е доста сложна функция и, в зависимост от броя на записите във вашата таблица с клиенти, мисля, че намаляването й до 1 секунда ще бъде малко предизвикателство.