最佳搜索查询

时间:2010-05-07 12:10:26

标签: sql-server tsql

继我的上一个问题Sql Server query performance之后,发现我在搜索查询中允许可选参数的方法是次优的,是否有人有关于如何处理此问题的指南?

例如,假设我有一个应用程序表,一个客户表和一个联系人详细信息表,我想创建一个允许搜索姓氏,家庭电话,移动电话和应用程序ID的部分,全部或全部的SP,我可以使用类似下面的内容:

select *
from application a inner join customer c on a.customerid = a.id
    left join contact hp on (c.id = hp.customerid and hp.contacttype = 'homephone')
    left join contact mob on (c.id = mob.customerid and mob.contacttype = 'mobile')
where (a.ID = @ID or @ID is null)
    and (c.Surname = @Surname or @Surname is null)
    and (HP.phonenumber = @Homphone or @Homephone is null)
    and (MOB.phonenumber = @Mobile or @Mobile is null)

上面使用的模式不是真实的,我不会在真实场景中使用select *,它是我感兴趣的where子句的构造。是否有更好的方法,无论是动态sql还是一种可以实现相同结果的替代方案,而不需要许多嵌套条件。一些SP可能以这种方式使用10-15个标准

3 个答案:

答案 0 :(得分:3)

对此没有“一刀切”的查询方法,在执行此操作时会产生微妙的性能影响。如果您希望不仅仅是让查询返回正确的答案,无论它有多慢,请查看以下文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog。它涵盖了每种方法,并详细介绍了每种方法的PRO和Cons。

如果您可以确定搜索列的最小和最大可能范围,并且搜索列为NOT NULL,那么您可以做得比(@Search IS NULL或Col = @ Search)更好,{{3} }。但是你应该阅读整篇文章,有很多变化取决于你的情况,你真的需要学习多种方法以及何时使用它们。

另见最近的其他答案:see this area of the above linked article

答案 1 :(得分:1)

好的,我们走了

选项(重建)

是必须的 - 否则第一个查询计划将被重用,无论参数如何匹配。对不起,没有比这更好的方法了。

除此之外 - 不,抱歉。动态SQL可以更高效(通过避免使用IS NULL替代方案),但如果不可能,您基本上可以将其命名为。

使用动态SQL,如果HomePhone变量为null,则基本上没有HP.phonenumber的aline;)

答案 2 :(得分:1)

在您的情况下,不同的查询将使用不同的索引。

您应该定义一组要使用的索引,并为每个集合编写单独的查询,并使用OR替换索引字段上的UNION ALL

SELECT  *
FROM    tables
WHERE   A = @ID
        AND (c.Surname = @Surname or @Surname IS NULL)
        AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
        AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)
UNION ALL
SELECT  *
FROM    tables
WHERE   @ID IS NULL
        AND c.Surname = @Surname
        AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
        AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)
UNION ALL
SELECT  *
FROM    tables
WHERE   @ID IS NULL
        AND @Surname IS NULL
        AND (HP.phonenumber = @Homphone or @Homephone IS NULL)
        AND (MOB.phonenumber = @Mobile or @Mobile IS NULL)