• Oracle关于WINDOW SORT PUSHED RANK一些探究猜想


    Oracle关于WINDOW SORT PUSHED RANK一些探究猜想

    最近遇到一条SQL,开发让我做出优化

    with tmp as
     (select *
        from T_VERIFY_APPLY ty
       where ty.result_id in ('11', '12')
         and ty.sender_id = 'SWBHAP'
         and ty.create_time >= ADD_MONTHS(sysdate, -12)
         and ty.create_time <= sysdate),
    tmp1 as
     (select count(*) as month_call_num
        from tmp
       where to_char(sysdate, 'yyyy/mm') = to_char(tmp.create_time, 'yyyy/mm')),
    tmp2 as
     (select count(*) as last_year_month
        from tmp
       where to_char(ADD_MONTHS(sysdate, -12), 'yyyy/mm') =
             to_char(tmp.create_time, 'yyyy/mm')),
    tmp3 as
     (select count(*) as month_on_month
        from tmp
       where to_char(ADD_MONTHS(sysdate, -1), 'yyyy/mm') =
             to_char(tmp.create_time, 'yyyy/mm')),
    tmp4 as
     (select count(*) as this_year
        from tmp
       where to_char(sysdate, 'yyyy') = to_char(tmp.create_time, 'yyyy')),
    tmp5 as
     (select count(*) as past_year_num
        from tmp
       where to_char(ADD_MONTHS(sysdate, -12), 'yyyy') =
             to_char(tmp.create_time, 'yyyy')),
    temp as
     (select tl.entry_id,
             ty.create_time,
             ty.sender_id,
             row_number() over(partition by tl.entry_id order by 1) rn
        from t_verify_apply_list tl --418M
        left join T_VERIFY_APPLY ty --14M
          on ty.head_seq_no = tl.head_seq_no
       where ty.result_id in ('11', '12')
         and ty.sender_id = 'SWBHAP'
         and ty.create_time >= ADD_MONTHS(sysdate, -12)
         and ty.create_time <= sysdate),
    tmp6 as
     (select count(temp.entry_id) month_goods_num
        from temp
       where temp.rn = 1
         and to_char(sysdate, 'yyyy/mm') = to_char(temp.create_time, 'yyyy/mm')),
    tmp7 as
     (select count(temp.entry_id) month_goods_with
        from temp
       where temp.rn = 1
         and to_char(ADD_MONTHS(sysdate, -12), 'yyyy/mm') =
             to_char(temp.create_time, 'yyyy/mm')),
    tmp8 as
     (select count(temp.entry_id) this_month_goods_with
        from temp
       where temp.rn = 1
         and to_char(ADD_MONTHS(sysdate, -1), 'yyyy') =
             to_char(temp.create_time, 'yyyy')),
    tmp9 as
     (select count(temp.entry_id) this_year_goods_with
        from temp
       where temp.rn = 1
         and to_char(sysdate, 'yyyy') = to_char(temp.create_time, 'yyyy')),
    tmp10 as
     (select count(temp.entry_id) year_goods_than
        from temp
       where temp.rn = 1
         and to_char(ADD_MONTHS(sysdate, -12), 'yyyy') =
             to_char(temp.create_time, 'yyyy'))
    SELECT tmp1.month_call_num,
           tmp2.last_year_month,
           tmp3.month_on_month,
           tmp4.this_year,
           tmp5.past_year_num,
           tmp6.month_goods_num,
           tmp7.month_goods_with,
           tmp8.this_month_goods_with,
           tmp9.this_year_goods_with,
           tmp10.year_goods_than
      from tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10;
    View Code

    别看SQL很长,实际上“架构”很简单。我给优化成如下SQL了。

    with tmp as
     (select count(case when to_char(ty.create_time, 'yyyy/mm') = to_char(sysdate, 'yyyy/mm') then 1 else null end) month_call_num,                        
             count(case when to_char(ty.create_time, 'yyyy/mm') = to_char(ADD_MONTHS(sysdate, -12), 'yyyy/mm') then 1 else null end) last_year_month,    
             count(case when to_char(ty.create_time, 'yyyy/mm') = to_char(ADD_MONTHS(sysdate, -1), 'yyyy/mm') then 1 else null end) month_on_month,        
             count(case when to_char(ty.create_time, 'yyyy') = to_char(sysdate, 'yyyy') then 1 else null end) this_year,                                
             count(case when to_char(ty.create_time, 'yyyy') = to_char(ADD_MONTHS(sysdate, -12), 'yyyy') then 1 else null end) past_year_num            
        from T_VERIFY_APPLY ty
       where ty.result_id in ('11', '12')
         and ty.sender_id = 'SWBHAP'
         and ty.create_time >= ADD_MONTHS(sysdate, -12)
         and ty.create_time <= sysdate),
    temp as
     (select count(case when to_char(create_time, 'yyyy/mm') = to_char(sysdate, 'yyyy/mm') then 1 else null end) month_goods_num,                    
             count(case when to_char(create_time, 'yyyy/mm') = to_char(ADD_MONTHS(sysdate, -12), 'yyyy/mm') then 1 else null end) month_goods_with,    
             count(case when to_char(create_time, 'yyyy') = to_char(ADD_MONTHS(sysdate, -1), 'yyyy') then 1 else null end) this_month_goods_with,    
             count(case when to_char(create_time, 'yyyy') = to_char(sysdate, 'yyyy') then 1 else null end) this_year_goods_with,                    
             count(case when to_char(create_time, 'yyyy') = to_char(ADD_MONTHS(sysdate, -12), 'yyyy')  then 1 else null end) year_goods_than
        from ( select /*+ no_merge */ create_time from  (
        select ty.create_time,
                     row_number() over(partition by tl.entry_id order by 1) rn
                from t_verify_apply_list tl,T_VERIFY_APPLY ty
                  where ty.head_seq_no = tl.head_seq_no
               and ty.result_id in ('11', '12')
                 and ty.sender_id = 'SWBHAP'
                 and ty.create_time >= ADD_MONTHS(sysdate, -12)
                 and ty.create_time <= sysdate
                 and tl.entry_id is not null
        )
       where rn = 1) )
    SELECT tmp.month_call_num,
           tmp.last_year_month,
           tmp.month_on_month,
           tmp.this_year,
           tmp.past_year_num,
           temp.month_goods_num,
           temp.month_goods_with,
           temp.this_month_goods_with,
           temp.this_year_goods_with,
           temp.year_goods_than
      from tmp, temp;
    View Code

    两者等价,但是会引起wrong result的bug出来,这个后边在单独写一篇另说。

    扯远了。

    拿出改造后SQL中的部分,暂且称之为SQL1。

    select *
      from (select tl.entry_id,
                   ty.create_time,
                   ty.sender_id,
                   row_number() over(partition by tl.entry_id order by ty.create_time) rn
              from t_verify_apply_list tl
              left join T_VERIFY_APPLY ty
                on ty.head_seq_no = tl.head_seq_no
             where ty.result_id in ('11', '12')
               and ty.sender_id = 'SWBHAP'
               and ty.create_time >= ADD_MONTHS(sysdate, -12)
               and ty.create_time <= sysdate)
     where rn = 1;

    将SQL1中rn=1条件改为rn=0,称为SQL0,

    改为rn=10000,称为SQL10000。

    就不一一展示了。

    再使用with as等价改为为SQL_wa如下:(必须使用hint:materialize不然无法将子查询固化为一张“临时表”)

    with tmp as
     (select /*+ materialize */
       tl.entry_id,
       ty.create_time,
       ty.sender_id,
       row_number() over(partition by tl.entry_id order by ty.create_time) rn
        from t_verify_apply_list tl
        left join T_VERIFY_APPLY ty
          on ty.head_seq_no = tl.head_seq_no
       where ty.result_id in ('11', '12')
         and ty.sender_id = 'SWBHAP'
         and ty.create_time >= ADD_MONTHS(sysdate, -12)
         and ty.create_time <= sysdate)
    select * from tmp where tmp.rn = 1;

    其中,SQL1,SQL0,SQL10000只是改变了条件rn的等值判断,实际上暂时称为同一类的语句。

    而SQL_wa只是用with as改造而已,虽然等价但是分为另一类语句。

    探究1:谓词推入?

    执行SQL1之后,看看执行计划:

    Plan hash value: 1267599599
    
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                     |      1 |        |  31360 |00:00:05.53 |   56828 |   1044 |   1044 |       |       |          |         |
    |*  1 |  VIEW                    |                     |      1 |   3093K|  31360 |00:00:05.53 |   56828 |   1044 |   1044 |       |       |          |         |
    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|  65060 |00:00:05.51 |   56828 |   1044 |   1044 |  9396K|  1191K|   97M (1)|    9216 |
    |*  3 |    FILTER                |                     |      1 |        |   3133K|00:00:02.32 |   56793 |      0 |      0 |       |       |          |         |
    |*  4 |     HASH JOIN            |                     |      1 |   3093K|   3133K|00:00:01.92 |   56793 |      0 |      0 |  4112K|  1291K| 5579K (0)|         |
    |*  5 |      TABLE ACCESS FULL   | T_VERIFY_APPLY      |      1 |  34791 |  35430 |00:00:00.03 |    1765 |      0 |      0 |       |       |          |         |
    |   6 |      TABLE ACCESS FULL   | T_VERIFY_APPLY_LIST |      1 |   3093K|   3133K|00:00:00.64 |   55028 |      0 |      0 |       |       |          |         |
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN"=1)
       2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=1)
       3 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       4 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       5 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))

    执行SQL_wa之后,看看执行计划:

    Plan hash value: 129230774
    
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                  | Name                        | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT           |                             |      1 |        |  31364 |00:00:11.56 |   95974 |  66248 |  66239 |       |       |          |         |
    |   1 |  TEMP TABLE TRANSFORMATION |                             |      1 |        |  31364 |00:00:11.56 |   95974 |  66248 |  66239 |       |       |          |         |
    |   2 |   LOAD AS SELECT           |                             |      1 |        |      0 |00:00:10.26 |   75481 |  47860 |  66239 |   530K|   530K|  530K (0)|         |
    |   3 |    WINDOW SORT             |                             |      1 |   3093K|   3133K|00:00:08.77 |   56804 |  47860 |  47851 |   420M|  6773K|   97M (1)|     374K|
    |*  4 |     FILTER                 |                             |      1 |        |   3133K|00:00:02.31 |   56793 |      9 |      0 |       |       |          |         |
    |*  5 |      HASH JOIN             |                             |      1 |   3093K|   3133K|00:00:01.95 |   56793 |      9 |      0 |  4112K|  1291K| 4635K (0)|         |
    |*  6 |       TABLE ACCESS FULL    | T_VERIFY_APPLY              |      1 |  34791 |  35436 |00:00:00.04 |    1765 |      0 |      0 |       |       |          |         |
    |   7 |       TABLE ACCESS FULL    | T_VERIFY_APPLY_LIST         |      1 |   3093K|   3133K|00:00:00.70 |   55028 |      9 |      0 |       |       |          |         |
    |*  8 |   VIEW                     |                             |      1 |   3093K|  31364 |00:00:01.29 |   20487 |  18388 |      0 |       |       |          |         |
    |   9 |    TABLE ACCESS FULL       | SYS_TEMP_0FD9D6B51_7DA5A5E2 |      1 |   3093K|   3133K|00:00:00.91 |   20487 |  18388 |      0 |       |       |          |         |
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       4 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       5 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       6 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))
       8 - filter("TMP"."RN"=1)

    两者执行计划不同,SQL_wa执行时间明显更久一点。

    其中,SQL_wa的执行计划id=3:WINDOW SORT为分析函数(也叫开窗函数)特有的,SQL1的执行计划id=2:WINDOW SORT PUSHED RANK同样也是。

    两者区别在于SQL1的有个PUSHED RANK,表示将row_number() over(partition by tl.entry_id order by ty.create_time)<=1推入视图中(注意是<=,不是=,这点后边在探究)。

    参考链接https://www.modb.pro/db/28980处所说的:

    看起来是因为谓词推入之后SQL1才会比SQL_wa执行的更快。

    但是实际上可能只是类似于谓词推入的技术而已,因为对SQL1使用no_pushed_pred并不会生效使得出现WINDOW SORT,还是会推入。

    select *
      from (select /*+ no_push_pred no_merge */ tl.entry_id,
                   ty.create_time,
                   ty.sender_id,
                   row_number() over(partition by tl.entry_id order by ty.create_time) rn
              from t_verify_apply_list tl
              left join T_VERIFY_APPLY ty
                on ty.head_seq_no = tl.head_seq_no
             where ty.result_id in ('11', '12')
               and ty.sender_id = 'SWBHAP'
               and ty.create_time >= ADD_MONTHS(sysdate, -12)
               and ty.create_time <= sysdate)
     where rn = 1;
    
    
    Plan hash value: 1267599599
    
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                     |      1 |        |  31391 |00:00:05.56 |   56828 |   1045 |   1045 |       |       |          |         |
    |*  1 |  VIEW                    |                     |      1 |   3093K|  31391 |00:00:05.56 |   56828 |   1045 |   1045 |       |       |          |         |
    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|  65123 |00:00:05.54 |   56828 |   1045 |   1045 |  9405K|  1191K|   97M (1)|    9216 |
    |*  3 |    FILTER                |                     |      1 |        |   3135K|00:00:02.40 |   56793 |      0 |      0 |       |       |          |         |
    |*  4 |     HASH JOIN            |                     |      1 |   3093K|   3135K|00:00:01.99 |   56793 |      0 |      0 |  4112K|  1291K| 4601K (0)|         |
    |*  5 |      TABLE ACCESS FULL   | T_VERIFY_APPLY      |      1 |  34791 |  35468 |00:00:00.04 |    1765 |      0 |      0 |       |       |          |         |
    |   6 |      TABLE ACCESS FULL   | T_VERIFY_APPLY_LIST |      1 |   3093K|   3135K|00:00:00.74 |   55028 |      0 |      0 |       |       |          |         |
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN"=1)
       2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=1)
       3 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       4 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       5 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))
    View Code

    不知道除了with as之外怎么阻止推入。,

    探究2:分析函数(开窗函数)推入值对消耗的影响

    从SQL1,SQL0,SQL10000的执行计划分别放在下边做对比。

    SQL1执行计划:

    Plan hash value: 1267599599
    
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                     |      1 |        |  31435 |00:00:05.53 |   56828 |   1046 |   1046 |       |       |          |         |
    |*  1 |  VIEW                    |                     |      1 |   3093K|  31435 |00:00:05.53 |   56828 |   1046 |   1046 |       |       |          |         |
    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|  65213 |00:00:05.52 |   56828 |   1046 |   1046 |  9414K|  1192K|   97M (1)|    9216 |
    |*  3 |    FILTER                |                     |      1 |        |   3138K|00:00:02.32 |   56793 |      0 |      0 |       |       |          |         |
    |*  4 |     HASH JOIN            |                     |      1 |   3093K|   3138K|00:00:01.92 |   56793 |      0 |      0 |  4112K|  1291K| 5579K (0)|         |
    |*  5 |      TABLE ACCESS FULL   | T_VERIFY_APPLY      |      1 |  34791 |  35519 |00:00:00.04 |    1765 |      0 |      0 |       |       |          |         |
    |   6 |      TABLE ACCESS FULL   | T_VERIFY_APPLY_LIST |      1 |   3093K|   3138K|00:00:00.64 |   55028 |      0 |      0 |       |       |          |         |
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN"=1)
       2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=1)
       3 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       4 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       5 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))

    SQL0执行计划:

    Plan hash value: 1267599599
    
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                     |      1 |        |      0 |00:00:10.30 |   56828 |  48295 |  48295 |       |       |          |         |
    |*  1 |  VIEW                    |                     |      1 |   3093K|      0 |00:00:10.30 |   56828 |  48295 |  48295 |       |       |          |         |
    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3138K|00:00:10.00 |   56828 |  48295 |  48295 |   424M|  6802K|   97M (1)|     378K|
    |*  3 |    FILTER                |                     |      1 |        |   3138K|00:00:02.66 |   56793 |      0 |      0 |       |       |          |         |
    |*  4 |     HASH JOIN            |                     |      1 |   3093K|   3138K|00:00:02.22 |   56793 |      0 |      0 |  4112K|  1291K| 5583K (0)|         |
    |*  5 |      TABLE ACCESS FULL   | T_VERIFY_APPLY      |      1 |  34791 |  35523 |00:00:00.03 |    1765 |      0 |      0 |       |       |          |         |
    |   6 |      TABLE ACCESS FULL   | T_VERIFY_APPLY_LIST |      1 |   3093K|   3138K|00:00:00.88 |   55028 |      0 |      0 |       |       |          |         |
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN"=0)
       2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=0)
       3 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       4 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       5 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))

    SQL10000执行计划:

    Plan hash value: 1267599599
    
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                     |      1 |        |      0 |00:00:10.73 |   56828 |  48295 |  48295 |       |       |          |         |
    |*  1 |  VIEW                    |                     |      1 |   3093K|      0 |00:00:10.73 |   56828 |  48295 |  48295 |       |       |          |         |
    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3138K|00:00:10.42 |   56828 |  48295 |  48295 |   424M|  6802K|   97M (1)|     378K|
    |*  3 |    FILTER                |                     |      1 |        |   3138K|00:00:02.54 |   56793 |      0 |      0 |       |       |          |         |
    |*  4 |     HASH JOIN            |                     |      1 |   3093K|   3138K|00:00:02.10 |   56793 |      0 |      0 |  4112K|  1291K| 4600K (0)|         |
    |*  5 |      TABLE ACCESS FULL   | T_VERIFY_APPLY      |      1 |  34791 |  35523 |00:00:00.04 |    1765 |      0 |      0 |       |       |          |         |
    |   6 |      TABLE ACCESS FULL   | T_VERIFY_APPLY_LIST |      1 |   3093K|   3138K|00:00:00.78 |   55028 |      0 |      0 |       |       |          |         |
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN"=10000)
       2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=10000)
       3 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
       4 - access("TY"."HEAD_SEQ_NO"="TL"."HEAD_SEQ_NO")
       5 - filter(("TY"."SENDER_ID"='SWBHAP' AND INTERNAL_FUNCTION("TY"."RESULT_ID") AND "TY"."CREATE_TIME">=ADD_MONTHS(SYSDATE@!,-12) AND
                  "TY"."CREATE_TIME"<=SYSDATE@!))

    这3个执行计划都看id=2步骤的消耗。

    从结果看,SQL0和SQL10000是一样的消耗的,只有SQL1消耗较少。

    一开始我还以为SQL0会秒出,因为不可能存在rn=0的结果,没想到还是没那么智能。

    结合谓词信息:2 - filter(ROW_NUMBER() OVER ( PARTITION BY "TL"."ENTRY_ID" ORDER BY "TY"."CREATE_TIME")<=???)

                -----------------------------------------------------------------------------------------------------------------------------------------------------------------
                | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
                -----------------------------------------------------------------------------------------------------------------------------------------------------------------
    rn=1        |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|  65213 |00:00:05.52 |   56828 |   1046 |   1046 |  9414K|  1192K|   97M (1)|    9216 |
    rn=0        |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3138K|00:00:10.00 |   56828 |  48295 |  48295 |   424M|  6802K|   97M (1)|     378K|
    rn=10000    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3138K|00:00:10.42 |   56828 |  48295 |  48295 |   424M|  6802K|   97M (1)|     378K|
                -----------------------------------------------------------------------------------------------------------------------------------------------------------------

    此处的Buffers均为56828,是由于全表扫描T_VERIFY_APPLY和T_VERIFY_APPLY_LIST导致的。

    其他的Reads和Writes则当rn=1时远小于其他两个,另外两个是一样的消耗。这才是rn=1的时候执行速度比另外两个快的原因。

    由于谓词信息为<=而不是=,猜想由于推入了rn导致在临时表空间中(10046event='direct path write temp',file number=1001)操作的数据量变少。

    也就是说rn的值推入后,根据值的不同控制了在temp文件中物理IO的量的多少,决定了WINDOW SORT PUSHED RANK的速度导致整体SQL的执行速度不同。

    后续想着消除临时表空间的物理IO在看看效果,结果啥也不说了,水太深了,给组数据对比就知道了。

    如何消除看我之前写的:Oracle手工增加排序区避免SQL使用临时表空间排序产生物理IO

    15:58:22 SYS@xxxxxx1(1893)> ALTER SESSION SET workarea_size_policy = MANUAL;
    
    Session altered.
    
    Elapsed: 00:00:00.01
    16:02:38 SYS@xxxxxx(1893)> ALTER SESSION SET sort_area_size = 1258291200;
    
    Session altered.
    
    Elapsed: 00:00:00.00

    数据比对:

                -------------------------------------------------------------------------------------------------------------------------------------
                | Id  | Operation                | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
                -------------------------------------------------------------------------------------------------------------------------------------
    rn=1        |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   2798K|00:00:08.52 |   56921 |   486M|  7266K|  432M (0)|
    rn=0        |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3144K|00:00:07.78 |   56921 |   486M|  7266K|  432M (0)|
    rn=10000    |*  2 |   WINDOW SORT PUSHED RANK|                     |      1 |   3093K|   3144K|00:00:07.87 |   56921 |   486M|  7266K|  432M (0)|
                -------------------------------------------------------------------------------------------------------------------------------------

    直接把我猜想干翻了。

    rn的值并不是决定性的影响因素,只能说是影响因素之一。。

    现在避免物理IO后,实际上无论rn等于多少,都一样快了,而且都一样慢了(rn=1变得和其它一样慢。。)。

    暂时没头绪了。

  • 相关阅读:
    立即执行函数的装逼写法
    SublimeText个性化快捷键设置
    arguments的理解
    webpack详细配置讲解
    webpack配置命令
    组件(0)
    特殊符号 && 和 ||
    Sublime Text的常用插件
    如何清除夜神模拟器的Pin密码
    swagger--Failed to load API definition.
  • 原文地址:https://www.cnblogs.com/PiscesCanon/p/16395574.html
Copyright © 2020-2023  润新知