SQL Server 缓存即席查询的执行计划,因此(扣除第一次调用所花费的时间)这两种方法在速度上是相同的。
一般来说,使用存储过程意味着获取应用程序所需的一部分代码(T-SQL 查询)并将其放在不受源代码控制的位置(它can是,但通常isn't)以及其他人可以在您不知情的情况下对其进行更改的地方。
将查询放在这样的中心位置may这是一件好事,具体取决于有多少不同的应用程序需要访问它们所代表的数据。我通常发现将应用程序使用的查询保留在应用程序代码本身中要容易得多。
在 20 世纪 90 年代中期,传统观点认为 SQL Server 中的存储过程是性能关键情况下的最佳选择,在当时确实如此。然而,这一 CW 背后的理由长期以来并不成立。
Update:此外,在关于存储过程的可行性的争论中,经常会提到防止 SQL 注入的必要性来保护过程。当然,头脑清醒的人不会认为通过字符串连接来组装即席查询是正确的做法(尽管如果您连接字符串,这只会让您遭受 SQL 注入攻击)用户输入)。显然,临时查询应该参数化,不仅是为了防止 sql 注入攻击的怪物,而且还只是为了让你作为程序员的生活变得更容易(除非你喜欢弄清楚何时使用单个查询)引用您的价值观)。
更新2:我做了更多研究。基于这份 MSDN 白皮书 http://msdn.microsoft.com/en-us/library/ee343986.aspx,看来答案取决于您的查询中“临时”的含义。例如,像这样的简单查询:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
... will缓存其执行计划。此外,由于查询不包含某些不合格的元素(就像除了来自一个表的简单 SELECT 之外的几乎任何内容),SQL Server 实际上会“自动参数化”查询并用参数替换文字常量“5”,并缓存参数化版本的执行计划。这意味着如果您随后执行this即席查询:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23
...它将能够使用缓存的执行计划。
不幸的是,自动参数化的不合格查询元素列表很长(例如,忘记使用DISTINCT
, TOP
, UNION
, GROUP BY
, OR
等),所以你真的不能指望它的性能。
如果您确实有一个不会自动参数化的“超级复杂”查询,例如:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23
...它仍然会被查询的确切文本缓存,因此,如果您的应用程序重复使用相同的文字“硬编码”值调用此查询,第一个查询之后的每个查询将重新使用缓存的执行计划(并且因此与存储过程一样快)。
如果文字值发生变化(基于用户操作,例如过滤或排序查看的数据),则查询将不会从缓存中受益(除非偶尔意外地与最近的查询完全匹配)。
从“临时”查询缓存中受益的方法是对它们进行参数化。在 C# 中动态创建一个查询,如下所示:
int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " +
itemCount.ToString();
是不正确的。正确的方法(使用 ADO.Net)是这样的:
using (SqlConnection conn = new SqlConnection(connStr))
{
SqlCommand com = new SqlCommand(conn);
com.CommandType = CommandType.Text;
com.CommandText =
"DELETE FROM tblSTUFF WHERE ITEM_COUNT > @ITEM_COUNT";
int itemCount = 5;
com.Parameters.AddWithValue("@ITEM_COUNT", itemCount);
com.Prepare();
com.ExecuteNonQuery();
}
该查询不包含文字并且已经完全参数化,因此使用相同参数化语句的后续查询将使用缓存的计划(即使使用不同的参数值调用)。请注意,这里的代码实际上与您用于调用存储过程的代码相同(唯一的区别是 CommandType 和 CommandText),因此它在某种程度上取决于您希望该查询的文本“实时”的位置“(在您的应用程序代码或存储过程中)。
最后,如果“临时”查询意味着您正在动态构建具有不同列、表、过滤参数等的查询,可能如下所示:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS
WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS
WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
ORDER BY LASTNAME DESC
...那你差不多了can't使用存储过程执行此操作(没有EXEC
hack 这在礼貌社会中是不应该谈论的),所以这一点毫无意义。
更新3:这是唯一真正好的与表现相关使用存储过程的原因(无论如何,我能想到)。如果您的查询是一个长时间运行的查询,其中编译执行计划的过程花费的时间比实际执行的时间明显长,并且该查询仅很少被调用(例如月度报告),那么将其放入存储过程中可能会使 SQL Server 将已编译的计划在缓存中保留足够长的时间,以便下个月仍然有效。不过,不管这是否属实,我都难受。