1

我有 20 年的 SQL 经验,但不是专门使用 Oracle 的。一位“Oracle 专家”向我保证,构建一个没有参数的 SQL 查询(像这样):

SELECT t.ID, t.Name, t.Address ... FROM Table1 t WHERE t.ID = 'someID' AND t.Name = 'someName'...

至少和使用参数一样快(像这样)

SELECT t.ID, t.Name, t.Address ... FROM Table1 t WHERE t.ID = ? AND t.Name = ?

代码在循环中执行。

在我使用过的大多数其他数据库中,使用参数可以提高速度。它允许数据库缓存与 SQL 语句匹配的编译计划。由于 SQL 不会在每次调用时更改(尽管参数会更改),因此可以提高性能。数据库简单地绑定参数并继续。

“甲骨文专家”表示这没有必要。但显然,Oracle 需要“解析”参数,将剩余的字符串与缓存的执行计划相匹配,然后重新绑定参数,就好像它们最初是作为参数传递的一样。

我在这里有正确的心理图景吗?Oracle 是否有一些“神奇”之处,它真的不会影响我们如何处理参数传递/SQL 构建策略?

是否有关于 Java / JDBC / Oracle 瘦驱动程序的想法我不知道我应该在这里知道?

我希望加强我的理解或扩展我的知识。

(除了安全问题,我知道构建 SQL 字符串允许 SQL 注入攻击,我正在寻找更直接的弹药来反对专家的意见 - 如果它存在的话)。

其他详情:Oracle 11gR2, Java 1.6

4

4 回答 4

4

直言不讳——你说得对,你的 Oracle 专家似乎根本不是专家(除非他想出售昂贵的咨询时间来加快你​​的应用程序投入生产后的速度)。

如果您构建不带参数的 SQL 语句(在 Oracle 中称为绑定变量),则会强制数据库在每次执行该语句时对其进行硬解析。

请参阅AskTom 关于软/硬解析和绑定变量以获得更好的解释。

于 2012-10-15T13:44:55.653 回答
3

使用参数几乎总是可取的。如果您使用文字(版本一),数千条略有不同的 SQL 语句将访问数据库,导致硬解析并填满 Oracle 的语句缓存。

这是该规则的一个例外:如果您要查询的列的值分布非常不均匀,则带有文字的版本可能允许查询优化器找到更好的计划。

例如,假设绝大多数 slashdot 读者是男性(*),

select * from slashdot_readers where gender='MALE';

可能会导致查询优化器忽略索引gender并执行全表扫描,而

select * from slashdot_readers where gender='FEMALE';

可能会导致它使用索引。使用变量,查询优化器将不知道要使用哪个版本,因此它可能总是进行全表扫描。

(*) 只是为了这个例子

于 2012-10-15T13:49:52.963 回答
1

我没有做过任何性能测量,但我认为你的图片是正确的。无论如何,即使它们同样快,我总是更喜欢使用参数/绑定变量的变体来防止 SQL 注入。在您的 where 子句中固定字符串的示例中,这可能不是问题,但在实际应用程序中,这些字符串通常来自外部某个地方。(我想你在我写这个答案时编辑了你的问题:-))

于 2012-10-15T13:41:56.203 回答
1

做一些测量。获取数据。

从我对甲骨文的了解来看——你应该是对的。显然,请确保它是否在循环中,您正在重新执行相同的操作PreparedStatement,而不是每次都重新准备它。仅此一项就可以降低查询的成本。

需要注意的一件事 -与简单的测试用例相比,您的实际应用程序可能从绑定变量中受益更多,因为在实际应用程序中,Oracle 将在其缓存中包含各种其他 SQL 语句(我忘记了不同内存区域的术语并缓存在 Oracle 中)并且随着它的填满,发送新 SQL 的成本一直上升很多。

于 2012-10-15T14:03:51.537 回答