SQL - 优化复杂的分页搜索查询

时间:2010-06-15 15:06:52

标签: sql database optimization stored-procedures paging

我目前正在为大型数据库中的复杂搜索开发存储过程。因为有很多条目,可以返回我想要使用分页。虽然它有效,但我觉得它太慢了。我阅读了很多关于SQL查询分页和优化性能的帖子和文章。但大多数“优化”仅对非常基本的请求有帮助,例如“从表x中提供项目20-30”。

由于我们的世界并不那么简单,而且有更复杂的查询需要帮助我优化以下查询:

CREATE PROCEDURE [SearchItems]
@SAttr1 BIT = 0,
@SAttr2 BIT = 0,
@SAttr3 BIT = 0,
@Flag1 BIT = 0,
@Flag2 BIT = 0,
@Param1 VARCHAR(20),
@Param2 VARCHAR(10),
@SkipCount BIGINT,
@TakeCount BIGINT,
@SearchStrings NVARCHAR(1000)    
AS
    DECLARE @SearchStringsT TABLE(
        Val NVARCHAR(30)
    )

    INSERT INTO @SearchStringsT 
    SELECT * FROM dbo.Split(@SearchStrings,',');

WITH ResultTable AS (
    SELECT  Table1.*, ROW_NUMBER() OVER(ORDER BY Table1.ID ASC) AS [!ROWNUM!]
    FROM Table1
    INNER JOIN Table2 ON Table1.ID = Table2.FK1
    INNER JOIN Table3 ON Table2.ID = Table3.FK2
    INNER JOIN Table4 ON Table3.XX = Table4.FKX
    WHERE Table1.X1 = @Parameter1
    AND
        (@Flag1 = 0 OR Table1.X2 = 1) AND
        (@Flag2 = 0 OR Table2.X4 = @Parameter2) AND
        (@Flag3 = 0 OR EXISTS(SELECT * FROM Table5 WHERE Table5.ID = Table3.X1)) 
    AND
    (                   
        (@SAttr1 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table1.X1 LIKE Val)) OR
        (@SAttr2 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table2.X1 LIKE Val)) OR
        (@SAttr3 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table3.X1 LIKE Val)) OR
        (@SAttr4 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table4.X1 LIKE Val))
    )
)
SELECT TOP(@TakeCount) * FROM ResultTable
WHERE [!ROWNUM!] BETWEEN (@SkipCount + 1) AND (@SkipCount + @TakeCount)
RETURN

@SAttr参数是指定是否搜索字段的位参数,@ Flag参数是打开/关闭某些布尔表达式的检查,@ SkipCount和@TakeCount用于分页。 @SearchString是一个逗号分隔的搜索关键字列表,已包含通配符。

我希望有人可以帮我优化这一点,因为主表中包含20.000个条目的数据库中的单个搜索持续800毫秒,并且随着条目数的增加而增加。最终的应用程序需要处理超过100,000个条目。

我非常感谢你的每一个帮助。 标记

2 个答案:

答案 0 :(得分:2)

虽然我同意Tom H.这可能是动态SQL最好的情况(我是一个存储过程类型的女孩,所以我不经常这么说),可能是你不喜欢你的表上有很好的索引。是否所有可能的搜索字段都已编入索引?所有的FK都被编入索引吗?

我的意思是20,000是一张很小的小桌子而且100,000也是,所以看起来好像你可能还没有编入索引。

检查执行计划以查看是否正在使用索引。

答案 1 :(得分:1)

存储过程不是很擅长超级泛型,因为它会阻止SQL Server始终使用最佳方法。在最近的类似情况下,我使用了( gasp )动态SQL。我的搜索存储过程将构建SQL代码来执行搜索,使用分页就像你拥有它一样(WITH with ROW_NUMBER()等)。优点是如果参数表明在搜索中没有使用一条信息,那么生成的代码将省略它。最后,它允许更好的查询计划。

确保正确使用sp_executesql以防止SQL注入攻击。