【问题标题】:Optimize this query please [closed]请优化此查询[关闭]
【发布时间】:2013-10-07 09:40:46
【问题描述】:
SELECT
      B.CE_ID,
      A.PPL_CNTR_ID,
      SUM ( A.NBR_IN ) ENTERS,
      SUM ( A.NBR_OUT ) EXITS,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )
          TS
FROM
      OUTPUTDB.TPPL_CNTR_TRAFFIC A,
      FLUX.V_CE_PPLCNTR B
WHERE
         A.LOG_TS BETWEEN '07-Sep-13' AND '08-Sep-13'
      AND A.PPL_CNTR_ID = B.PPL_CNTR_ID
      AND B.CE_ID IN (SELECT
                        DISTINCT CE_DPN_ID
                   FROM
                        TCE_RLT
                   START WITH
                        CE_PRN_ID = 5798
                   CONNECT BY
                        PRIOR CE_DPN_ID = CE_PRN_ID)
GROUP BY
      B.CE_ID,
      A.PPL_CNTR_ID,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )
ORDER BY
      B.CE_ID,
      A.PPL_CNTR_ID,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )

内部子查询

                   SELECT
                        DISTINCT CE_DPN_ID
                   FROM
                        TCE_RLT
                   START WITH
                        CE_PRN_ID = 5798
                   CONNECT BY
                        PRIOR CE_DPN_ID = CE_PRN_ID

返回970行,但是执行时间很长,请建议任何备用子句或加入,以便它运行得更快。使用的 2 个表只有一列共有,所以我很确定没有发生交叉连接。

【问题讨论】:

  • 请格式化您的问题。可以添加执行计划吗?
  • 与您的问题无关,但这种情况:where a.log_ts between '07-Sep-13' and '08-Sep-13' 依赖于隐式数据类型转换(这是一件非常糟糕的事情),并且在使用不同 NLS 设置从客户端运行时会惨遭失败跨度>

标签: sql optimization oracle10g query-optimization


【解决方案1】:
  1. 不要使用 A.LOG_TS BETWEEN '07-Sep-13' AND '08-Sep-13' 而是使用 TO_DATE('07-09-13' , 'DD-MM-YY')
  2. 尽可能替换 DISTINCT 查询
  3. 删除排序,即排序方式

【讨论】:

  • 使用 TO_DATE() 无疑是个好建议 - 使用 TO_DATE(.., 'MON') 不是,因为这 依赖于某些 NLS 设置。请改用 TO_DATE(..., 'MM')。
  • 我同意弗兰克的观点。 MON 在我的电脑上 10 月份会失败。
  • 是的。我也同意MM是最好的
  • NB 您还可以使用较短的日期文字语法指定日期,如 DATE '2013-09-08'
  • 由于您在 IN 谓词中使用 SELECT DISTINCT 而不是产生结果,因此您可以简单地省略 DISTINCT 并且您将获得相同的正确行为(重复行无效)。当然,CONNECT BY 树查询中的重复结果实际上是不可能开始的。
【解决方案2】:
 A.LOG_TS
  + DECODE ( TO_CHAR ( A.LOG_TS,
                   'mi' ),
           '05', 55
                / 1440,
           '10', 50
                / 1440,
           '15', 45
                / 1440,
           '20', 40
                / 1440,
           '25', 35
                / 1440,
           '30', 30
                / 1440,
           '35', 25
                / 1440,
           '40', 20
                / 1440,
           '45', 15
                / 1440,
           '50', 10
                / 1440,
           '55', 5
                / 1440,
           0 )

太糟糕了,在结果中对 A.LOG_TS 使用正确的转换(例如 SELECT TO_CHAR(A.LOG_TS, 'YYYYMMDDHHMI') TS 或任何其他格式,不使用默认转换)并使用 A.LOG_TS 本身,而不使用无意义的转换GROUP BY 和 ORDER BY 子句。

【讨论】:

    【解决方案3】:
                     SELECT
                        DISTINCT CE_DPN_ID
                   FROM
                        TCE_RLT
                   START WITH
                        CE_PRN_ID = 5798
                   CONNECT BY
                        PRIOR CE_DPN_ID = CE_PRN_ID
    

    如果您可以向 TCE_RLT 添加一列,那么带有索引的“根”ID 将使查询更便宜:

    SELECT CE_DPN_ID
    FROM TCE_RLT
    WHERE ROOT_ID = 5798
    

    这样的字段可以在插入时廉价地计算:

    INSERT INTO TCE_RLT (CE_DPN_ID, CE_PRN_ID,ROOT_ID) 
        VALUES 5798,5798,5798;
    INSERT INTO TCE_RLT (CE_DPN_ID, CE_PRN_ID,ROOT_ID) 
        SELECT 12,34,ROOT_ID FROM TCE_RLT WHERE CE_DPN_ID = 34;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-19
      • 2012-07-03
      • 2017-10-12
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多