如何在下面的更新SQL上做SQL调优

时间:2018-07-06 08:48:36

标签: sql oracle performance awr

每个人,最近我参与了一个针对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
    )

enter image description here

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)

1 个答案:

答案 0 :(得分:1)

我要尝试的第一件事是使用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. 我将条件移动为仅将具有特定纳税月份的行从join子句更新到update部分的WHERE子句中。我非常确定它可能留在join子句中,但是我认为如果将它放在更新的WHERE子句中,意图就更清楚了。

我将对新的MERGE语句进行测试,以确保它在做正确的事情(或对其进行修复,直到它起作用为止),然后查看它如何影响性能。

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