【发布时间】:2011-01-21 11:29:06
【问题描述】:
我正在构建一个复杂的查询以在 Web 视图中显示一些统计结果。根据用户的选择,视图可以有几个不同的过滤器。此外,还可以使用通配符。
我正在使用 SqlParameters 在 c# 中以编程方式构建此查询。所以查询看起来像这样:
sc.CommandText = "SELECT * FROM table
WHERE field1 = @filter1
AND field2 LIKE @filter2"; //...and more parameters
sc.SqlParameters.Add(
new SqlParameter("@filter1", SqlDbType.Int, 32) { Value = 1});
sc.SqlParameters.Add(
new SqlParameter("@filter2", SqlDbType.VarChar, 446) { Value = "whatever%"});
这是一个非常简化的版本,但查询本身并不是重点。请记住,它可以有不同的可选参数(我认为这是很常见的情况)。
当我在 Sql Manager 中运行此查询时,我意识到使用参数时速度非常慢。因此,以下两个查询应该是相同的,它们使用不同的执行计划,使参数化的查询运行慢很多:
DECLARE @filter1 INT
DECLARE @filter2 VARCHAR 446
SET @filter1 = 1
SET @filter2 = "whatever%"
SELECT * FROM table WHERE field1 = @filter1 AND field2 LIKE @filter2
快速版:
SELECT * FROM table WHERE field1 = 1 AND field2 LIKE 'whatever%'
这是另一个有同样问题的人的例子:
Why does a parameterized query produces vastly slower query plan vs non-parameterized query
似乎有一个名为parameter sniffing 的东西可能会使参数化查询运行得更慢,但它不适用于我的情况,因为这不是存储过程。
solutions 建议之一是使用 OPTION(RECOMPILE) 或 OPTION(OPTIMIZE FOR)。我不能这样做,因为我有大约 10 个可选参数,它们可能在过滤器中或不在过滤器中,并且在使用 LIKE 时此选项不起作用。
所以,我觉得我陷入了死胡同,我正在考虑摆脱参数并在代码上构建动态文字查询。但随后 Sql Injection 出现在游戏中。
那么,您对如何解决此问题还有其他建议吗?或者您知道转义参数的安全方法吗?
编辑:在这里,您可以使用LIKE查看带有一个参数的查询的执行计划:
编辑:更简化的代表性查询执行计划:
【问题讨论】:
-
参数嗅探不仅仅适用于存储过程。它适用于参数化执行计划被缓存并稍后被传递不同参数值的查询的其他调用重用的任何查询。当您使用文字值时,查询优化器可以对查询进行某些简化,这些简化对特定情况有效,但不适用于可能需要应用于任何参数值的计划(这与参数嗅探不同)你能提供一个示例执行计划来说明您遇到的确切问题?
-
@Martin 我已经添加了执行计划。
-
@despart - 第一个计划中进入哈希匹配的顶部箭头是哪个? (我可以在底部计划中看到它来自
like我只是想知道这是否在好计划中颠倒了) -
@Martin 在这两个计划中,顶部的箭头是 LIKE
-
这可以解释为什么你得到的是串行计划而不是并行计划。不过,我怀疑这可能解释 42 倍的性能差异。我想知道低估是否也意味着授予的内存不足并且您收到大量哈希警告? (你可以在 profiler 中看到)
标签: sql-server-2005 optimization c#-3.0 parameterized