【问题标题】:Does Oracle SQL database optimize by value?Oracle SQL 数据库是否按价值优化?
【发布时间】:2026-02-23 18:55:01
【问题描述】:

我知道(或认为我知道)使用准备好的语句之类的东西可以帮助将来执行相同的查询更快地执行。但是,我想知道,如果您使用准备好的语句但每次的实际值都相同,那么它是否还会使用该值进行额外优化?

为了提供更多背景信息,我想测试使用底层数据库的服务请求的性能。简单的方法是每次发送相同的数据。更艰巨的路线是确保每次的数据值都不同。但是,在任何一种情况下,都会生成相同的 SQL 查询——只是值会不同。那么,由于潜在的数据库优化,这些场景最终会测试相同的东西还是不同的东西?

我试图研究这个主题,但我觉得我正在阅读的很多内容都超出了我的想象。除了中心问题之外,还欢迎对数据库优化知之甚少的人提供任何好的链接。

【问题讨论】:

  • 试试看有什么不同?
  • @PeterLawrey 我的时间有限,而且做“每次新值”的路线会很耗时(因为数据需要满足某些条件)。此外,这样做会限制我在这方面可以做的其他测试(因为时间有限)。我希望这个问题的答案可以帮助我决定我应该如何奉献我的时间。
  • 如果您发现很难对具有不同值的几个查询进行计时,那么您做错了。完成第一个后,您应该花 5 分钟反复尝试不同的值。
  • @PeterLawrey 是的,这是真的。我认为我应该创建不同的数据集,因为这将最接近真实的用例。
  • @AHungerArtist 从理论上讲,理论和实践是相同的,实际上它们是不同的。所以我经常认为某件事应该或不应该有所作为,但是当我测试它时,结果并不是我所期望的。 (它们匹配的时间超过一半;)

标签: java sql database performance oracle


【解决方案1】:

这完全取决于您正在做什么和测量什么。不过,我希望您需要使用不同的值才能获得真实的结果。

缓存

如果您每次都发送相同的值,您可能可以保证您感兴趣的特定行总是会被缓存(在缓冲区缓存中、在文件系统缓存中、在 SAN 中缓存等)如果可能的输入集很大,这可能不太现实。另一方面,如果有少量潜在输入,并且您有理由相信感兴趣的行将始终被缓存(例如,如果您知道在调用您的服务之前发生的一些其他活动将导致您感兴趣的数据在调用服务之前缓存在内存中)那么也许这是一个现实的假设。

优化

忽略缓存,我们可以看看优化器如何处理这两种情况。如果您正在生成带有嵌入文字的 SQL 查询(这是一种在 Oracle 中特别有害但非常常见的不良做法),那么您正在生成不同的 SQL 语句。就甲骨文而言

SELECT *
  FROM emp
 WHERE deptno = 10

是与

完全不同的陈述
SELECT *
  FROM emp
 WHERE deptno = 20

您可以调整一些设置(即cursor_sharing)以要求 Oracle 将这两个查询视为相同的查询(通过让 Oracle 强制它们使用绑定变量)但这并非没有缺点,通常只推荐当您在重构应用程序以正确使用绑定变量时尝试将创可贴应用于编写不佳的应用程序。

假设您在应用程序中使用绑定变量生成查询,准备语句,然后在多次执行查询之前绑定不同的值,即

SELECT *
  FROM emp
 WHERE deptno = :1

然后您将进入直方图、绑定变量窥视和自适应游标共享领域。这可能会涉及很多,并且很大程度上取决于您使用的 Oracle 版本、您使用的版本以及您如何配置优化器以使其工作。我将尝试在这里提供一个简化的高级概述 - 如果您想深入研究其中一个,我们可能需要一个单独的问题。

直方图

默认情况下,优化器假定数据是等间距和等可能的。因此,例如,如果deptno 列有 50 个不同的值,则优化器默认假定每个值的可能性相同。对于大多数列来说,这可能是一个非常合理的假设,但对于所有列来说显然不是合理的。例如,如果我有一张包含所有现役军人的表,其中一列是 birth_year,那么 1994 年(20 年前)的 birth_year 行将比 1934 年(80 年前)多得多.在这些情况下,您可以收集相关列的直方图,以便告诉优化器数据分布不均匀,并让优化器收集有关哪些值更常见以及它们的常见程度的信息。

优化器不关心您为绑定变量值传递的值,除非您的谓词中的一列上有直方图(我暂时忽略您传递的值的可能性超出范围)。

绑定变量窥视

如果您在一个或多个列上确实有直方图,那么 Oracle(9.1 及更高版本,如果有记忆的话)将“窥视”为绑定变量传入的第一个值,并将该值与直方图一起使用来确定所有后续执行的最佳计划。这在绝大多数情况下工作得相当好,但是当 Oracle 偷看一个“坏”值并生成一个对那一次执行有效但对所有未来都很糟糕的计划时,它偶尔会导致令人毛骨悚然的痛苦问题(以及很多咒骂)处决。 Tom Kyte 关于the database that has to be restarted if it's rainy on a Monday morning 的故事总结了这一点。如果您在列上有一个直方图,并且您可能传入的不同值可能会从不同的查询计划中受益,那么您可能需要考虑绑定变量窥视以确定以不同顺序传入值是否会产生任何性能问题.

自适应光标共享

在最近的版本中(如果内存服务于 11.1 和更高版本)并且根据您的配置,Oracle 可以使用 adaptive cursor sharing 来维护单个语句的多个查询计划,并为特定的绑定变量值使用最合适的版本,即这是一个更复杂的绑定变量窥视版本,它窥视你传入的每组值,并确定它是否与其他一组值足够接近以使用先前生成的计划,或者它是否需要计算新价值观的新计划。弄清楚什么是“足够接近”以及它如何与各种功能相互作用以确保计划的稳定性,这本身就是一个相当复杂的话题。

【讨论】:

    【解决方案2】:

    你可以使用数据库缓存

    http://www.oracle.com/technetwork/articles/sql/11g-caching-pooling-088320.html

    如果应用程序在进行网络往返和计算结果,那仍然会消耗相当长的时间

    【讨论】:

    • 您的答案只是链接,您介意编辑您的帖子以包含文本中相关的引用部分吗?
    • 该材料只是解释了“如何”进行数据库缓存,并且 op 确实要求提供链接 - 链接没有回答 op 问题的真正答案,数据库只是整个应用程序的一部分
    • 非常正确...但是 * 也是一个参考站点,人们可以/将根据需要提出这个问题(其中许多问题和答案出现在 google 中)。链接总是有过时的风险,最好在答案中包含相关组件