Điều tốt nhất tôi có thể làm là đơn giản hóa một số truy vấn và thay đổi nó thành một hàm có giá trị bảng. Các hàm vô hướng nổi tiếng là hoạt động kém và lợi ích của TVF nội tuyến là định nghĩa truy vấn được mở rộng thành truy vấn chính, giống như một dạng xem.
Điều này làm giảm đáng kể thời gian thực hiện đối với các bài kiểm tra tôi đã thực hiện.
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
);
Và điều này sẽ được gọi là:
SELECT f.Score
FROM dbo.Customer AS c
CROSS APPLY [dbo].[FuzySearch]('First Name Middle Name Last Name', c.FirstName) AS f
Tuy nhiên, nó vẫn là một chức năng khá phức tạp và tùy thuộc vào số lượng bản ghi trong bảng khách hàng của bạn, tôi nghĩ rằng việc giảm nó xuống còn 1 giây sẽ là một chút thách thức.