[英]JDBC automatical query turned to be very slow
我正在維護一個通過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內部構件開始變得非常慢,因為它似乎對我所有的分支都是一樣的。
有人知道一個可能的原因以及如何面對這個問題嗎?
此致,Nunzio
數據字典或固定對象統計信息可能很舊,請嘗試重新收集它們:
exec dbms_stats.gather_dictionary_stats;
exec dbms_stats.gather_fixed_objects_stats;
alter system flush shared_pool;
即使這樣也不一定會收集所有系統對象的統計信息。 必須手動收集某些對象,如X$KFTBUE
。 雖然這是一個罕見的數據字典問題,可能與此無關。
如果這不起作用,則下一步可能的步驟是查看SQL Tuning Advisor等工具來創建配置文件,或使用SQL計划管理強制優化器使用以前工作過的特定計划。 調整數據字典查詢可能非常困難,因為您沒有太多控制權。
這是另一個更優雅的解決方案..我發現強制帶有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;
/
問題中的查詢是通過調用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
我發現這種方式作弊..在你反向設計一個模式之前,以你用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);
然后有問題的查詢真的尖叫..缺點是你必須不時刷新它...也許使它成為物化視圖?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.