【问题标题】:Factor out COALESCE function?排除 COALESCE 功能?
【发布时间】:2009-01-16 18:25:49
【问题描述】:

我有一个很大的查询(不是我写的,但我正在做一些修改)。让我烦恼的一件事是,我在大约四个地方都有相同的 COALESCE 功能。有没有办法解决这个问题,可能是通过从 DUAL 中选择加入?将其分解是否有性能优势?

这里的查询略显粗体:

select 
tbl1.gid
[snip]
         ,COALESCE(t1_end_dt, t6_actl_end_dt,t6_calc_end_dt) perd_end_dt
        ,t1_end_dt
FROM    tbl1
....
JOIN    tbl2               ON (t2_pk          = wpck_wrkr_id  AND
                                            t2_ind_1    ='Y'    AND
        COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) 
        BETWEEN  t2_strt_dt AND t2_end_dt)
JOIN    tbl3                ON (t3_pk               = t2_fk_t3_pk AND
       COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) 
        BETWEEN t3_strt_dt AND t3_end_dt)    
LEFT JOIN tbl4 tbl4_a             ON (tbl4_a.t4_pk         = chkw_wkt_id)
.....
GROUP BY tbl1.gid 
.....
        ,COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt)
        ,COALESCE(tbl4_b.t4_or_id, tbl4_a.t4_or_id, t7_or_id )
        ,t1_end_dt
ORDER BY perd_end_dt

请注意,我已经通过在 SELECT 中将其命名为 pred_end_dt 并在 ORDER BY 中使用该名称来引用它,从而排除了其中一个 COALESCE。

【问题讨论】:

    标签: sql oracle coalesce


    【解决方案1】:

    您应该能够将 GROUP BY 子句中的出现替换为您的列别名 perd_end_dt。但是JOIN条件中的出现不能使用列别名。

    这确实会影响性能。我不认为加入 条件可以按照当前编写的方式使用索引。然而, JOIN条件中只有一个term,所以影响可能很大 轻微。也就是说,涉及t2_pkt2_ind_1 的术语可能已经减少了行集,因此日期比较只需要处理一个小集合。这取决于我们讨论的行数以及数据的分布方式。

    排除COALESCE() 并利用索引的一种方法是创建一个冗余列,该列是该表达式的结果。使用触发器确保在每次插入或更新后它具有正确的值。然后索引列。

    但就像我说的,这可能比它的价值更麻烦。这将是更多的工作,您应该确保此更改将使代码更易于维护、更正确或更快。


    另一种选择是为COALESCE() 表达式定义一个别名 在子查询中。我不知道这些列来自哪些表,因为 你没有用表别名来限定它们。但如果我能假设 都是tbl1的列:

    ...
    FROM (
        SELECT COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) perd_end_dt,
          t1_fk_t2_pk
        FROM tbl1) t1
      JOIN tbl2
        ON (tbl2.t2_pk = t1.t1_fk_t2_pk AND tbl2.t2_ind_1 = 'Y'
          AND t1.perd_end_dt BETWEEN tbl2.t2_strt_dt AND tbl2.t2_end_dt)
    ...
    

    【讨论】:

    • 不幸的是,当我尝试替换 GROUP BY 中的 COALESCE 时,我收到“ORA-00904 Invalid Indentifier”错误。
    • 是的,不知道为什么您认为列别名可以进入 group by。你可以在 Order by tho 中做到这一点。
    • @Mark:我不确定你的恶作剧的根源是什么。至少在 MySQL 中(我的 PC 上有),如果不是 Oracle(我没有),你可以在 GROUP BY 子句中使用列别名。诚然,根据我的 SQL-99 书,这是非标准 SQL 语义。
    【解决方案2】:

    你可以创建一个虚拟表

    (Select Coalesce( all your stuff ....) perdEndDt 
       From [all your tables necessary for this one value])
    

    并将此作为单独的联接表包含在您的 Select SQL 中

      Select [all yr other stuff,
          Z.perdEndDt
      From [Other Tables Joined together]
          Join 
             (Select Coalesce( all your stuff ....) perdEndDt,
                   [other columns necessary for join conditions]
             From [all your tables necessary for this one value]) As Z
             On [Join conditions for Z to other tables]
      Where  [any filter predicates]
      Order By Z.perdEndDt
         ... etc.  
    

    【讨论】:

      【解决方案3】:

      甲骨文有意见吗? (必须这样做。)如果您发现自己在许多不同的地方使用了 COALESCE() 表达式,那么可能值得创建一个 VIEW 并使用它而不是原始表。下面将执行相同的计算,但查询的语法会更简洁,因此更清晰。

      在我看来,“视图”是数据库中的“表”,就像“函数”是程序中的“代码行”一样。每当您发现一堆使用相似逻辑的查询时,请编写一个考虑通用逻辑的视图并改用它。

      【讨论】:

        【解决方案4】:

        也许你可以使用 with 子句?

        with data as
        (
           select COALESCE(t1_end_dt, t6_actl_end_dt,t6_calc_end_dt) perd_end_dt
           ,      .....
           ,      ...
           from   tbl1
        )
        select ...
        from   data
        ,      ....
        where  ....
        

        【讨论】:

          猜你喜欢
          • 2018-05-05
          • 2011-01-31
          • 1970-01-01
          • 2021-02-28
          • 1970-01-01
          • 2011-01-28
          • 2012-11-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多