【问题标题】:Oracle search list of words in string and retruen existing onesOracle搜索字符串中的单词列表并重新生成现有单词
【发布时间】:2018-08-15 21:13:37
【问题描述】:

我正在尝试编写有关使用的数据仓库表的统计信息。

因此我应该进行查询以带上使用过的表。

我有一个表名列表和一个数据库表,其中存储了查询。

如何选择表名中使用的行?

Report Table:
...
QUERYTEXT String
...


select * from Report where QUERETEXT (?)

DWTableNames: DWA, DWB,..

我想用查询文本字段中存在的数据仓库表名打印每个报表。

【问题讨论】:

  • 这将是一个困难的项目(可能没有希望)。这只是其中一个原因:查询可能会间接引用表。它可以从视图中选择,但视图本身从基表中读取。您是否要编写您的解决方案,以便如果在查询中找到视图,那么还会解析视图定义以查看 IT 使用哪些表?那么:你可能有一个递归的 WITH 子句;在那种查询中,一个表可能会被多次读取,但查询的文本只引用表名一次。那你想怎么数呢?
  • @MarmiteBomber - 你的意思是?我只举了一个例子说明为什么这个项目不太有意义(我在那条评论中又举了一个例子)。还有很多。无论我们解决多少这些“特殊情况”,都会有更多没有解决。
  • 好吧,如果您需要一个真正的statistic,即不准确,但也不会出现错误的结果,您可以尝试这种方法。 1) 对所有查询执行Explain plan。 2) 根据您的列表检查plan_table 中的所有值OBJECT_OWNEROBJECT_NAME。 3) 您必须使用dba_indexes resp 将使用过的索引映射到表和视图到基表。 DBA_DEPENDENCIES。祝你好运!
  • @mathguy 对不起,我没有把标题弄红,这种方法使明确的意义不大。在上面的评论中看到我的观点。
  • @mathguy,感谢您的回答。我想,我这里没有递归。您可以在问题中看到解释的用例。

标签: oracle


【解决方案1】:

从 SQL 查询列表中提取表名的简单方法

设置 假设这是您的查询列表:

select * from a where id = 1;
select * from v;
with my_id as (select id from b)
select  /*+ PARALLEL(4) */ * from a where id in (select id from my_id);

为了也涵盖视图访问,这里是表定义:

create table a (id number);
create index a_idx  on a(id);

create table b (id number);
create table c (id number);
create table d (id number);

create view v as
select c.id from c join d on c.id = d.id;

所以有表a, b, c and dvc and d 上查看

*因此,您希望看到一个表列表 a, b, c and d,即使在您的查询列表中也只有表 a, b 被直接引用。

解决方案

第一步中,将您的查询列表转换为EXPLAIN PLAN 语句列表。如果列表的长度很长,您可能会发现使用某种脚本是可行的:

EXPLAIN PLAN  SET STATEMENT_ID = 'q1' into   plan_table  FOR select * from a where id = 1;
EXPLAIN PLAN  SET STATEMENT_ID = 'q2' into   plan_table  FOR select * from v; 
EXPLAIN PLAN  SET STATEMENT_ID = 'q3' into   plan_table  FOR with my_id as (select id from b)
select  /*+ PARALLEL(4) */ * from a where id in (select id from my_id);

通过执行EXPLAIN PLAN 语句,plan_table 填充了执行计划,每个操作的访问对象存储在列OBJECT_OWNER, OBJECT_NAME 中。

第一个天真的查询返回这个列表:

select distinct  OBJECT_OWNER,  OBJECT_NAME  
from plan_table 
where statement_id in ('q1','q2','q3') and OBJECT_NAME is not NULL
order by 1,2;

OBJECT_OWNER OBJECT_NAME
------------ -----------
DWH          A_IDX       
DWH          B           
DWH          C           
DWH          D           
SYS          :TQ10000    
SYS          :TQ10001    
SYS          :TQ10002 

有两件事必须解决。 首先必须忽略并行执行的行源(例如:TQ10000),因为它们不是真正的表。 其次,索引名称(例如A_IDX)必须使用字典视图DBA_INDEXES映射到table_names。

请注意,您不需要特别注意视图,因为它们会自动解析为源表。 子查询分解with 子句)也是如此。

两个主题的查询如下所示:

select distinct OBJECT_OWNER, 
/* map index name to table name */
case when p.OPERATION = 'INDEX' then i.TABLE_NAME else p.OBJECT_NAME end as TABLE_NAME  
from plan_table p
left outer join dba_indexes i on p.OBJECT_OWNER = i.OWNER and p.OBJECT_NAME = i.INDEX_NAME
where statement_id in ('q1','q2','q3') and OBJECT_NAME is not NULL
and p.OBJECT_NAME not like ':%' /* suppress parallel row sources */
order by 1,2;

OBJECT_OWNER TABLE_NAME
------------ ----------
DWH          A          
DWH          B          
DWH          C          
DWH          D 

最后请注意,此方法仅在所有查询和视图在语法上有效并且您拥有足够权限的用户来解释列表中所有查询的计划时才有效。

【讨论】:

  • 脚注:执行计划中的表和查询中的表之间可能存在差异。优化器可以从执行计划中完全消除表,因此您可以获得虚假结果。一个快速的技巧是根据您的 SQL 创建一个视图,然后查询 USER_DEPENDENCIES 以获取该视图。这将显示所需的对象,无论它们是否从执行计划中消除。
  • @ConnorMcDonald 好主意,而且执行起来也简单得多。非常感谢分享!
【解决方案2】:

这是我搜索的解决方案:

WITH dwtables(dwtable) AS (
  SELECT 'DWA' FROM dual UNION ALL
  SELECT 'DWB' FROM dual UNION ALL
  SELECT 'DWC' FROM dual

)--> Tabelle mit einem Spalte (Liste)

SELECT title, 
    (SELECT LISTAGG (dwtable, ', ' ) WITHIN GROUP (ORDER BY dwtable)
     FROM dwtables
    WHERE REGEXP_LIKE (r.querytext, '(^|\s)'||dwtables.dwtable||'(\s|$)', 'i')) AS dwtables

 FROM Reports r;

【讨论】:

  • 一些可能会欺骗您的文字扫描方法的示例:select /* DWA */ * from comple_other_table;select * from comple_other_table DWB;select DWC from comple_other_table;
猜你喜欢
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-22
  • 2011-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多