简体   繁体   English

避免在返回搜索结果的存储过程中进行分支?

[英]Avoiding branching in stored procedures that return search results?

I have an application that needs to return search results from a SQL Server 2008 database. 我有一个需要从SQL Server 2008数据库返回搜索结果的应用程序。 I would like to use a single stored procedure to return the results but I am finding that as I build the stored procedure it is full of many Else .. Else If statements with the query repeated over and over with slight variations depending on the users search criteria. 我想使用一个存储过程来返回结果,但是我发现在构建存储过程时,它充满了许多其他..其他If语句随着查询的重复而不断重复,具体取决于用户搜索标准。

Is there a better way to go about this? 有没有更好的方法来解决这个问题? I am trying to avoid writing dynamic SQL because I would like the benefits of an execution plan but I am thinking there must be a better way. 我试图避免编写动态SQL,因为我想享受执行计划的好处,但我认为必须有更好的方法。 Does anyone have any suggestions or perhaps examples of how best to design a stored procedure that has to deal with many search parameters, many of which may be NULL? 是否有人对如何最好地设计必须处理许多搜索参数(其中许多可能为NULL)的存储过程有任何建议或示例? Thank you. 谢谢。

Not really. 并不是的。

With SQL Server 2005 and above with statement level recompilation then there is less of a penalty with OR clauses, just maintenance complexity. 使用带有语句级重新编译的SQL Server 2005及更高版本,使用OR子句的代价就更少了,只是维护的复杂性。

Using Richard Harrison's approach makes it worse because OR is not-sargable, runs slowly, most likely won't use indexes. 使用Richard Harrison的方法会使情况变得更糟,因为OR是不可持久的,运行缓慢,很可能不会使用索引。

Dynamic SQL opens up SQL injection, quoting and caching issues. 动态SQL打开了SQL注入,引用和缓存问题。

This leaves sp_executesql as per CountZero's answer which still requires building up strings. 根据CountZero的答案,这仍然需要sp_executesql,但这仍然需要构建字符串。

The solution may not be code based... do you really need to search on all fields at any one time? 解决方案可能不是基于代码的...您真的需要一次在所有字段上进行搜索吗? I'd try to split into simple and advanced searches, or work out what the most common are and try to cover these queries. 我将尝试分为简单和高级搜索,或者找出最常见的搜索并尝试涵盖这些查询。

I've always done this by using default values and conditions; 我一直通过使用默认值和条件来完成此操作。 eg 例如

CREATE PROCEDURE [dbo].[searchForElement]
(
    @Town     nvarchar(100) = '',
    @County   nvarchar(100) = '',
    @postcode nvarchar(100) = ''
)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT <fields> 

    FROM table 
    WHERE 
        (@Town = ''             OR Town     LIKE '%'+@Town+'%')
        AND (@County = ''       OR County   LIKE '%'+@County+'%')
        AND (@postcode = ''     OR postcode LIKE '%'+@PostCode +'%')
END

Edit: 编辑:

As @gbn correctly advises the above will result in an index scan which may be a problem for large tables. 正如@gbn正确建议的那样,以上内容将导致索引扫描,这对于大型表可能是个问题。 If this is a problem the solution is to below using ISNULL and the fact that adding NULL to anything results in NULL it will allow an index seek because the '%' is understood by the optimiser (tested on SQL2008). 如果这是一个问题,则下面的解决方案是使用ISNULL,并且将NULL添加到任何内容都会导致NULL的事实,这将允许索引查找,因为优化器可以理解“%”(已在SQL2008上进行了测试)。 This may be less readable but it makes better use of the indexes. 这可能不太可读,但可以更好地利用索引。

CREATE PROCEDURE [dbo].[searchForElement]
(
    @Town     nvarchar(100) = NULL,
    @County   nvarchar(100) = NULL,
    @postcode nvarchar(100) = NULL
)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT <fields> 

    FROM table 
    WHERE   Town     LIKE ISNULL('%'+@Town+'%', '%')
       AND  County   LIKE ISNULL('%'+@County+'%', '%')
       AND  Postcode LIKE ISNULL('%'+@PostCode +'%', '%')
END

I always run into this problem myself. 我自己总是遇到这个问题。 Tend to use dynamic SQL, as long as you use the sp_executesql then the optimizer will try to use the same execution plan. 倾向于使用动态SQL,只要您使用sp_executesql,优化器就会尝试使用相同的执行计划。

http://ayyanar.blogspot.com/2007/11/performance-difference-between-exec-and.html http://ayyanar.blogspot.com/2007/11/performance-difference-between-exec-and.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM