在 Oracle 12c 中对 user_cons_columns 的查询要慢得多

J D*_*Dor 3 oracle oracle12c

我们正在从 Oracle 11g 升级到 12c,并注意到 user_cons_columns 上的查询似乎慢了很多。

例如,即使在较小的数据集上,这也会慢 4 倍:

select uc.search_condition 
from user_constraints uc inner join user_cons_columns ucc on ucc.CONSTRAINT_NAME = uc.CONSTRAINT_NAME  
where ucc.table_name = :upper_table_name
and ucc.column_name = :upper_column
Run Code Online (Sandbox Code Playgroud)

难道这只是收集统计数据的问题吗?

Kje*_* S. 5

根据我的经验,对于几个主要的 Oracle 版本,从user_constraintsuser_cons_columns以及其他数据字典视图中进行选择的速度很慢。不只是12c。这样做将dbms_stats.gather_dictionary_stats;第一个查询的速度提高了 10-20%。

真正有用的是使用提示重写查询以从 with子句“表”中选择/*+materialized*/,而不是直接从user_表中选择。

这个查询在我的设置中非常慢,大约150 秒:(它返回表列表上的所有外键,包括外键两端的表名和列名)

select
  cc.table_name, cc.position, cc.constraint_name, cc.column_name,
  cr.table_name r_table_name, ccr.constraint_name r_constraint_name, ccr.column_name r_column_name
from user_constraints   c
join user_cons_columns  cc on cc.constraint_name=c.constraint_name and
                              cc.owner=c.owner and 
                              cc.table_name=c.table_name
join user_constraints   cr on cr.owner=c.r_owner and
                              cr.constraint_name=c.r_constraint_name and
                              cr.constraint_type in ('P','U')
join user_cons_columns ccr on ccr.constraint_name=cr.constraint_name and
                              ccr.owner=cr.owner and
                              ccr.table_name=cr.table_name and
                              ccr.position=cc.position
where c.constraint_type='R'
and c.table_name in ('TABLE_A', 'TABLE_B', ........a list of about 157 table names.......)
order by cc.table_name, cc.position, constraint_name, column_name, cc.position;
Run Code Online (Sandbox Code Playgroud)

重写此后,查询仅使用1-8 秒

with
uc  as (select /*+materialize*/ owner,table_name,constraint_name,constraint_type,r_owner,r_constraint_name  from user_constraints),
ucc as (select /*+materialize*/ owner,table_name,constraint_name,position,column_name from user_cons_columns)
select
  cc.table_name, cc.position, cc.constraint_name, cc.column_name,
  cr.table_name r_table_name, ccr.constraint_name r_constraint_name, ccr.column_name r_column_name
from uc     c
join ucc   cc on cc.constraint_name=c.constraint_name and cc.owner=c.owner and cc.table_name=c.table_name
join uc    cr on cr.owner=c.r_owner and cr.constraint_name=c.r_constraint_name and cr.constraint_type in ('P','U')
join ucc  ccr on ccr.constraint_name=cr.constraint_name and ccr.owner=cr.owner and ccr.table_name=cr.table_name and ccr.position=cc.position
where c.constraint_type='R'
and c.table_name in ('TABLE_A', 'TABLE_B', ........a list of about 157 table names.......)
order by cc.table_name, cc.position, constraint_name, column_name, cc.position;
Run Code Online (Sandbox Code Playgroud)

我也尝试*不只列出with表中所需的列,但这没有帮助。我猜这是因为/*+materialize*/如果要记住/缓存太多数据,Oracle 会忽略提示。