代码之家  ›  专栏  ›  技术社区  ›  Marks

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

  •  2
  • Marks  · 技术社区  · 16 年前

    我目前正在为一个大数据库中的复杂搜索开发一个存储过程。因为有几千个条目,所以可以返回我想使用分页。虽然它在工作,但我觉得太慢了。我读了很多关于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是一个用逗号分隔的搜索关键字列表,已经包含了通配符。

    我希望有人能帮助我优化这一点,因为在主表中有20000个条目的数据库中,一次搜索持续800ms,并且随着条目数的增加而增加。最终申请需要处理超过10万个条目。

    我非常感谢你的帮助。 标志

    2 回复  |  直到 16 年前
        1
  •  2
  •   HLGEM    16 年前

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

    我的意思是20000是一个很小很小的表,100000也是,所以看起来你还没有索引。

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

        2
  •  1
  •   Tom H zenazn    16 年前

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

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