什么时候编写“ad hoc sql”与存储过程更好[重复]

2023-12-31

我的应用程序中有 100% 的即席 SQL。我的一个朋友建议我转换为存储过程以获得额外的性能和安全性。这在我脑海中提出了一个问题,除了速度和安全性之外,还有其他理由坚持使用即席 SQL 查询吗?


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使用存储过程执行此操作(没有EXEChack 这在礼貌社会中是不应该谈论的),所以这一点毫无意义。

更新3:这是唯一真正好的与表现相关使用存储过程的原因(无论如何,我能想到)。如果您的查询是一个长时间运行的查询,其中编译执行计划的过程花费的时间比实际执行的时间明显长,并且该查询仅很少被调用(例如月度报告),那么将其放入存储过程中可能会使 SQL Server 将已编译的计划在缓存中保留足够长的时间,以便下个月仍然有效。不过,不管这是否属实,我都难受。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么时候编写“ad hoc sql”与存储过程更好[重复] 的相关文章

随机推荐

  • Javascript 与 Django?

    我知道以前有人问过这个问题 但我很难在 Django Web 应用程序上设置 JS 即使我正在阅读文档 我正在运行 Django 开发服务器 我的文件结构如下所示 mysite init py MySiteDB manage py sett
  • 让用户在扫描仪Java中仅输入整数

    我这里有一些问题 我希望用户只能输入整数 我已经尝试了很多代码 但仍然不起作用 顺便说一句 这是我的代码 import java util Scanner public class test public static void main
  • Function.const 的目的是什么?

    它是在ScalaDoc http www scala lang org archives downloads distrib files nightly docs library index html scala Function 24但没
  • 向 PageDown markdown 编辑器添加新按钮

    如何向位于以下位置的 PageDown markdown 编辑器添加新按钮http code google com p pagedown http code google com p pagedown 理想情况下 该按钮将创建一个类似于用于
  • 如何在NSIS中调用PowerShell

    我正在尝试在 NSIS 中运行 PowerShell 当我运行 NSIS 脚本时 include x64 nsh Name nsExec Test OutFile nsExecTest exe ShowInstDetails show Se
  • Android 列表视图过滤与重新填充

    经过一些建议后 我的应用程序使用媒体存储光标在加载时填充列表视图 这会将音乐链接到用户定义的文件夹 在大多数情况下 该文件夹将是他们存储的所有音乐 我有一个 Beta 测试人员 正在使用一台装有大约 10000 首歌曲的 Archos 平板
  • Pandas 根据索引名称突出显示行

    我一直在努力研究如何根据索引名称突出显示 Pandas 行的样式 我知道如何突出显示选定的行 但是当我必须根据索引突出显示时 代码不起作用 Setup df pd DataFrame key list ABCD value range 4
  • 熊猫断言_帧_等于错误

    我正在构建测试用例 我想比较 2 个数据帧 即使数据帧具有相同的列和值 assert frame equal 报告也不相等 列顺序不同 我尝试对列重新排序但没有成功 在我的测试用例中 我使用以下函数 testing assert frame
  • 适配器-适配器模式的任何真实示例[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想演示使用适配器模式 https en wikipedia org wiki Adapter pat
  • Spark中字符串类型的汇总统计

    Spark 中是否有像 R 中那样的汇总函数 Spark MultivariateStatisticalSummary 附带的汇总计算仅适用于数字类型 我有兴趣获取字符串类型的结果 例如前四个最大出现的字符串 groupby 类型的操作 唯
  • 可以在 Typescript 中向 Promise 添加取消方法吗?

    我想创建一个 QueryPromise 它只是一个带有取消方法的具体承诺 下面是它的使用方法 function runQuery text string QueryPromise return new QueryPromise resolv
  • Spring OAUTH:覆盖 CheckTokenEndpoint 'check_token?token=' 响应映射

    我想重写 CheckTokenEndpoint 以将我自己的自定义输出作为 Map 提供给资源服务器 我已尝试以下操作 但不起作用 为 oauth check token 引入新的自定义控制器 但 Spring 拒绝此自定义并注册自己的控制
  • 将 PagedList 与 ViewModel ASP.Net MVC 结合使用

    我正在尝试在 ASP Net 应用程序中使用 PagedList 我在 Microsoft 网站上找到了这个示例http www asp net mvc tutorials getting started with ef using mvc
  • 我的日志消息不会通过 proguard 配置被删除

    我正在开发我的 Android 应用程序 然后我通过以下方式启用并配置混淆器 步骤1 启用proguard In 项目 属性 I have proguard config sdk dir tools proguard proguard an
  • 使用 R,将可变行数的文本合并到单个文本元素中

    什么样的 R 代码可以将下面的模拟数据框中每个人的叙述条目合并到一个变量中 数据来自 Excel 电子表格 其中记录的叙述条目可以有 1 到 8 行 每个计时员的记录都以空行结束 假设这个数据框 dput 如下 gt df timekeep
  • 提前终止工作人员 puma 日志意味着什么?为什么会发生这种情况?

    对于我的 Elastic Beanstalk 实例 我得到了504每当我访问它时状态代码响应 当我跟踪日志时 我在 puma 应用服务器上看到以下日志 gt var log puma puma log lt 27240 Early term
  • 在 PL/SQL 中将 varchar2 转换为日期 ('MM/DD/YYYY')

    我需要将字符串从 varchar 转换为 MM DD YYYY 格式的日期 我的输入字符串是 4 9 2013 我的预期输出是 04 09 2013 即 2 位月份 2 位日期和 4 位年份 以 分隔 我有以下数据 DOJ varchar2
  • 为什么提供静态文件不安全

    这可能是一个愚蠢的问题 并且有一个明显的答案 但我正在测试 404 和 500 错误处理程序 这意味着我必须将 debug 切换为 False 我进入 Django 管理页面 注意到没有提供静态文件 我知道它们应该通过 Apache 路由
  • iOS 7.1 滑动解锁文字动画

    我不确定以前是否有人问过这个问题 但我很难找到它 也许我没有使用正确的搜索词 所以如果答案已经存在 如果有人能指出我正确的方向 我将不胜感激 我刚刚注意到 随着 iOS 7 1 的更新 锁屏 滑动解锁 文本上的闪烁动画发生了变化 聚光灯现在
  • 什么时候编写“ad hoc sql”与存储过程更好[重复]

    这个问题在这里已经有答案了 我的应用程序中有 100 的即席 SQL 我的一个朋友建议我转换为存储过程以获得额外的性能和安全性 这在我脑海中提出了一个问题 除了速度和安全性之外 还有其他理由坚持使用即席 SQL 查询吗 SQL Server