优化使用函数的SQL Server存储过程?

时间:2012-07-25 19:32:24

标签: sql-server-2008 tsql query-optimization

我想在优化以下查询方面提供一些帮助:

SELECT DISTINCT TOP (@NumberOfResultsRequested) dbo.FilterRecentSearchesTitles(OriginalSearchTerm) AS SearchTerms
FROM UserSearches
WHERE WebsiteID = @WebsiteID
AND LEN(OriginalSearchTerm) > 20
--AND dbo.FilterRecentSearchesTitles(OriginalSearchTerm) NOT IN (SELECT KeywordUrl FROM PopularSearchesBaseline WHERE WebsiteID = @WebsiteID)
GROUP BY OriginalSearchTerm, GeoID

没有注释掉的行,它运行正常。我在UserSearches.OriginalSearchTerm,WebsiteID和PopularSearchesBaseline.KeywordUrl上设置了一个索引,但是该行中的查询仍然运行缓慢。

- 更新 - 使用的功能如下:

 ALTER FUNCTION [dbo].[FilterRecentSearchesTitles]
(
    @SearchTerm VARCHAR(512)
)

RETURNS VARCHAR(512)

AS
BEGIN
    DECLARE @Ret VARCHAR(512)

    SET @Ret = dbo.RegexReplace('[0-9]', '', REPLACE(@SearchTerm, '__s', ''), 1, 1)
    SET @Ret = dbo.RegexReplace('\.', '', @Ret, 1, 1)
    SET @Ret = dbo.RegexReplace('\s{2,}', ' ', @Ret, 1, 1)
    SET @Ret = dbo.RegexReplace('\sv\s', ' ', @Ret, 1, 1)

    RETURN(@Ret)
END

使用Reglar Expression Workbench代码。

然而,正如我所提到的 - 如果没有当前注释掉的行,它运行正常。

还有其他建议吗?

3 个答案:

答案 0 :(得分:1)

我猜测dbo.FilterRecentSearchesTitles(OriginalSearchTerm)是一个函数。我的建议是将其重写为table valued function,以便您可以返回可以加入的表格。

否则,您正在为您尝试返回的每一行调用该函数,这将导致您的问题。

如果你不能重写这个函数,那么为什么不创建一个只执行一次的存储过程,类似于:

SELECT DISTINCT TOP (@NumberOfResultsRequested) dbo.FilterRecentSearchesTitles(OriginalSearchTerm) AS SearchTerms
INTO #temp
WHERE WebsiteID = @WebsiteID


SELECT *
FROM #temp
WHERE SearchTerms NOT IN (SELECT KeywordUrl 
                            FROM PopularSearchesBaseline 
                            WHERE WebsiteID = @WebsiteID)

然后在执行一次函数后将记录放入临时表中,然后在临时表上选择。

答案 1 :(得分:1)

在这种情况下,我可能会尝试使用persisted computed column

ALTER TABLE UserSearches ADD FilteredOriginalSearchTerm AS dbo.FilterRecentSearchesTitles(OriginalSearchTerm) PERSISTED

您可能需要将WITH SCHEMABINDING添加到您的函数(和RegexReplace函数)中,如下所示:

ALTER FUNCTION [dbo].[FilterRecentSearchesTitles]
(
    @SearchTerm VARCHAR(512)
)

RETURNS VARCHAR(512)

WITH SCHEMABINDING -- You will need this so the function is considered deterministic

AS
BEGIN
    DECLARE @Ret VARCHAR(512)

    SET @Ret = dbo.RegexReplace('[0-9]', '', REPLACE(@SearchTerm, '__s', ''), 1, 1)
    SET @Ret = dbo.RegexReplace('\.', '', @Ret, 1, 1)
    SET @Ret = dbo.RegexReplace('\s{2,}', ' ', @Ret, 1, 1)
    SET @Ret = dbo.RegexReplace('\sv\s', ' ', @Ret, 1, 1)

    RETURN(@Ret)
END

这使您的查询如下所示:

SELECT DISTINCT TOP (@NumberOfResultsRequested) FilteredOriginalSearchTerm AS SearchTerms
FROM UserSearches
WHERE WebsiteID = @WebsiteID
AND LEN(OriginalSearchTerm) > 20
AND FilteredOriginalSearchTerm NOT IN (SELECT KeywordUrl FROM PopularSearchesBaseline WHERE WebsiteID = @WebsiteID)
GROUP BY OriginalSearchTerm, GeoID

可能使用连接而不是not in来优化速度(如果需要),或者可能是不同的索引(可能在计算列或某些覆盖索引上)。另外,带有DISTINCT的{​​{1}}对我来说有点代码味道,但它可能是合法的。

答案 2 :(得分:0)

我没有使用SELECT上的函数,而是修改了INSERT查询以包含此函数。这样,当我以后想要检索数据时,我避免为每一行调用该函数。