使用针对数据库表的多个可选参数实现搜索功能

时间:2010-05-06 12:56:47

标签: .net sql design-patterns ado.net

我想检查是否有一个首选的设计模式,用于实现具有针对数据库表的多个可选参数的搜索功能,其中只能通过存储过程访问数据库。

目标平台是带有SQL 2005,2008后端的.Net,但我认为这是非常普遍的问题。

例如,我们有客户表,我们希望为UI提供不同参数的搜索功能,如客户类型,客户状态,客户邮编等,所有这些都是可选的,可以任意组合选择。换句话说,用户可以仅按customerType或按customerType,customerZIp或任何其他可能的组合进行搜索。 有几种可用的设计方法,但它们都有一些缺点,我想问一下它们中是否有一个首选设计,或者是否有另一种方法。

  1. 根据来自UI的搜索请求,在业务层中动态生成sql where子句sql语句,并将其作为参数传递给存储过程。像@Where =',其中CustomerZip = 111111' 在存储过程内部生成动态sql语句并使用sp_executesql执行它。 缺点:动态sql,sql注入

  2. 使用多个输入参数实现存储过程,表示来自UI的搜索字段,并使用以下构造仅为where语句中的请求字段选择记录。

  3. 在哪里

            (CustomerType = @CustomerType OR @CustomerType is null )
    
    AND      (CustomerZip = @CustomerZip OR @CustomerZip is null )
    
    AND   …………………………………………
    

    缺点:sql可能存在性能问题。

    3.为每个搜索参数组合实现单独的存储过程。 缺点:随着搜索参数的增加,重复的代码,存储过程的数量将迅速增加。

4 个答案:

答案 0 :(得分:4)

这是描述如何在SQL中执行此操作的微妙性能影响的最佳文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog。它涵盖了每种方法,并详细介绍了每种方法的PRO和Cons。

答案 1 :(得分:2)

Query Object模式。

答案 2 :(得分:2)

方法1:动态SQL可以接受参数,它非常简单,并且几乎消除了SQL注入的风险。反对动态SQL的最好的论据是非平凡的语句如何需要一些复杂的逻辑来生成,尽管如果你使用一个像样的ORM,这也是一个非问题。

NHiberante和LinqToSql在幕后构建动态SQL,并且它们没有安全漏洞。在我看来,在推出自己的DAL之前,你最好考虑这两种技术中的一种。

方法2:我个人过去曾亲自使用过方法二,没有任何问题。您评论了“sql可能存在的性能问题”,但您有没有进行过分析?比较执行计划?根据我自己的经验,他们使用@param is null OR col = @param方法几乎没有表现。请记住,如果需要10个小时的开发人员时间来优化代码以节省每年10微秒的执行时间,那么您的净节省时间仍然是近-10小时。

方法3:组合爆炸。不惜一切代价避免。

答案 3 :(得分:2)

我发布此评论作为评论,但我意识到这应该是一个答案。

将谓词编写为WHERE @Param IS NULL OR Column = @Param并不好,因为优化器通常认为它是不可搜索的。

尝试此实验:获取人口最多的表格,然后尝试查询主键字段,该字段应该是您的聚集索引:

DECLARE @PrimaryKey int
SET @PrimaryKey = 1

SELECT CoveredColumn
FROM Table
WHERE @PrimaryKey IS NULL
OR PrimaryKeyColumn = @PrimaryKey

SELECT CoveredColumn
FROM Table
WHERE PrimaryKeyColumn >= ISNULL(@PrimaryKey, 0)
AND PrimaryKeyColumn <= ISNULL(@PrimaryKey, 2147483647)

假设PK列是非负SELECT,这两个int语句都会产生相同的结果。但是为此拉出执行计划,你会发现巨大的成本差异。第一个SELECT执行完整索引扫描,通常占查询成本的约90%。

如果您希望在SQL中具有可选搜索条件,并且无法使用动态SQL,那么如果您可以使用ISNULL将其转换为范围查询,则最佳性能。即使范围巨大(这里只是int的一半范围),优化程序仍会在使用可选参数 时弄明白。 / p>