【问题标题】:Performance issues with JDBCJDBC 的性能问题
【发布时间】: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 = ? 将其传递到准备好的语句中,会有什么不同吗

标签: oracle jdbc


【解决方案1】:

我会尝试在使用应用程序时在数据库上运行trace

然后您应该能够看到正在运行的查询以及实际的执行计划。这将准确地向您显示发生了什么,即它是否正在获取索引。

【讨论】:

    【解决方案2】:

    由于传入谓词,您很可能遇到绑定变量峰值问题。尝试使用以下内容运行查询以确认(即一致的运行时间)

    alter session set “_optim_peek_user_binds”=false;
    

    所有对象的统计数据都是最新的吗?

    正如贾斯汀所发布的那样,确保您的测量也正确无误。如果没有完整的查询,就很难提供额外的见解。

    【讨论】:

    • 你指的是什么变量?正如我所说,准备好的语句没有参数。此外,性能差异是仅获取单行的数量级。统计数据是最新的。
    • 根据 CURSOR_SHARING 参数的值,Oracle 可以在语句上强制绑定变量。 download.oracle.com/docs/cd/B19306_01/server.102/b14237/…
    【解决方案3】:

    检查以确保没有人设置属性 oracle.jdbc.defaultNChar=true

    有时这样做是为了解决 unicode 问题,但这意味着所有列都被视为 nvarchars。如果您在 varchar 列上有索引,则不会使用它,因为 oracle 必须使用函数来转换字符编码。

    【讨论】:

      猜你喜欢
      • 2012-05-05
      • 2012-06-18
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      • 2011-01-20
      • 2012-02-13
      • 2011-01-20
      • 2017-04-13
      相关资源
      最近更新 更多