继我的上一个问题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个标准
答案 0 :(得分:3)
对此没有“一刀切”的查询方法,在执行此操作时会产生微妙的性能影响。如果您希望不仅仅是让查询返回正确的答案,无论它有多慢,请查看以下文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog。它涵盖了每种方法,并详细介绍了每种方法的PRO和Cons。
如果您可以确定搜索列的最小和最大可能范围,并且搜索列为NOT NULL,那么您可以做得比(@Search IS NULL或Col = @ Search)更好,{{3} }。但是你应该阅读整篇文章,有很多变化取决于你的情况,你真的需要学习多种方法以及何时使用它们。
答案 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)