Luk*_*101 37 c# sql sql-server-2008
我的应用程序中有100%的临时sql.我的朋友建议我转换为存储过程以获得额外的性能和安全性.这提出了一个问题,除了速度和安全性之外还有其他任何理由坚持使用ad hoc sql查询吗?
Mus*_*sis 71
SQL Server缓存临时查询的执行计划,因此(折扣第一次调用所花费的时间)这两种方法在速度方面是相同的.
通常,使用存储过程意味着获取应用程序所需的部分代码(T-SQL查询)并将其放在不受源代码控制的位置(它可以,但通常不是)和在你不知情的情况下被别人改变的地方.
将查询放在这样的中心位置可能是件好事,这取决于有多少不同的应用程序需要访问它们所代表的数据.我通常发现保持应用程序使用的查询驻留在应用程序代码本身更容易.
在20世纪90年代中期,传统观点认为SQL Server中的存储过程是在性能关键的情况下发展的方式,当时它们肯定是.然而,这个CW背后的原因已经很长时间没有了.
更新: 此外,经常在讨论存储过程的可行性时,需要防止SQL注入以保护过程.当然,没有一个心智正常的人认为通过字符串连接组装即席查询是正确的事情(尽管如果你连接用户输入,这只会让你接受SQL注入攻击).显然,临时查询应该被参数化,不仅是为了防止sql注入攻击下的怪物,而且只是为了让你作为程序员的生活变得更加容易(除非你喜欢弄清楚何时使用单个引用你的价值观).
更新2: 我做了更多的研究.根据这篇MSDN白皮书,答案似乎取决于您对查询的"ad-hoc"的含义.例如,一个简单的查询,如下所示:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
Run Code Online (Sandbox Code Playgroud)
... 将缓存其执行计划.此外,因为查询不包含某些不合格元素(几乎除了一个表中的简单SELECT之外的其他任何元素),SQL Server实际上将"自动参数化"查询并用参数替换文字常量"5",并缓存参数化版本的执行计划.这意味着如果您随后执行此即席查询:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23
Run Code Online (Sandbox Code Playgroud)
...它将能够使用缓存的执行计划.
不幸的是,不合格查询元素的自动参数的名单很长(例如,忘记使用DISTINCT,TOP,UNION,GROUP BY,OR等),所以你真的不能表现这个数.
如果您确实有一个不会自动参数化的"超级复杂"查询,例如:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23
Run Code Online (Sandbox Code Playgroud)
...它仍然会被查询的确切文本缓存,因此如果您的应用程序重复使用相同的文字"硬编码"值调用此查询,则第一个查询之后的每个查询将重新使用缓存的执行计划(和因此,与存储过程一样快.
如果文字值发生变化(例如,基于用户操作,如过滤或排序已查看的数据),则查询将无法从缓存中受益(除非偶尔意外地与最近的查询完全匹配).
通过"ad-hoc"查询进行缓存的方法是参数化它们.在C#中动态创建查询,如下所示:
int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " +
itemCount.ToString();
Run Code Online (Sandbox Code Playgroud)
是不正确的.正确的方法(使用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();
}
Run Code Online (Sandbox Code Playgroud)
查询不包含文字,并且已经完全参数化,因此使用相同参数化语句的后续查询将使用缓存计划(即使使用不同的参数值调用).请注意,这里的代码实际上与用于调用存储过程的代码相同(唯一的区别是CommandType和CommandText),因此它有点归结为您希望该查询的文本"活"的位置"(在您的应用程序代码或存储过程中).
最后,如果通过"ad-hoc"查询,你的意思是你动态构建具有不同列,表,过滤参数等等的查询,就像这些:
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
Run Code Online (Sandbox Code Playgroud)
...那么你几乎不能用存储过程做到这一点(没有EXEC礼貌社会中没有提到的hack),所以重点是没有实际意义.
更新3: 这是使用存储过程的唯一非常好的与性能相关的原因(无论如何我都能想到).如果您的查询是一个长期运行的查询,其中编译执行计划的过程比实际执行花费的时间要长得多,并且查询只是不经常调用(例如,像月度报告),那么将它放在存储过程中可能使SQL Server将已编译的计划保留在缓存中足够长的时间,使其仍然在下个月左右.但是,如果这是真的与否,请打败我.
Bil*_*win 19
没有任何关于存储过程使它们神奇地更快或更安全.有些情况下,精心设计的存储过程可以更快地执行某些类型的任务,但对于临时SQL也是如此.
按照您发现最有效率的方式编码.
"在你加快速度之前做好准备." - Brian Kernighan
有一些与此主题相关的神话你应该自己解除:
误区1:存储过程是预先编译的
http://scarydba.wordpress.com/2009/09/30/pre-compiled-stored-procedures-fact-or-myth/
误解2:Ad Hoc SQL查询不重用执行计划: http ://scarydba.wordpress.com/2009/10/05/ad-hoc-queries-dont-reuse-execution-plans-myth-or-fact/
当你绝对需要锁定数据库时,恕我直言的过程有优势.在这些情况下,您可以使用仅具有执行存储过程权限的帐户.此外,它们可以从DBA角度在您的应用程序和数据库之间提供一个抽象层.
同样,动态SQL在查询可能需要更改某些内容并且......好......动态的情况下更好.或者,如果您知道必须移植到多个数据库.
只要所有用户输入的值都参数化,两者在SQL注入方面都是安全的.
已经有很多关于该线程的性能,缓存和安全性的文章,我不再赘述。在此线程中,我还没有读过几件事,即可移植性问题和绕行旅行。
关于往返:
| 归档时间: |
|
| 查看次数: |
15345 次 |
| 最近记录: |