我想检查是否有一个首选的设计模式,用于实现具有针对数据库表的多个可选参数的搜索功能,其中只能通过存储过程访问数据库。
目标平台是带有SQL 2005,2008后端的.Net,但我认为这是非常普遍的问题。
例如,我们有客户表,我们希望为UI提供不同参数的搜索功能,如客户类型,客户状态,客户邮编等,所有这些都是可选的,可以任意组合选择。换句话说,用户可以仅按customerType或按customerType,customerZIp或任何其他可能的组合进行搜索。 有几种可用的设计方法,但它们都有一些缺点,我想问一下它们中是否有一个首选设计,或者是否有另一种方法。
根据来自UI的搜索请求,在业务层中动态生成sql where子句sql语句,并将其作为参数传递给存储过程。像@Where =',其中CustomerZip = 111111' 在存储过程内部生成动态sql语句并使用sp_executesql执行它。 缺点:动态sql,sql注入
使用多个输入参数实现存储过程,表示来自UI的搜索字段,并使用以下构造仅为where语句中的请求字段选择记录。
在哪里
(CustomerType = @CustomerType OR @CustomerType is null )
AND (CustomerZip = @CustomerZip OR @CustomerZip is null )
AND …………………………………………
缺点:sql可能存在性能问题。
3.为每个搜索参数组合实现单独的存储过程。 缺点:随着搜索参数的增加,重复的代码,存储过程的数量将迅速增加。
答案 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>