2

这个问题可能更适合 DB stackexchange 站点,但我不确定。

无论如何,我正在处理优化查询,并且我了解到使用绑定变量会使解析器工作不那么努力。我们已经看到正在运行的查询有所改进,但我想知道将我们的软件传入的静态变量替换为绑定变量是否也会有所帮助。这是一个例子:

select *
from report
where report.name = :1
and report.enabled = '1'

我可以说出来

select *
from report
where report.name = :1
and report.enabled = :2

我只是进行更改,但是在软件中实际进行更改并查看它所产生的差异的过程有点漫长而乏味。有谁知道混合文字(如第一个示例)是否会损害优化器的效率,即使它们始终相同?

提前致谢。

4

4 回答 4

7

我不确定你的意思是什么I learned that using bind variables makes the parser not work as hard,但我猜......


您是否在客户端中构建 SQL 字符串并将它们发送到 oracle 数据库执行?

如果是这样,参数化查询的行为意味着数据库引擎可以看到多个查询,尽管具有不同的参数,但可以使用相同的执行计划/解释计划来满足。

这意味着引擎不需要重新编译原生 SQL,并且可以重用缓存中已经(可能)的计划。

如果没有参数化,并且“名称”具有不同的值,引擎会认为查询完全不同,而不会注意到相似性。这将导致 SQL 被编译,除非完全相同的字符串已经在缓存中。


但是,如果您的查询始终具有report.enabled = 1,则无需对查询的该部分进行参数化。因为它是静态的,所以不使用参数的行为不会使它看起来像一个不同的查询,也不会导致它被重新编译。

相反,您实际上可能会根据索引、数据统计等进行节省。例如,如果 99% 的数据是“启用 = 1”,那么与 1% 的数据相比,您可能会得到不同的计划被“启用= 1”。但是引擎只会在查询中针对“启用 = 1”进行优化,其中已知要查找的值始终为1。只有静态指定(作为文字)时才会出现这种情况。


简而言之,如果它确实是一个静态值,请不要对其进行参数化。

于 2011-12-20T16:27:19.510 回答
4

如果您的 SQL 确实包含常量(即子句 always enabled=1),我看到让它们作为 SQL 中的文字的几个原因:

  • 当您遇到性能问题并且无法立即访问绑定的值时(例如在某些跟踪文件中),调试起来会更容易
  • 优化器有时可以在使用常量时更有效地估计查询的基数(即:禁用绑定窥视或旧版本的 DBMS 时),特别是如果您在此列上有直方图的统计信息
  • 您需要为某些特定的计划选项使用常量(例如分区修剪)

此外,除了性能之外,使用参数化查询的另一个主要原因是防止 SQL 注入。真正的常量不会受到 SQL 注入的影响,因为它们将由您的代码提供,而不是由外部源提供。

于 2011-12-20T16:30:44.237 回答
0

答案通常是“视情况而定”。

什么?您的应用程序是 OLTP(多查询、小结果集)还是 DSS(少查询、大量数据)?您正在查看的从绑定更改为文字的列中涉及的偏差是什么?这些列是否需要可绑定,或者它们总是绑定到相同的值?

于 2011-12-20T16:22:27.800 回答
0

当 Oracle 收到一条 SQL 语句时,它首先会查看该 SQL 语句及其执行计划是否已经存在于缓存中。如果是这样,它就节省了重新创建执行计划的成本,从而节省了执行时间。为了让传入的 SQl 语句匹配缓存中的一条,它必须是完全匹配的(包括字母、绑定变量和空格)。这就是为什么鼓励使用绑定变量的原因,以便变量的不同值(以及不同的文字)的语句保持相同。但是,如果一直使用相同的文字,则使用绑定变量没有区别。在解析和执行计划生成方面,两种情况下的性能是相同的。

于 2011-12-20T16:28:14.020 回答