首页 > 解决方案 > 如何在以下更新 sql 上进行 SQL 调优

问题描述

大家,最近我在做oracle的一个SQL调优任务,我觉得我遇到了一个非常困难的问题,我什至可以说我被这个问题吓到了,我从DBA那里得到了AWR报告,似乎是AMR的红线SQL需要做一些调整(我已经将这些SQL粘贴在下面,这个sql在SP中)。但是我不知道是什么导致了性能不佳,任何人都可以帮助提供一些关于调整SQL的解决方案或想法?

如果您需要 AWR 提供的更多证据,请告诉我。

提前致谢...

    UPDATE tax_ratio tar
    SET
        ( ecm,
        esm,
        epm,
        ecam,
        update_dt,
        update_by ) = (
            SELECT
                nvl(src_t1.ecm,0) AS ecm,
                nvl(src_t1.esm,0) AS esm,
                nvl(src_t1.epm,0) AS epm,
                nvl(src_t1.ecam,0) AS ecam,
                SYSDATE,
                'ffee_user'
            FROM
                (
                    SELECT
                        city_code,
                        tax_type,
                        company_type,
                        taxpayer,
                        company_group,
                        company_tax_type,
                        SUM(new_tax_current_mth) /12 AS ecm,
                        SUM(new_tax_miss_current_mth) /12 AS esm,
                        SUM(new_tax_get_current_mth) /12 AS epm,
                        SUM(new_tax_special_current_mth) /12 AS ecam
                    FROM
                        tax_ratio
                    WHERE
                        city_code ='001'
                        AND   company_type ='typ_01'
                        AND   tax_mth <= add_months(TO_DATE('08-JUL-2015'),-3)
                        AND   tax_mth >= add_months(TO_DATE('08-JUL-2015'),-14)
                        AND   eff_date =TO_DATE('08-JUL-2015')
                        AND   tax_type = '00'
                    GROUP BY
                        city_code,
                        tax_type,
                        company_type,
                        taxpayer,
                        company_group,
                        company_tax_type
                    HAVING SUM(new_tax_current_mth) <> 0
                           OR SUM(new_tax_miss_current_mth) <> 0
                           OR SUM(new_tax_get_current_mth) <> 0
                           OR SUM(new_tax_special_current_mth) <> 0
                ) src_t1
            WHERE
                tar.city_code = src_t1.city_code
                AND   tar.tax_type = src_t1.tax_type
                AND   tar.company_type = src_t1.company_type
                AND   tar.taxpayer = src_t1.taxpayer
                AND   nvl(tar.company_group,'-99999') = nvl(src_t1.company_group,'-99999')
                AND   (
                    src_t1.ecm IS NOT NULL
                    OR    src_t1.esm IS NOT NULL
                    OR    src_t1.epm IS NOT NULL
                    OR    src_t1.ecam IS NOT NULL
                )
                AND   tar.tax_mth =TO_DATE('08-JUL-2015')
                AND   tar.company_tax_type = src_t1.company_tax_type
        )
WHERE
    tar.city_code ='001'
    AND   tar.company_type ='typ_01'
    AND   tar.tax_mth =TO_DATE('08-JUL-2015')
    AND   EXISTS (
        SELECT
            1
        FROM
            (
                SELECT
                    city_code,
                    tax_type,
                    company_type,
                    taxpayer,
                    company_group,
                    company_tax_type,
                    SUM(new_tax_current_mth) /12 AS ecm,
                    SUM(new_tax_miss_current_mth) /12 AS esm,
                    SUM(new_tax_get_current_mth) /12 AS epm,
                    SUM(new_tax_special_current_mth) /12 AS ecam
                FROM
                    tax_ratio
                WHERE
                    city_code ='001'
                    AND   company_type ='typ_01'
                    AND   tax_mth <= add_months(TO_DATE('08-JUL-2015'),-3)
                    AND   tax_mth >= add_months(TO_DATE('08-JUL-2015'),-14)
                    AND   eff_date =TO_DATE('08-Aug-2015')
                    AND   tax_type = '00'
                GROUP BY
                    city_code,
                    tax_type,
                    company_type,
                    taxpayer,
                    company_group,
                    company_tax_type
                HAVING SUM(new_tax_current_mth) <> 0
                       OR    SUM(new_tax_miss_current_mth) <> 0
                       OR    SUM(new_tax_get_current_mth) <> 0
                       OR    SUM(new_tax_special_current_mth) <> 0
            ) src_t1
        WHERE
            tar.city_code = src_t1.city_code
            AND   tar.tax_type = src_t1.tax_type
            AND   tar.company_type = src_t1.company_type
            AND   tar.taxpayer = src_t1.taxpayer
            AND   nvl(tar.company_group,'-99999') = nvl(src_t1.company_group,'-99999')
            AND   (
                src_t1.ecm IS NOT NULL
                OR    src_t1.esm IS NOT NULL
                OR    src_t1.epm IS NOT NULL
                OR    src_t1.ecam IS NOT NULL
            )
            AND   tar.tax_mth =TO_DATE('08-JUL-2015')
            AND   tar.company_tax_type = src_t1.company_tax_type
    )

在此处输入图像描述

add the EXPLAIN PLAN

PLAN HASH VALUE: 3650439649

----------------------------------------------------------------------------------------------------------------------
| ID  | OPERATION                                | NAME              | ROWS  | BYTES |TEMPSPC| COST (%CPU)| TIME     |
----------------------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT                         |                   |  1698 |   179K|       |  6169K  (1)| 00:08:02 |
|   1 |  UPDATE                                  | TAX_RATIO         |       |       |       |            |          |
|*  2 |   HASH JOIN RIGHT SEMI                   |                   |  1698 |   179K|       |   732K  (1)| 00:00:58 |
|   3 |    VIEW                                  |                   | 39251 |  1111K|       |   371K  (2)| 00:00:29 |
|*  4 |     FILTER                               |                   |       |       |       |            |          |
|   5 |      SORT GROUP BY                       |                   | 39251 |  2414K|   100M|   371K  (2)| 00:00:29 |
|*  6 |       TABLE ACCESS FULL                  | TAX_RATIO         |  1140K|    68M|       |   365K  (2)| 00:00:29 |
|*  7 |    TABLE ACCESS FULL                     | TAX_RATIO         |   207K|    15M|       |   361K  (1)| 00:00:29 |
|   8 |   VIEW                                   |                   |     1 |    81 |       |   484   (1)| 00:00:01 |
|*  9 |    FILTER                                |                   |       |       |       |            |          |
|  10 |     SORT GROUP BY                        |                   |     1 |    63 |       |   484   (1)| 00:00:01 |
|* 11 |      FILTER                              |                   |       |       |       |            |          |
|* 12 |       TABLE ACCESS BY INDEX ROWID BATCHED| TAX_RATIO         |     1 |    63 |       |   483   (0)| 00:00:01 |
|* 13 |        INDEX RANGE SCAN                  | TAX_RATIO_TAXPAYER_IDX |   544 |       |       |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

PREDICATE INFORMATION (IDENTIFIED BY OPERATION ID):
---------------------------------------------------

   2 - ACCESS("TAR"."CITY_CODE"="SRC_T1"."CITY_CODE" AND "TAR"."TAX_TYPE"="SRC_T1"."TAX_TYPE" AND 
              "TAR"."COMPANY_TYPE"="SRC_T1"."COMPANY_TYPE" AND "TAR"."TAXPAYER"="SRC_T1"."TAXPAYER" AND 
              NVL("TAR"."COMPANY_GROUP",'-99999')=NVL("SRC_T1"."COMPANY_GROUP",'-99999') AND "TAR"."COMPANY_TAX_TYPE"="SRC_T1"."COMPANY_TAX_TYPE")
   4 - FILTER((SUM("NEW_TAX_CURRENT_MTH")<>0 OR SUM("NEW_TAX_MISS_CURRENT_MTH")<>0 OR SUM("NEW_TAX_GET_CURRENT_MTH")<>0 OR SUM("NEW_TAX_SPECIAL_CURRENT_MTH")<>0) AND 
              (SUM("NEW_TAX_CURRENT_MTH")/12 IS NOT NULL OR SUM("NEW_TAX_MISS_CURRENT_MTH")/12 IS NOT NULL OR SUM("NEW_TAX_GET_CURRENT_MTH")/12 IS NOT NULL OR 
              SUM("NEW_TAX_SPECIAL_CURRENT_MTH")/12 IS NOT NULL))
   6 - FILTER("COMPANY_TYPE"='LIMIT' AND "TAX_TYPE"='00' AND "TAX_MTH">=TO_DATE(' 2017-03-31 00:00:00', 
              'SYYYY-MM-DD HH24:MI:SS') AND "TAX_MTH"<=TO_DATE(' 2018-02-28 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') AND 
              "CITY_CODE"='001' AND "NEW_TAX_MISS_CURRENT_MTH"=TO_DATE(' 2200-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'))
   7 - FILTER("TAR"."TAX_MTH"=TO_DATE(' 2018-05-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') AND 
              "TAR"."COMPANY_TYPE"='LIMIT' AND "TAR"."CITY_CODE"='001')
   9 - FILTER((SUM("NEW_TAX_CURRENT_MTH")<>0 OR SUM("NEW_TAX_MISS_CURRENT_MTH")<>0 OR SUM("NEW_TAX_GET_CURRENT_MTH")<>0 OR SUM("NEW_TAX_SPECIAL_CURRENT_MTH")<>0) AND 
              (SUM("NEW_TAX_CURRENT_MTH")/12 IS NOT NULL OR SUM("NEW_TAX_MISS_CURRENT_MTH")/12 IS NOT NULL OR SUM("NEW_TAX_GET_CURRENT_MTH")/12 IS NOT NULL OR 
              SUM("NEW_TAX_SPECIAL_CURRENT_MTH")/12 IS NOT NULL))
  11 - FILTER(:B1=TO_DATE(' 2018-05-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') AND :B2='LIMIT' AND :B3='00' AND 
              :B4='001')
  12 - FILTER("COMPANY_TYPE"='LIMIT' AND "COMPANY_TAX_TYPE"=:B1 AND "TAX_TYPE"='00' AND "TAX_MTH">=TO_DATE(' 
              2017-03-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') AND "TAX_MTH"<=TO_DATE(' 2018-02-28 00:00:00', 'SYYYY-MM-DD 
              HH24:MI:SS') AND NVL("COMPANY_GROUP",'-99999')=NVL(:B2,'-99999') AND "CITY_CODE"='001' AND "NEW_TAX_MISS_CURRENT_MTH"=TO_DATE(' 
              2200-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'))
  13 - ACCESS("TAXPAYER"=:B1)

标签: sqloracleperformanceawr

解决方案


我要尝试的第一件事是使用 MERGE 语句而不是 UPDATE 语句 - 这让我想起了,因为您在 where 子句的 set 子句中有效地重复子查询。

我认为您的 UPDATE 可以重写为:

MERGE INTO tax_ratio tgt
  USING (SELECT city_code,
                tax_type,
                company_type,
                taxpayer,
                company_group,
                company_tax_type,
                SUM(new_tax_current_mth) / 12 AS ecm,
                SUM(new_tax_miss_current_mth) / 12 AS esm,
                SUM(new_tax_get_current_mth) / 12 AS epm,
                SUM(new_tax_special_current_mth) / 12 AS ecam
         FROM   tax_ratio
         WHERE  city_code = '001'
         AND    company_type = 'typ_01'
         AND    tax_mth <= add_months(to_date('08-JUL-2015', 'dd-MON-yyyy', 'nls_date_language = english'), -3)
         AND    tax_mth >= add_months(to_date('08-JUL-2015', 'dd-MON-yyyy', 'nls_date_language = english'), -3)
         AND    eff_date = to_date('08-JUL-2015', 'dd-MON-yyyy', 'nls_date_language = english')
         AND    tax_type = '00'
         GROUP  BY city_code,
                   tax_type,
                   company_type,
                   taxpayer,
                   company_group,
                   company_tax_type
         HAVING SUM(new_tax_current_mth) <> 0 
                OR SUM(new_tax_miss_current_mth) <> 0
                OR SUM(new_tax_get_current_mth) <> 0
                OR SUM(new_tax_special_current_mth) <> 0)) src
  ON (tgt.city_code = src.city_code
      AND    tgt.tax_type = src.tax_type
      AND    tgt.company_type = src.company_type
      AND    tgt.taxpayer = src.taxpayer
      AND    NVL(tgt.company_group, '-99999') = NVL(src.company_group, '-99999')
      --AND    COALESCE(src.ecm, src.esm, src.epm, src.ecam) IS NOT NULL -- unnecessary, since your having clause excludes rows where all are null anyway
      AND    tgt.company_tax_type = src.company_tax_type)
WHEN MATCHED THEN
  UPDATE SET tgt.ecm = NVL(src.ecm, 0),
             tgt.esm = NVL(src.esm, 0),
             tgt.epm = NVL(src.epm, 0),
             tgt.ecam = NVL(src.ecam, 0),
             tgt.update_dt = SYSDATE,
             tgt.update_by = 'ffee_user')
  WHERE  tgt.tax_mth = to_date('08-JUL-2015', 'dd-MON-yyyy', 'nls_date_language = english');

笔记:

  1. 我将其更改to_dates()为包含格式掩码(否则,如果您的 NLS_DATE_FORMAT nls 参数已更改,to_date()则会失败),并且由于您使用“JUL”作为月份,因此附加的第三个参数将日期作为字符串转换 nls 设置独立(例如,如果您的 NLS_DATE_FORMAT nls 参数设置JUL为不是有效的短月,to_date()如果未设置第三个参数,则会失败)。 您可以通过将日期作为数字传递来避免使用第三个参数,例如to_date('05/07/2015', 'dd/mm/yyyy').
  2. 我改为and ecm is not null and esm is not null and ...使用COALESCE,因为它返回列表中的第一个非空值。这样你的支票就变成了and COALESCE(ecm, esm, ...) is not null
  3. 实际上并不需要 COALESCE,因为您的 HAVING 子句有效地排除了所有值为 NULL 和 0 的行。
  4. 用于使子查询相关的谓词成为目标表和源子查询之间的连接条件,这意味着您不再需要之前在相关子查询中拥有的外部查询。
  5. 我将条件移动到仅将具有特定纳税月份的行从连接子句更新到更新部分的 WHERE 子句中。我很确定它可以留在 join 子句中,但我认为如果将其放在更新的 WHERE 子句中,意图会更清楚。

我会测试新的 MERGE 语句以确保它做正确的事情(或修复它直到它正确),然后看看它如何影响性能。

如果它仍然作为 AWR 中的问题陈述弹出,那么我将进一步研究如何调整它;可能需要更新/附加索引,可能需要物化视图等。


推荐阅读