【问题标题】:More efficient way to write multi-tier sql statement更高效的多层sql语句编写方式
【发布时间】:2025-12-26 19:30:12
【问题描述】:

我希望以更有效的方式编写一个 8 层查询。目前我正在使用这样的 with 语句:

    with ffdepend as  (
    SELECT DISTINCT ATR1.PARENT_N_VALUE col1, ATR1.CHILD_N_VALUE col2, ATR2.CHILD_N_VALUE col3, 
    ATR3.CHILD_N_VALUE col4, ATR4.CHILD_N_VALUE col5, ATR5.CHILD_N_VALUE col6, ATR6.CHILD_N_VALUE 
    col7, ATR7.CHILD_N_VALUE col8
    FROM ADDTL_TYPE_REL ATR1, ADDTL_TYPE_REL ATR2, ADDTL_TYPE_REL ATR3, ADDTL_TYPE_REL ATR4, 
    ADDTL_TYPE_REL ATR5, ADDTL_TYPE_REL ATR6, ADDTL_TYPE_REL ATR7
    WHERE ATR1.CHILD_N_VALUE = ATR2.parent_n_value
    AND ATR2.CHILD_N_VALUE = ATR3.parent_n_value
    AND ATR3.CHILD_N_VALUE = ATR4.parent_n_value
    AND ATR4.CHILD_N_VALUE = ATR5.parent_n_value
    AND ATR5.CHILD_N_VALUE = ATR6.parent_n_value
    AND ATR6.CHILD_N_VALUE = ATR7.parent_n_value
    AND ATR1.PARENT_FIELD_ID = 3934--highest dependency
    AND ATR1.CHILD_FIELD_ID = 3935--one level down
    AND ATR2.CHILD_FIELD_ID = 3936--two levels down
    AND ATR3.CHILD_FIELD_ID = 3937--three levels down
    AND ATR4.CHILD_FIELD_ID = 3938--four levels down
    AND ATR5.CHILD_FIELD_ID = 3939--five levels down
    AND ATR6.CHILD_FIELD_ID = 3940--six levels down
    AND ATR7.CHILD_FIELD_ID = 3941--seven levels down
    Order by col1, col2, col3, col4, col5, col6, col7, col8
    )
    select distinct (select name from addtl_type  where id = f.col1 and addtl_type.is_active = 1) as col1, 
            (select name from addtl_type where id = f.col2 and addtl_type.is_active = 1) as col2,
            (select name from addtl_type where id = f.col3 and addtl_type.is_active = 1) as col3,
            (select name from addtl_type where id = f.col4 and addtl_type.is_active = 1) as col4,
            (select name from addtl_type where id = f.col5 and addtl_type.is_active = 1) as col5,
            (select name from addtl_type where id = f.col6 and addtl_type.is_active = 1) as col6,
            (select name from addtl_type where id = f.col7 and addtl_type.is_active = 1) as col7,
            (select name from addtl_type where id = f.col8 and addtl_type.is_active = 1) as col8
    from ffdepend f;

我知道这里有很多变量,基于返回值的数量将决定运行时间。目前,这需要一个多小时。只是想看看是否有人知道一种更有效的方式来写这个。我对 sql 相当陌生,并希望获得一些输入。

如果还需要更多信息,请告诉我。 谢谢大家。 桑尼

这是 8 层的一些示例数据。只是为了展示一些东西:

 Product Quality Issue  Yes Yes Yes Yes Yes Yes No
 Product Quality Issue  Yes Yes Yes Yes No  Yes Yes
 Product Quality Issue  Yes Yes No  No  Yes Yes No
 Product Quality Issue  Yes No  Yes No  No  No Yes
 Product Quality Issue  Yes No  No  Yes Yes Yes No
 Product Quality Issue  No  Yes Yes No  No  No Yes
 Product Quality Issue  No  Yes No  No  Yes No No
 Product Quality Issue  No  No  Yes No  No  No Yes
 Product Quality Issue  No  No  No  Yes Yes Yes No

这是产生与上述相同结果的原始查询:

 SELECT DISTINCT AT1.NAME col1, AT2.NAME col2, AT3.NAME col3, AT4.NAME col4, 
 AT5.NAME col5, AT6.NAME col6, AT7.NAME col7, AT8.NAME col8
 FROM ADDTL_TYPE_REL ATR1, ADDTL_TYPE_REL ATR2, ADDTL_TYPE_REL ATR3, 
 ADDTL_TYPE_REL ATR4, ADDTL_TYPE_REL ATR5, ADDTL_TYPE_REL ATR6, 
 ADDTL_TYPE_REL ATR7,
 ADDTL_TYPE AT1, ADDTL_TYPE AT2, ADDTL_TYPE AT3, ADDTL_TYPE AT4, ADDTL_TYPE 
 AT5, ADDTL_TYPE AT6, ADDTL_TYPE AT7, ADDTL_TYPE AT8
 WHERE ATR1.CHILD_FIELD_ID = ATR2.PARENT_FIELD_ID
 AND ATR2.CHILD_FIELD_ID = ATR3.PARENT_FIELD_ID
 AND ATR3.CHILD_FIELD_ID = ATR4.PARENT_FIELD_ID
 AND ATR4.CHILD_FIELD_ID = ATR5.PARENT_FIELD_ID
 AND ATR5.CHILD_FIELD_ID = ATR6.PARENT_FIELD_ID
 AND ATR6.CHILD_FIELD_ID = ATR7.PARENT_FIELD_ID
 AND ATR1.PARENT_N_VALUE = AT1.ID
 AND ATR1.CHILD_N_VALUE = AT2.ID
 AND ATR2.CHILD_N_VALUE = AT3.ID
 AND ATR3.CHILD_N_VALUE = AT4.ID
 AND ATR4.CHILD_N_VALUE = AT5.ID
 AND ATR5.CHILD_N_VALUE = AT6.ID
 AND ATR6.CHILD_N_VALUE = AT7.ID
 AND ATR7.CHILD_N_VALUE = AT8.ID
 AND AT1.IS_ACTIVE = 1
 AND AT2.IS_ACTIVE = 1
 AND AT3.IS_ACTIVE = 1
 AND AT4.IS_ACTIVE = 1
 AND AT5.IS_ACTIVE = 1
 AND AT6.IS_ACTIVE = 1
 AND AT7.IS_ACTIVE = 1
 AND AT8.IS_ACTIVE = 1
 AND ATR1.PARENT_FIELD_ID = 3934--highest dependency
 AND ATR1.CHILD_FIELD_ID = 3935--one level down
 AND ATR2.CHILD_FIELD_ID = 3936--two levels down
 AND ATR3.CHILD_FIELD_ID = 3937--three levels down
 AND ATR4.CHILD_FIELD_ID = 3938--four levels down
 AND ATR5.CHILD_FIELD_ID = 3939--five levels down
 AND ATR6.CHILD_FIELD_ID = 3940--six levels down
 AND ATR7.CHILD_FIELD_ID = 3941--seven levels down
 Order by col1, col2, col3, col4, col5, col6, col7, col8;

【问题讨论】:

  • 请提供示例数据、期望的结果,并说明您使用的 Oracle 版本。
  • @GordonLinoff-我正在使用 Oracle11。我在上面的原始问题部分添加了一些示例数据。
  • 您的查询有 两个 表,并且您发布了 一个 数据集。所以我猜这应该是期望的输出。您还需要向我们提供一组准确的输入数据。
  • @APC - 你是对的,我正在访问两个表,但我有该表的多个实例。例如,对于 addtl_type_rel 我有该表的 7 个实例,因此我可以生成 8 列(addtl 类型用于链接这些表以显示实际名称)。我现在还添加了没有 with 语句的原始查询。希望这能说明问题。
  • 你是自加入 ADDTL_TYPE_REL 八次,你应该使用递归查询(connect by prior child_n_value = parent_n_value)。然后使用查找表和数据透视表加入 ONCE。但是不看数据就很难回答,能不能给我们看一些ADDTL_TYPE_REL(PARENT_FIELD_ID, PARENT_N_VALUE, CHILD_FIELD_ID, CHILD_N_VALUE)的行?

标签: sql oracle performance query-optimization


【解决方案1】:

有趣且困难的问题,至少对我来说是这样:) 您正在从分层数据中寻找不同的查找值组合。我尝试了几种方法,这是我可以做的:

with t as (
  select parent_field_id pid, parent_n_value pnv, 
         child_field_id  cid, child_n_value cnv, name
    from addtl_type_rel 
    left join addtl_type on child_n_value = addtl_type.id and is_active = 1
    where child_field_id between 3935 and 3941)
select (select name from addtl_type where id = a.pnv) root, path
  from (
    select distinct connect_by_root(pnv) pnv, 
           sys_connect_by_path(rpad(nvl(name, '?'), 3, ' '), ' - ') path
      from t where connect_by_isleaf = 1 
      start with pid = 3934 
      connect by prior cnv = pnv and pid = prior pid + 1) a

dbfiddle

它不会将值放在不同的列中,但我们可以很容易地用substring 来剪切它们。更重要的是它是否更快。起初我想尽可能地过滤来自addtl_type_rel的数据,加入一次addtl_type。然后是主要部分,分层查询,它只过滤叶子节点并找到不同的路径。

(child_n_value, parent_field_id) 上的索引对connect by 很有用。我假设我们应该基于这个序列 3934-3935-...-3941。我只是试图避免来自两个相同表的所有这些子选择,也许这会对你有所帮助。

【讨论】:

  • 如何在这里使用子字符串来分隔列?
  • 所以主要任务(更快的查询)已经完成 :) 我将尝试找到解决方案以在单独的列中显示数据,但我不能保证,正如您可能注意到的那样,我并不总是有时间,所以也许更好地提出新问题。最简单的是在上述结果上使用 substr 或 regexp_substr。你能判断值是否总是是-否吗?并且总是有特定的列数(不一定是八列,而是已知的)?
  • -是的,这个查询速度快得令人难以置信。 :-) 我非常感谢。在此查询中,它们将为是和否。我真的很感谢你在这方面的帮助。我可以继续创建一个新问题。同时,我将查找 rexexp 和 substr 函数。查询最多 11 层,它遵循相同的格式。第一列与给出的结果相同,其余(10 列)是和否。
  • 那么简单的substr 就可以了:dbfiddle