一般来说,存储过程比现代 RDBMS 上的内联语句更有效吗? [复制]

2023-11-23

传统观点认为存储过程总是更快。所以,因为它们总是更快,所以使用它们每时每刻.

我很确定这是有历史背景的,这种情况曾经发生过。现在,我并不是主张不需要存储过程,而是我想知道在现代数据库(例如 MySQL、SQL Server、Oracle 或 在此处插入您的数据库>。通过存储过程获得所有访问权限是否太过分了?


NOTE这是对存储过程的一般看法,未针对特定情况进行监管 数据库管理系统。一些 DBMS(甚至不同的 相同 DBMS 的版本!)可以运行 与此相反,所以你会想要 仔细检查您的目标 DBMS 在假设所有这些仍然成立之前。

近十年来,我一直断断续续地担任 Sybase ASE、MySQL 和 SQL Server DBA(以及 C、PHP、PL/SQL、C#.NET 和 Ruby 中的应用程序开发)。所以,我在这场(有时)圣战中没有什么特别的目的。

存储过程的历史性能优势通常来自以下方面(排名不分先后):

  • 预解析 SQL
  • 预先生成的查询执行计划
  • 减少网络延迟
  • 潜在的缓存优势

预解析 SQL-- 与编译代码和解释代码类似的好处,除了非常微观的层面上。

还有优势吗?在现代 CPU 上根本不明显,但是如果您每秒发送一个非常大的 SQL 语句 1100 亿次,则解析开销可能会增加。

预先生成的查询执行计划。 如果您有许多 JOIN,则排列可能会变得非常难以管理(现代优化器出于性能原因有限制和截止)。众所周知,非常复杂的 SQL 具有明显的、可测量的(在我们调整 DBMS 之前,我见过一个复杂的查询需要 10 多秒才能生成一个计划)延迟,因为优化器试图找出“接近最佳” ”执行计划。通常,存储过程会将其存储在内存中,这样您就可以避免这种开销。

还有优势吗?大多数 DBMS(最新版本)都会缓存单个 SQL 语句的查询计划,从而大大减少存储过程和即席 SQL 之间的性能差异。在某些情况下,情况并非如此,因此您需要在目标 DBMS 上进行测试。

此外,越来越多的 DBMS 允许您提供优化器路径计划(抽象查询计划)以显着减少优化时间(对于即席 SQL 和存储过程 SQL!!)。

WARNING缓存查询计划并不是性能的灵丹妙药。有时,生成的查询计划不是最佳的。 例如,如果您发送SELECT * FROM table WHERE id BETWEEN 1 AND 99999999,DBMS可以选择一个 全表扫描而不是索引 扫描,因为你正在抓取每一行 在表中(如此说 统计数据)。如果这是缓存的 版本,那么你就会变穷 稍后发送时的性能SELECT * FROM table WHERE id BETWEEN 1 AND 2。这背后的原因是 超出了本文的范围,但是 如需进一步阅读,请参阅:http://www.microsoft.com/technet/prodtechnol/sql/2005/frcqupln.mspxhttp://msdn.microsoft.com/en-us/library/ms181055.aspx and http://www.simple-talk.com/sql/performance/execution-plan-basics/

“总而言之,他们确定 提供除 编译时的通用值或 执行重新编译导致 优化器编译和缓存 该特定的查询计划 价值。然而,当该查询计划是 重用于后续执行 对公共值的相同查询 (“M”、“R”或“T”),结果是 次优性能。这 次优性能问题 存在直到查询 重新编译。那时,基于 提供的@P1参数值, 查询可能有也可能没有 性能问题。”

减少网络延迟A) 如果您一遍又一遍地运行相同的 SQL,并且该 SQL 的代码加起来会达到许多 KB,那么用简单的“exec foobar”替换它确实可以加起来。 B) 存储过程可用于将过程代码移至 DBMS 中。这样可以避免将大量数据传输到客户端,而只是让它发送回少量信息(或者根本不发送信息!)。类似于在 DBMS 中与代码中进行 JOIN(每个人最喜欢的 WTF!)

还有优势吗?A) 现代 1Gb(以及 10Gb 及以上!)以太网确实使这一点可以忽略不计。 B) 取决于您的网络的饱和程度——为什么要无缘无故地来回传输几兆字节的数据?

潜在的缓存优势如果 DBMS 上有足够的内存并且您需要的数据位于服务器内存中,则执行服务器端数据转换可能会更快。

还有优势吗?除非您的应用程序具有对 DBMS 数据的共享内存访问权限,否则优势将始终是存储过程。

当然,如果不讨论参数化和即席 SQL,那么对存储过程优化的讨论就不完整。

参数化/准备好的 SQL
它们是存储过程和即席 SQL 之间的一种交叉,它们是使用“参数”作为查询值的主机语言中的嵌入式 SQL 语句,例如:

SELECT .. FROM yourtable WHERE foo = ? AND bar = ?

它们提供了更通用的查询版本,现代优化器可以使用它来缓存(和重用)查询执行计划,从而获得存储过程的大部分性能优势。

即席 SQL只需打开 DBMS 的控制台窗口并输入 SQL 语句即可。在过去,这些是“最差”的执行者(平均而言),因为 DBMS 无法像参数化/存储过程方法那样预先优化查询。

还是劣势?不必要。大多数 DBMS 都能够将临时 SQL“抽象”为参数化版本,从而或多或少地消除了两者之间的差异。有些是隐式执行此操作或必须使用命令设置启用(SQL 服务器:http://msdn.microsoft.com/en-us/library/ms175037.aspx,甲骨文:http://www.praetoriate.com/oracle_tips_cursor_sharing.htm).

得到教训?摩尔定律继续发展,DBMS 优化器在每个版本中都变得更加复杂。当然,您可以将每一个愚蠢的微小 SQL 语句放入存储过程中,但要知道,从事优化器工作的程序员非常聪明,并且不断寻找提高性能的方法。最终(如果还没有)临时 SQL 性能将与存储过程性能变得无法区分(平均而言!),因此任何类型的massive存储过程使用**仅出于“性能原因”**对我来说听起来确实是过早的优化。

无论如何,我认为如果您避免边缘情况并使用相当普通的 SQL,您将不会注意到临时过程和存储过程之间的差异。

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

一般来说,存储过程比现代 RDBMS 上的内联语句更有效吗? [复制] 的相关文章

  • @GenerateValue(strategy = GenerationType.SEQUENCE) 和 startVaule

    当在 Hibernate 中使用 GeneeratedValue Annotation 并向数据库添加新实体时 它的 id 为 1 n 是否可以设置第一个值 以便获得 id 例如10000 n 序列样式生成器应该做到这一点 Generate
  • PostgreSQL 中“-”处或附近的语法错误

    我正在尝试运行查询来更新用户密码 alter user dell sys with password Pass 133 但因为 它给了我这样的错误 ERROR syntax error at or near LINE 1 alter use
  • T-SQL:用最新的非空值替换 NULL 的最佳方法?

    假设我有这张表 id value 1 5 2 4 3 1 4 NULL 5 NULL 6 14 7 NULL 8 0 9 3 10 NULL 我想编写一个查询来替换任何NULL值与表中最后一个不为空的值在那一栏里 我想要这个结果 id va
  • 数据库表设计

    我在选择数据库表的变量类型时遇到问题 有人可以给我一些关于如何选择类型的一般准则吗 以下是我的一些问题 用户 ID 应该是什么 INT 看起来很小 因为设计时应该考虑到大量用户 那么如果不是 INT 还有什么呢 大整数 VARCHAR 难道
  • SQL 2008全文索引填充延迟

    我的经理说 在基础表数据更改后 可能需要一段时间才能更新全文搜索索引 例如 如果我有一张桌子Products有一个柱子Description我更新了该描述 然后我可能需要一些时间才能搜索该新描述 真的吗 这需要多长时间 SQL 2008 对
  • 检查两个“select”是否相等

    有没有办法检查两个 非平凡的 选择是否等效 最初我希望两个选择之间有形式上的等价 但是答案在证明 sql 查询等价性 https stackoverflow com questions 56895 proving sql query equ
  • Android Realm.io:行/对象不再有效

    这是我的删除功能 它确实找到了workday1 object public static void delete Context context Workday workday Realm realm getRealm context re
  • 如何搜索例程的内容/(SP-触发函数)

    我需要在数据库内所有例程的例程主体 存储过程 函数 触发器 中搜索文本 我该怎么做 Thanks SELECT OBJECT NAME object id FROM sys sql modules WHERE definition LIKE
  • 使用子查询 select 创建新表

    我试图从子查询选择创建一个新表 但出现以下错误 附近的语法不正确 SELECT INTO foo FROM SELECT DATEPART MONTH a InvoiceDate as CalMonth DATEPART YEAR a In
  • 获取带有计数的不同记录

    我有一张桌子personid and msg列 personid msg 1 msg1 2 msg2 2 msg3 3 msg4 1 msg2 我想得到总计msg对于每个personid 我正在尝试这个查询 select distinct
  • 如何在 DB2 中创建返回序列值的函数?

    如何在 DB2 中创建一个从序列中获取值并返回该值的函数 应该可以在 select 或 insert 语句中使用该函数 例如 select my func from xxx insert into xxx values my func 基本
  • 解析带下划线的 SQL Server 数字文字

    我想知道它为什么有效以及为什么它不返回错误 SELECT 2015 11 Result 11 2015 第二种情况 SELECT 2 1 a a 2 1 检查元数据 SELECT name system type name FROM sys
  • SQL 连接两个没有关系的表

    我有具有相同结构的不同表 我想通过其中一列将它们连接起来 问题是他们不共享该专栏中的信息 Table 1 Type A Name Value Table 2 Type B Name Value 结果表 在单列中 nameFromA name
  • 如何处理数据库中的巨大结果集

    我正在设计一个多层数据库驱动的 Web 应用程序 SQL 关系数据库 用于中间服务层的 Java 用于 UI 的 Web 语言其实并不重要 中间服务层执行数据库的实际查询 用户界面只是要求某些数据 并不知道它是由数据库支持的 问题是如何处理
  • 从 Getdate() 获取时间

    我想采取Getdate 结果 例如 2011 10 05 11 26 55 000 into 11 26 55 AM 我看过其他地方并发现 Select RIGHT CONVERT VARCHAR GETDATE 100 7 这给了我 11
  • 如何使用 BigQuery 有效地选择另一个表中匹配子字符串的记录?

    我有一个包含数百万个字符串的表 我想将其与包含大约两万个字符串的表进行匹配 如下所示 standardSQL SELECT record FROM record JOIN fragment ON record name LIKE CONCA
  • Spring Boot Data JPA 从存储过程接收多个输出参数

    我尝试通过 Spring Boot Data JPA v2 2 6 调用具有多个输出参数的存储过程 但收到错误 DEBUG http nio 8080 exec 1 org hibernate engine jdbc spi SqlStat
  • 快速将列的副本添加到 MySQL 表

    我需要一种快速的方法来复制表中的 DATETIME 列并为其指定一个新名称 我的表中有一个名为 myDate 的列 名为 myResults 我需要一个查询来在名为 newDate 的表中创建一个新列 该列的数据与 myDate 列完全相同
  • SQL 更新 - 更新选定的行

    我正在使用 SQL Server 2008 我有一个名为MYTABLE有两列 ID STATUS 我想编写一个存储过程来返回其记录STATUS是 0 但是这个存储过程必须更新STATUS返回行数为 1 如何在单个查询中执行此选择和更新操作
  • 是否可以引用同一个表中的不同列?

    如果博客有一个 类别 表 如下所示 CREATE TABLE categories id INTEGER PRIMARY KEY AUTO INCREMENT parent id INTEGER NOT NULL name VARCHAR

随机推荐