【发布时间】:2010-11-02 14:35:50
【问题描述】:
我目前面临一个问题,即在我的 Java 应用程序中发出特定的 SQL 查询大约需要 30 秒,但在 SQL 客户端 (SQL Developer) 中发出
在问题中,
Slow query in Java by JDBC but not in other systems (TOAD),建议使用绑定到 java 变量的 PreparedStatement 可能会使查询的执行速度比在 SQL 客户端(在这种情况下为 TOAD)中执行得慢得多,因为 Oracle 感到困惑关于使用哪些索引。这可能是没有参数的 PreparedStatement 的问题吗?
否则可能是什么问题?
查询看起来像
select
sum(col1),
sum(col2),
max(select ...)
from view_
where time_id = get_time_id(to_date('2010-10-10','yyyy-mm-dd'))
其中 view_ 是一个复杂视图,包含表和其他复杂视图的聚合。查询作为 PreparedStatement 执行,但没有任何参数。无论我们使用准备好的语句还是简单的语句似乎都没有区别。
由于执行计划非常庞大,我无法在此处发布所有内容,但相关差异似乎是:
UNION-ALL 表访问完整 GVC_WH.PLAYER_FACT_DAILY 表 37 6717151 596,934.317 19940 240 7621178231 19502 UNION-ALL 按索引 ROWID 访问表 GVC_WH.PLAYER_FACT_DAILY 表 38 2657 236.120 2429 30 20544658 2428 索引范围扫描 GVC_WH.PK_AGG_PLAYER 索引(唯一) 37 2657 16 1 638743 16第一个 sn-p 是使用 JDBC 瘦客户端运行时的位置,第二个是在 SQL Developer 中运行时的位置。使用 JDBC 瘦客户端作为语句运行时(无论我是否使用准备好的语句都没有区别),它没有拾取正确的索引。第一个时间差是 30 秒,第二个是 0.5 秒。
难道是使用函数 get_time_id 在通过 JDBC 使用时禁止使用索引,即使它不是列上的函数,即使它似乎在 SQL Developer 中工作?
【问题讨论】:
-
能否获取并发布这两个案例的查询计划?为了清楚起见,您是否始终如一地衡量绩效?意外测量 SQL Developer 返回第一行的时间与您的 Java 代码获取最后一行的时间是很常见的,这可能有很大的不同。
-
我将从查看每个方法(TOAD 与 Java)生成的执行计划(通过 dbms_xplan.display 光标)开始。这应该告诉您数据库是否以不同的方式处理查询。如果是这样,请密切注意谓词部分,因为这可能会为您提供一些关于原因的线索(例如,Java 版本发生隐式数据类型转换并导致 Oracle 无法使用索引)
-
您是否在 to_date 调用中指定日期模式参数?我认为默认模式取决于您的语言环境设置,实际上可能与 java 代码或 toad 不同。
-
如果您将查询拆分为
select get_time_id(to_date('2010-10-10','yyyy-mm-dd')) from dual,然后使用... where time_id = ?将其传递到准备好的语句中,会有什么不同吗