实施过滤搜索的最佳方法


17

我想问您,关于实施过滤后的搜索表单的意见。让我们想象以下情况:

  • 1个有很多列的大表
  • 可能很重要的一点是,此SQL Server

您需要实现一个表单来搜索此表中的数据,并且在此表单中,您将具有几个复选框,可用于汇总此搜索。

现在,我的问题是,以下哪一项应该是实现搜索的最佳方法?

  1. 创建一个内部带有查询的存储过程。此存储过程将检查应用程序是否提供了参数,如果未提供参数,则将在查询中放入通配符。

  2. 创建一个动态查询,该查询将根据应用程序给出的内容进行构建。

我之所以这样问,是因为我知道SQL Server在创建存储过程时会创建执行计划,以优化其性能,但是通过在存储过程内部创建动态查询,我们会牺牲执行计划获得的优化吗?

请告诉我,您认为最好的方法是什么。


您在下面声明,您倾向于动态解决方案。太酷了,只要确保您枚举可能的过滤器并有支持它们的索引即可。只要构建一致的查询,它们就应该是有效的。
马修·弗林

Answers:


10

您可能想在这里查看类似问题的答案:https : //stackoverflow.com/questions/11329823/add-where-clauses-to-sql-dynamically-programmatically

我们发现,一个SPROC接受了许多可选参数,并实现了以下过滤器:

CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS 
...
SELECT field1, field2, ... FROM [Table]
WHERE 
  (@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
  AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)

会缓存运行它的第一个执行计划(例如@optionalParam1 = 'Hello World', @optionalParam2 = NULL),但是如果我们将不同的一组可选参数(例如@optionalParam1 = NULL, @optionalParam2 = 42)传递给它,则会执行得很惨。(很显然,我们需要缓存计划的性能,因此WITH RECOMPILE已淘汰)

这里的例外是,如果在查询上还至少有一个MANDATORY过滤器,除了可选参数之外,该过滤器具有高度选择性和正确索引,那么上面的PROC会很好地执行。

但是,如果所有过滤器都是可选的,那么可怕的事实是,参数化的动态sql实际上会更好(除非您为可选参数的每个排列编写N!个不同的静态PROCS)。

如下所示的动态SQL将为Query参数的每个排列创建并缓存一个不同的计划,但是至少每个计划都将“定制”到特定的查询(无论是PROC还是Adhoc SQL-只要它们是参数化查询,它们就会被缓存)

因此,我更喜欢:

DECLARE @SQL NVARCHAR(MAX)        

-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'

IF @OptionalParam1 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'    
    END        

IF @OptionalParam2 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'    
    END        

EXEC sp_executesql @SQL,        
    N'@optionalParam1 NVARCHAR(50), 
      @optionalParam2 INT'
    ,@optionalParam1 = @optionalParam1
    ,@optionalParam2 = @optionalParam2

等等。是否将冗余参数传递给sp_executesql没关系-它们将被忽略。值得注意的是,像Linq2SQL和EF这样的ORM以类似的方式使用参数化的动态sql。


1
是的,我是这么认为的,这是我选择的选项。只是想确保它是一个好的。感谢您的答复。
2012年

“如果执行不带参数的SQL语句,SQL Server将在内部对语句进行参数化,以增加将其与现有执行计划进行匹配的可能性。此过程称为简单参数化。” 因此,基本上程序可以使用“ where filenumber =“ + filename”之类的东西。当然,这会打开一罐蠕虫,但这是一个不同的话题;-)
Codism 2012年

5

从您认为更容易实现的东西开始(我猜选项2)。然后测量真实数据的性能。仅在需要时才开始优化,而不是事先进行优化。

顺便说一下,根据您的搜索过滤器的复杂程度,如果没有动态SQL,您的任务可能很难解决。因此,即使您使用存储过程,也可能不会像您已经怀疑的那样提高性能。另一方面,如果有帮助,则可以将几种类型的提示添加到SQL中(请参阅http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/)。动态查询与否,以帮助SQL Server优化其执行计划。


好吧,我已经实现了选项2,我认为这是最好的方法,主要是因为通配符会大大降低性能,但是我却牺牲了维护,因为这会增加代码的复杂性。我只是想知道是否有人对这种情况有更好的选择。
2012年

我想给你增加一票,但对不起我没有声誉。
2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.