【问题标题】:JDBC automatical query turned to be very slowJDBC自动查询变得很慢
【发布时间】:2014-03-18 13:21:08
【问题描述】:

我正在维护一个通过 JDBC 创建 Oracle DB 的应用程序。从今天开始这个查询:

SELECT  NULL                                                   AS pktable_cat  ,
        p.owner                                                AS pktable_schem,
        p.table_name                                           AS pktable_name ,
        pc.column_name                                         AS pkcolumn_name,
        NULL                                                   AS fktable_cat  ,
        f.owner                                                AS fktable_schem,
        f.table_name                                           AS fktable_name ,
        fc.column_name                                         AS fkcolumn_name,
        fc.position                                            AS key_seq      ,
        NULL                                                   AS update_rule  ,
        DECODE (f.delete_rule, 'CASCADE', 0, 'SET NULL', 2, 1) AS delete_rule  ,
        f.constraint_name                                      AS fk_name      ,
        p.constraint_name                                      AS pk_name      ,
        DECODE(f.deferrable, 'DEFERRABLE',5 ,'NOT DEFERRABLE',7 , 'DEFERRED', 6 ) deferrability
FROM    all_cons_columns pc,
        all_constraints p  ,
        all_cons_columns fc,
        all_constraints f
WHERE   1                      = 1
        AND p.table_name       = :1
        AND p.owner            = :3
        AND f.constraint_type  = 'R'
        AND p.owner            = f.r_owner
        AND p.constraint_name  = f.r_constraint_name
        AND p.constraint_type  = 'P'
        AND pc.owner           = p.owner
        AND pc.constraint_name = p.constraint_name
        AND pc.table_name      = p.table_name
        AND fc.owner           = f.owner
        AND fc.constraint_name = f.constraint_name
        AND fc.table_name      = f.table_name
        AND fc.position        = pc.position
ORDER BY fktable_schem,
        fktable_name  ,
        key_seq

由于一些 oracle 内部结构,它开始变得非常缓慢,因为它似乎对我所有的分支都是一样的。

有人知道一个可能的原因以及如何面对这个吗?

问候, 努齐奥

【问题讨论】:

  • 您是否尝试过为您的查询生成解释计划?
  • 我可以,这有什么帮助?我无法控制此内容。我的观点是:我们是否缺少任何维护步骤?该软件每天在我们的 CI 中运行数十次。现在我们遇到了这个奇怪的问题。
  • 它会告诉你为什么查询很慢。如果您不知道导致缓慢的原因,您无法决定哪些维护步骤可能会或可能不会产生影响。

标签: java sql oracle jdbc database-metadata


【解决方案1】:

数据字典或固定对象统计信息可能是旧的,请尝试重新收集它们:

exec dbms_stats.gather_dictionary_stats;
exec dbms_stats.gather_fixed_objects_stats;
alter system flush shared_pool;

即使这样也不一定会收集所有系统对象的统计信息。有些对象,如X$KFTBUE,必须手动收集。虽然这是一个罕见的数据字典问题,可能与这里无关。

如果这不起作用,接下来的一些可能步骤是查看 SQL Tuning Advisor 等工具来创建配置文件,或者使用 SQL 计划管理来强制优化器使用以前有效的特定计划。由于您没有太多控制权,因此调整数据字典查询可能非常困难。

【讨论】:

  • 这似乎已经解决了这个问题,我一直在寻找类似的东西。感谢您抽出宝贵时间分享这条有趣的信息。
  • stackoverflow.com/questions/8792890/… @a_horse_with_no_name 中还建议:“我的经验是 Oracle 的系统目录非常慢。有时对我有帮助的唯一方法是在 SYS 模式上运行 dbms_stats.gather_schema_stats() 。”
  • 必须注意的是,在我们的案例中,上述方法都无法帮助实现持续加速。
  • @Vadzim 谢谢。我添加了一些我过去用来解决数据字典问题的选项。
【解决方案2】:

这里是另一个更优雅的解决方案.. 我发现使用 sql 补丁强制规则库优化器也有效.. 2 个补丁是必要的,因为有时 jdbc 驱动程序使用 :1 和 :3 作为绑定变量,有时它使用: 2 & :4.. SQL 必须完全匹配才能使补丁工作。

在您的数据库中以 sysdba 身份运行它..

    begin 
        dbms_sqldiag_internal.i_create_patch ( 
      sql_text =>'SELECT NULL AS pktable_cat,
        p.owner as pktable_schem, p.table_name as pktable_name, 
        pc.column_name as pkcolumn_name, NULL as fktable_cat, f.owner as       
        fktable_schem, f.table_name as fktable_name, 
        fc.column_name as fkcolumn_name, fc.position as key_seq, NULL as 
        update_rule, decode 
        (f.delete_rule, ''CASCADE'', 0, ''SET NULL'', 2, 1) as delete_rule, 
        f.constraint_name as fk_name, p.constraint_name as pk_name, 
        decode(f.deferrable, ''DEFERRABLE'',5 ,''NOT DEFERRABLE'',7 , ''DEFERRED'', 6)  
        deferrability
        FROM all_cons_columns pc, all_constraints p, all_cons_columns fc, 
        all_constraints f
        WHERE 1 = 1 AND p.table_name = :1  AND p.owner = :3 AND 
         f.constraint_type = ''R'' AND p.owner = f.r_owner AND 
         p.constraint_name = f.r_constraint_name AND p.constraint_type = ''P'' 
         AND pc.owner = p.owner AND pc.constraint_name = p.constraint_name AND
         pc.table_name = p.table_name AND fc.owner = f.owner AND 
         fc.constraint_name = f.constraint_name AND 
         fc.table_name = f.table_name AND fc.position = pc.position 
        ORDER BY fktable_schem, fktable_name, key_seq' ,
      hint_text => 'RULE', 
      name => 'jdbcpatch');
    end;
    /

    begin 
        dbms_sqldiag_internal.i_create_patch ( 
      sql_text =>'SELECT NULL AS pktable_cat,
        p.owner as pktable_schem, p.table_name as pktable_name, 
        pc.column_name as pkcolumn_name, NULL as fktable_cat, f.owner as       
        fktable_schem, f.table_name as fktable_name, 
        fc.column_name as fkcolumn_name, fc.position as key_seq, NULL as 
        update_rule, decode 
        (f.delete_rule, ''CASCADE'', 0, ''SET NULL'', 2, 1) as delete_rule, 
        f.constraint_name as fk_name, p.constraint_name as pk_name, 
        decode(f.deferrable, ''DEFERRABLE'',5 ,''NOT DEFERRABLE'',7 , ''DEFERRED'', 6)  
        deferrability
        FROM all_cons_columns pc, all_constraints p, all_cons_columns fc, 
        all_constraints f
        WHERE 1 = 1 AND p.table_name = :2  AND p.owner = :4 AND 
         f.constraint_type = ''R'' AND p.owner = f.r_owner AND 
         p.constraint_name = f.r_constraint_name AND p.constraint_type = ''P'' 
         AND pc.owner = p.owner AND pc.constraint_name = p.constraint_name AND
         pc.table_name = p.table_name AND fc.owner = f.owner AND 
         fc.constraint_name = f.constraint_name AND 
         fc.table_name = f.table_name AND fc.position = pc.position 
        ORDER BY fktable_schem, fktable_name, key_seq' ,
      hint_text => 'RULE', 
      name => 'jdbcpatch2');
    end;
    /

【讨论】:

  • 这是一种有趣的方法,但使用文档化的计划管理功能可能会更好,例如配置文件、大纲、SPM 等。
【解决方案3】:

问题中的查询是通过调用java.sql.DatabaseMetaData.getExportedKeys() 生成的,该调用委托oracle.jdbc.OracleDatabaseMetaData.getExportedKeys() 枚举引用给定表的外键。

正如@Jon 的回答中所述,Oracle 有时会为此查询使用次优计划,这可能会或可能不会通过收集统计信息来避免。

如果代码可以更改的其他替代方案:

第二个选项是由Liquibase 项目选择的,该项目过去在旧版本中调用DatabaseMetaData。 新版本使用来自CORE-1844 的正确连接的优化查询:

SELECT NULL AS pktable_cat, p.owner as pktable_schem, 
    p.table_name as pktable_name, pc.column_name as pkcolumn_name,    
    NULL as fktable_cat, f.owner as fktable_schem, f.table_name as fktable_name,    
    fc.column_name as fkcolumn_name, fc.position as key_seq, NULL as update_rule,    
    decode (f.delete_rule, 'CASCADE', 0, 'SET NULL', 2, 1) as delete_rule,    
    f.constraint_name as fk_name, p.constraint_name as pk_name,    
    decode(f.deferrable, 'DEFERRABLE', 5, 'NOT DEFERRABLE', 7, 'DEFERRED', 6) deferrability  
FROM    all_constraints p
INNER JOIN  all_cons_columns pc ON pc.owner = p.owner    
    AND pc.constraint_name = p.constraint_name    
    AND pc.table_name = p.table_name    
INNER JOIN all_constraints f ON p.owner = f.r_owner    
    AND p.constraint_name = f.r_constraint_name
INNER JOIN all_cons_columns fc ON fc.owner = f.owner    
    AND fc.constraint_name = f.constraint_name
    AND fc.table_name = f.table_name
    AND fc.position = pc.position
WHERE p.owner = :jdbcSchemaName
    AND p.constraint_type in ('P', 'U')    
    AND f.constraint_type = 'R'    
ORDER BY fktable_schem, fktable_name, key_seq

【讨论】:

    【解决方案4】:

    我发现了这种作弊方式。在对架构进行逆向工程之前,以与 jdbc 连接的用户身份运行它。

    CREATE TABLE all_constraints AS
      SELECT owner,
             constraint_name,
             constraint_type,
             table_name,
             r_owner,
             r_constraint_name,
             delete_rule,
             status,
             deferrable,
             deferred,
             validated,
             generated,
             bad,
             rely,
             last_change,
             index_owner,
             index_name,
             invalid,
             view_related
      FROM   all_constraints;
    
    CREATE TABLE all_cons_columns AS
      SELECT *
      FROM   all_cons_columns;
    
    CREATE INDEX ac1
      ON all_constraints (owner, constraint_name, table_name);
    
    CREATE INDEX acc1
      ON all_cons_columns (owner, constraint_name, table_name);  
    

    那么有问题的查询真的很尖叫..缺点是你必须不时刷新它..也许让它成为一个物化视图?

    【讨论】:

      【解决方案5】:
      1. 使用 oracle 解释计划http://docs.oracle.com/cd/B10500_01/server.920/a96533/ex_plan.htm (使用结果找到瓶颈并重新编写或更改您的查询以更快地运行)。
      2. 确保您在表上使用索引并且索引已更新。
      3. 使用分区。
      4. 清理一些您不再需要的数据
      5. 尽可能使用休眠(如果这是一个遗留应用程序,这可能不是一件容易的事情),因为它会为您优化查询,并且您不需要编写 JDBC 查询。
      6. 最后看一下oracle性能调优文档http://docs.oracle.com/cd/E11882_01/server.112/e41573/perf_overview.htm#PFGRF02503

      【讨论】:

      • 这是一个内部查询,我无法控制这些表。顺便说一句,我们使用 JPA。
      • @NunzioVisciano 不确定您对内部查询和无法控制表的含义。如果您想要更好的性能,您需要对表和查询进行调整。
      • 我的意思是:JDBC 和 JPA 使用一些内部数据结构(以及表)来执行它们的工作。这个查询不在我们的代码库中就是这种情况,它会自动启动。所有这一切都意味着,根据我目前的知识,我们无法更改任何架构和查询本身。我希望我现在清楚了。
      • 你能直接在数据库上运行查询吗?那里也很慢吗?
      • 伙计们,我认为情况还不清楚。这个查询中提到的表是 Oracle 表,因为我们的 sw 在几十个不同的服务器上运行,所以我根本无法触摸它们。恕我直言,服务器中发生了一些事情,需要使用一些维护程序来修复。有人遇到过这样的事情吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-06
      • 1970-01-01
      • 2017-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多