【问题标题】:Drawbacks of Dynamic Query in Sqlserver 2005?Sql Server 2005 中动态查询的缺点?
【发布时间】:2010-05-11 07:17:27
【问题描述】:

我在我的数据库中为程序使用了许多动态查询,因为我的过滤器没有修复,所以我将@filter 作为参数并传入程序。

Declare @query as varchar(8000)
Declare @Filter as varchar(1000)

set @query = 'Select * from Person.Address where 1=1 and ' + @Filter

exec(@query)

就像我的过滤器包含表中的任何字段以进行比较。

会不会影响我的表现? 有没有其他方法可以实现这种类型的事情

【问题讨论】:

  • 我们的项目中有复杂的查询,在“WHERE”子句中需要很多参数。我们的 dba 倾向于对此类情况进行动态查询,但我对此感觉不对。恕我直言,只要对参数嗅探采取必要措施,静态查询应该更快。有没有人对 KuldipMCA 的问题有好的答案,所以我可以让我们的高级 DBA 停止支持动态查询?

标签: sql tsql stored-procedures query-optimization


【解决方案1】:

就性能而言,问题只是数据库是否可以重用现有计划。

简单来说可以看成是数据库缓存了以sql语句为key的查询计划。一旦你更改了 sql 语句,它就不会在缓存中,必须生成一个新的计划。

所以生成像这样的动态语句

"SELECT * FROM table WHERE param = @paramvalue"

更有机会进入缓存
"SELECT * FROM table WHERE param = '" + variable + "'"

您还应该将模式名称添加到查询中的表名(例如 dbo.table)。否则,如果不同的登录名执行,计划将不会被重用。

【讨论】:

  • +1,需要注意的是,SQL Server 会尝试将后一种类型的查询转换为内部参数化查询以用于执行计划缓存
【解决方案2】:

只要不需要动态地进行其他连接来检查可能重要的参数的值,并且唯一的动态部分是 WHERE 子句,这也可以是具有所有可能参数的静态查询。所以你有以下场景:

如果您想检查可以是所有内容的值(负/空/零/正/空字符串/等),则需要使用辅助参数,例如 @signifficant_param1,以及 @ 的原始值参数1。

[...]
WHERE 
    (@signifficant_param1=0 or (@param1 is null and field1 is null) or @param1=field1) 
    AND (@signifficant_param2=0 or (@param2 is null and field2 is null) or @param2=field2)
    //etc
[...]

这是我能想象到的最普遍的条款。 基本上它将验证@signifficant_param 值。如果要考虑这个参数,它将为 1,条件的第一部分为假,第二部分(参数的验证)将发生。在第二阶段,如果@param 为null,那么您正在寻找field 的所有null 值,并且您不能将null 与null 进行比较,因为它们不相等。然后进行常规非空值匹配的验证。

另一方面,如果field 中的值不能为空,或者不能为负数,则不需要@signifficant_param,因为您可以制定规则,例如,如果@param 为空,则该值不重要(在前一种情况下,您必须搜索所有空值),您可以使用以下内容:

[...]
WHERE
    field1=case when @param1 is null then field1 else @param1 end --first way with case statement
    and (@param2 is null or field2=@param2) --second way with boolean logic
[...]

【讨论】:

  • 你必须非常小心这个结构。是的,这是一个几乎通用的 WHERE 子句,但它不是,正如他们所说,SARGable。也就是说,它不能有效地使用您的索引来处理您的 WHERE 条件。这对于过滤小的数据子集很好,但是对于一个大表的搜索,这将导致数据库优化器进行扫描。
  • 很好的答案和很好的评论,但我同意戴夫马克尔的观点,认为这不是解决这个问题的有效方法。
  • 是的,部分正确,但在从 MSSQL 内部构建动态查询时,您不能存储超过 8000 个字符的查询。根据我的经验,这部分是正确的,因为我在大型表(数亿条记录)上使用了这样的算法,但性能非常糟糕,因为该表没有在所需的字段上建立索引。一旦在另一台服务器上设置了复制,我就可以运行数据库引擎优化顾问,它提出了复杂的索引和统计信息,之后性能提高了大约 10 个系数。我说尝试没有伤害。
【解决方案3】:

动态查询本身并没有什么问题。但是你打算这样做的方式是可怕的。这有点暗示您的参数将成为@Filter 的一部分,这只是要求进行 SQL 注入攻击。这也意味着您的查询计划不太可能被重用,这可能会由于过多的查询重新编译而导致高 CPU 和低吞吐量。

您需要确保您生成的动态 SQL 已正确参数化。您还需要确保当您使用 ADO.NET 代码(或您可能使用的任何数据访问技术)访问它时,您使用的是 SqlParameter(或等效)对象。

【讨论】:

    猜你喜欢
    • 2011-04-01
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多