使用临时表的SQL查询速度更快?

时间:2011-08-09 17:34:35

标签: sql-server

我对SQL很新,但我需要弄清楚如何更快地继承一大堆现有的查询。

这里有一个WHERE子句:

 @SearchFor nvarchar(200)        
 ,@SearchIn nvarchar(1024)      
 ,@SearchActivity int   

    -- stuff here I've left out ---

WHERE
    ( -- filter for all queries --
            (FT_TBL.IsActive = 1)
        AND (FT_TBL.IsPro = 1)
        AND (
            (FT_TBL.DatePaidUpTo >= @CurrentTime)
            OR (
                (FT_TBL.IsFromPaidBusinessDB = 1) 
                AND (FT_TBL.DatePaidUpTo IS NULL)
            )
        )
        AND (aspnet_Membership.IsApproved = 1)
    )       
    AND ( -- filter if user fills in 'searchfor' box --
           (@SearchFor IS NULL)
        OR (FT_TBL.CompanyName like '%' + @SearchFor + '%') 
        OR (aspnet_Users.UserName like '%' + @SearchFor + '%')
        OR (Activities.Activity like '%' + @SearchFor + '%')
    )
    AND ( -- filter if user fills in 'searchIn' box --
           (@SearchIn IS NULL)
        OR (a1.City LIKE '%' + @SearchIn + '%') 
        OR (a1.Region LIKE '%' + @SearchIn + '%') 
        OR (a1.Postcode LIKE '%' + @SearchIn + '%') 
        OR (Country.Name LIKE '%' + @SearchIn + '%')
    )
    AND ( -- filter by activity --
           (@SearchActivity IS NULL)
        OR (@SearchActivity = Activities.ActivityID)
    )

    AND NOT EXISTS (Select a2.AddressId, a2.UserId
            from Addresses a2
            where a2.userid = a1.UserId
            and a2.addressid < a1.addressid
    )

SearchInSearchForSearchActivity是可以通过以过滤搜索结果的三个字段。我们的想法是,如果每个传递'null',搜索结果的唯一约束来自WHERE子句中的第一个块。如果这3个字段中的任何一个不为空,则会根据该行的位置,名称或类别进一步限制结果。最后一个块是一个小技巧 - 用户可以附加几个地址,但每个用户只应返回一行。所以这个块只选择ID最低的地址。

目前这个查询运行速度非常慢 - 部分是因为我们的硬件欠载,但我也怀疑,因为这个过程效率不高。我正在努力找到让它变得更好的方法 - 当我试图学习SQL如何同时工作时很困难!

我的一个想法是尝试分两个阶段进行搜索 - 例如,首先只使用WHERE子句的第一个块进行查询,然后对结果进行第二次查询与WHERE子句中其余块的表。由于初始块过滤掉了表中的很多行,我认为这可能会有所帮助。

有人可以提出改善此查询的好方法吗?此外,哪些工具最适合用于测试查询的效率?有时,即使是相同的输入,执行时间也会有很大差异。

4 个答案:

答案 0 :(得分:4)

有些观点:

  1. 首先:学习阅读执行计划!将最终查询粘贴到SSMS中,让SQL Server显示查询的执行计划。然后查看哪些部分占用的时间最多(通常为table scansclustered index scans)。这些是你应该仔细看看的地方。

  2. 优化您的查询,以便它可以使用索引。也就是说,摆脱查询中的LIKE '%value%'部分。如果可能,请强制用户仅进行begins withexact匹配搜索。当您的表开始有大约10k行时,contains语法开始出现性能问题。

  3. 删除最后NOT EXISTS块,因为它非常昂贵。在结果显示上进行过滤。

  4. 在适当的位置向列添加索引。根据您的SQL Server版本,它甚至可能会为您提供有关缺失索引的一些提示。

  5. 如果您无法确定查询的瓶颈,请开始删除查询的部分内容,并观察效果对执行计划的影响。

答案 1 :(得分:2)

据我所知,查询存在一个普遍问题,其中包含很多WHERE条件。 SQLServer可能无法为您的查询找到良好的执行计划,因为可能需要太多列才能进行搜索。

同样带有'%'+ searchWord +'%'的LIKE可能会返回您需要的值,但会有效地推出Indexusage,因为开头'%'表示必须搜索所有内容。也许你可以收集最常用的shearch场景并对其进行优化(收集统计数据,查看执行计划,为这些创建索引等)。让一个查询完成所有事情总是难以优化。

也许你可以在列上放置一个ClusteredIndex来限制结果(例如Date或者什么),以避免使用tablecans。

答案 2 :(得分:1)

您需要了解编写查询的方式会影响天气,否则可以使用索引。通过阅读,学习和使用这些技术:Dynamic Search Conditions in T-SQL by Erland Sommarskog您将有更好的机会获得索引(从而加快查询速度)。

如果您正在运行SQ:Server 2008的最新版本,这是快速回答(这是上一个链接中描述的技术): How can I use optional parameters in a T-SQL stored procedure?

答案 3 :(得分:0)

当我遇到一个不可避免的慢查询问题时,我会将查询分为两个阶段。

第一阶段将记录ID列表检索到@table变量中,仅应用那些我知道已编入索引且速度快的WHERE子句。

第二阶段将@table与完整的多部分多连接查询相连接,然后我可以应用较慢的过滤器,例如LIKE子句和UDF调用。第二阶段很快,因为它仅对较小的记录集应用慢速过滤器。