zoukankan      html  css  js  c++  java
  • merge into sql优化

    今天网友说他的merge into sql跑了15分钟了还没有跑出数据,问我能不能优化一下,我让他把sql和sql的执行计划发过来

    merge into F_Sal_P_Camp_Samp_Cust_Data A
    using (select CUST_ID,
    CUST_MNGR_ID,
    ORGCODE From (
    SELECT t.CUST_ID,
    t.CUST_MNGR_ID,
    t.ORGCODE,
    ROW_NUMBER() OVER(PARTITION BY t.cust_id ORDER BY t.BELG_RELA_TYPE asc,t.open_percent DESC) AS RN
    From F_Sal_P_Camp_Samp_Cust_Data a
    INNER JOIN (
    SELECT T.CUST_ID,T.CUST_MNGR_ID,T.BELG_RELA_TYPE,T.OPEN_PERCENT,OM.ORGSEQ,OM.ORGCODE
    FROM O_F_PTY_P_CUST_BELG_INFO T
    INNER JOIN OM_EMPLOYEE EMP
    ON t.CUST_MNGR_ID = EMP.EMPCODE
    and emp.empname not like '%虚拟%'
    INNER JOIN AC_OPERATOR opr
    ON emp.operatorid = opr.operatorid
    AND opr.status IN ('running', 'openuse')
    INNER JOIN OM_ORGANIZATION OM
    ON EMP.ORGADMINID = OM.ORGID
    ) t ON A.CUST_ID=T.CUST_ID
    where A.activity_id = '20150114-1003' AND t.orgseq like '.10001.'||'%'
    and A.used_org = 'BS001'
    and A.execute_man is null
    ) where rn = 1
    ) t1
    on (A.CUST_ID = T1.cust_id AND A.activity_id = '20150114-1003')
    when matched then
    update
    set A.execute_man = T1.CUST_MNGR_ID,
    A.task_stat = '3',
    a.Used_Org = T1.ORGCODE
    WHERE A.activity_id = '20150114-1003'

    5 - filter("RN"=1)

    6 - filter(ROW_NUMBER() OVER ( PARTITION BY "T"."CUST_ID" ORDER BY
    "T"."BELG_RELA_TYPE",INTERNAL_FUNCTION("T"."OPEN_PERCENT") DESC )<=1)
    12 - filter("A"."USED_ORG"='BS001' AND "A"."EXECUTE_MAN" IS NULL)
    13 - access("A"."ACTIVITY_ID"='20150114-1003')
    15 - access("A"."CUST_ID"="T"."CUST_ID")
    16 - filter("EMP"."EMPNAME" NOT LIKE '%虚拟%' AND "EMP"."EMPNAME" IS NOT NULL)
    17 - access("T"."CUST_MNGR_ID"="EMP"."EMPCODE")
    18 - filter("OPR"."STATUS"='openuse' OR "OPR"."STATUS"='running')
    19 - access("EMP"."OPERATORID"="OPR"."OPERATORID")
    20 - access("EMP"."ORGADMINID"="OM"."ORGID")
    21 - filter("OM"."ORGSEQ" LIKE '.10001.%')
    22 - access("A"."ACTIVITY_ID"='20150114-1003')
    23 - filter("A"."CUST_ID"="CUST_ID")

    看了这个执行计划,发现全都是NL连接,我让他查询相应sql返回的行数

    F_Sal_P_Camp_Samp_Cust_Data 返回20w

    select count(*) from O_F_PTY_P_CUST_BELG_INFO T; 369983
    select count(*) from OM_EMPLOYEE EMP where emp.empname not like '%虚拟%; 6353
    select count(*) from AC_OPERATOR opr where opr.status IN ('running', 'openuse'); 3234
    select count(*) from OM_ORGANIZATION OM; 1079

    发现返回的行数都不少,走NL连接一定有问题,应该走hash join,而且执行计划上看统计信息也是不对的

    由于网友是开发没有dba权限,所以不能 重新统计信息,所以只能使用hint,添加了hint强制走hash,运行时间是19秒,网友说可以了,我在帮他看看

    merge /*+ use_hash(A,t1) leading(A) */ into F_Sal_P_Camp_Samp_Cust_Data A
    using (select CUST_ID,
    CUST_MNGR_ID,
    ORGCODE From (
    SELECT /*+ use_hash(A,t) leading(a) */t.CUST_ID,
    t.CUST_MNGR_ID,
    t.ORGCODE,
    ROW_NUMBER() OVER(PARTITION BY t.cust_id ORDER BY t.BELG_RELA_TYPE asc,t.open_percent DESC) AS RN
    From F_Sal_P_Camp_Samp_Cust_Data a
    INNER JOIN (
    SELECT T.CUST_ID,T.CUST_MNGR_ID,T.BELG_RELA_TYPE,T.OPEN_PERCENT,OM.ORGSEQ,OM.ORGCODE
    FROM O_F_PTY_P_CUST_BELG_INFO T
    INNER JOIN OM_EMPLOYEE EMP
    ON t.CUST_MNGR_ID = EMP.EMPCODE
    and emp.empname not like '%虚拟%'
    INNER JOIN AC_OPERATOR opr
    ON emp.operatorid = opr.operatorid
    AND opr.status IN ('running', 'openuse')
    INNER JOIN OM_ORGANIZATION OM
    ON EMP.ORGADMINID = OM.ORGID
    ) t ON A.CUST_ID=T.CUST_ID
    where A.activity_id = '20150114-1003' AND t.orgseq like '.10001.'||'%'
    and A.used_org = 'BS001'
    and A.execute_man is null
    ) where rn = 1
    ) t1
    on (A.CUST_ID = T1.cust_id AND A.activity_id = '20150114-1003')
    when matched then
    update
    set A.execute_man = T1.CUST_MNGR_ID,
    A.task_stat = '3',
    a.Used_Org = T1.ORGCODE
    WHERE A.activity_id = '20150114-1003'

    这个sql中间嵌套了很多层,这是中间那层,这个sql跑了2:30秒

    SELECT T.CUST_ID,T.CUST_MNGR_ID,T.BELG_RELA_TYPE,T.OPEN_PERCENT,OM.ORGSEQ,OM.ORGCODE
    FROM O_F_PTY_P_CUST_BELG_INFO T
    INNER JOIN OM_EMPLOYEE EMP
    ON t.CUST_MNGR_ID = EMP.EMPCODE
    and emp.empname not like '%虚拟%'
    INNER JOIN AC_OPERATOR opr
    ON emp.operatorid = opr.operatorid
    AND opr.status IN ('running', 'openuse')
    INNER JOIN OM_ORGANIZATION OM
    ON EMP.ORGADMINID = OM.ORGID

    select count(*) from O_F_PTY_P_CUST_BELG_INFO T; 369983
    select count(*) from OM_EMPLOYEE EMP where emp.empname not like '%虚拟%; 6353
    select count(*) from AC_OPERATOR opr where opr.status IN ('running', 'openuse'); 3234
    select count(*) from OM_ORGANIZATION OM; 1079

    看了这个执行计划,看了sql返回的行数,发现非常好,走的hash连接是对的,那为什么走的慢呢,因为所有的表走的都是全表扫描,没有走索引,但是能走索引的都是小表,没有影响,

    真正有影响的是T表,T表30多w,而且没有筛选条件,只能改写sql了

    with X as ( select /*+ materialize parallel(T,6) */ T.CUST_ID,T.CUST_MNGR_ID,T.BELG_RELA_TYPE,T.OPEN_PERCENT from O_F_PTY_P_CUST_BELG_INFO T)
    SELECT X.CUST_ID,X.CUST_MNGR_ID,X.BELG_RELA_TYPE,X.OPEN_PERCENT,OM.ORGSEQ,OM.ORGCODE
    FROM X
    INNER JOIN OM_EMPLOYEE EMP
    ON X.CUST_MNGR_ID = EMP.EMPCODE
    and emp.empname not like '%虚拟%'
    INNER JOIN AC_OPERATOR opr
    ON emp.operatorid = opr.operatorid
    AND opr.status IN ('running', 'openuse')
    INNER JOIN OM_ORGANIZATION OM
    ON EMP.ORGADMINID = OM.ORGID

    sql改写之后跑了1分钟,快了好多

    整个sql跑起来,在10秒左右,改到这里就可以了

    本人qq 343548233,期待和各位交流,一起探讨sql,提高sql性能

  • 相关阅读:
    1282 回文数猜想
    1279 验证角谷猜想
    1205 吃糖果
    1201 18岁生日
    1106 排序
    2024 C语言合法标识符
    196 让气球飞吧
    1001 Sum Problem
    if语句
    三元运算符
  • 原文地址:https://www.cnblogs.com/SUN-PH/p/4226619.html
Copyright © 2011-2022 走看看