[20250718]WINDOW SORT PUSHED RANK Performance Regression in Oracle 21c.txt

来源:这里教程网 时间:2026-03-03 22:20:55 作者:

[20250718]WINDOW SORT PUSHED RANK Performance Regression in Oracle 21c.txt https://nenadnoveljic.com/blog/window-sort-pushed-rank-performance-regression-in-oracle-21c/ --//重复测试看看。 1.环境: SCOTT@book01p> @ver2 ============================== PORT_STRING                   : x86_64/Linux 2.4.xx VERSION                       : 21.0.0.0.0 BANNER                        : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production BANNER_FULL                   : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production Version 21.3.0.0.0 BANNER_LEGACY                 : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production CON_ID                        : 0 PL/SQL procedure successfully completed. 2.测试例子建立: create table t1 (n1 number, c1 varchar2(10)) ; create table t2 (n1 number, c1 varchar2(10), n2 number) ; insert into t1 select level, null from dual connect by level <= 5*1e5 ; insert into t2 select 5*1e5 + level, 'X', 1 from dual connect by level <= 4*1e5 ; commit ; exec dbms_stats.gather_table_stats(null, 'T1'); exec dbms_stats.gather_table_stats(null, 'T2'); $ cat g8.txt merge /*+ gather_plan_statistics monitor */ --nenad into t1 using ( select n1,c1 from   ( select n1,c1,       row_number() over (partition by n1 order by n2 desc) rn         from t2   ) where rn = 1 ) v1 on ( v1.n1 = t1.n1 ) when matched then update set t1.c1 = v1.c1 ; 3.测试: SCOTT@book01p> set timing on SCOTT@book01p> @ g8.txt 0 rows merged. Elapsed: 00:02:32.95 --//差不多150秒。 SCOTT@book01p> @ dpc '' outline '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  2r8rr3pht5cvn, child number 0 ------------------------------------- merge /*+ gather_plan_statistics monitor */ --nenad into t1 using ( select n1,c1 from   ( select n1,c1,       row_number() over (partition by n1 order by n2 desc) rn  from t2   ) where rn = 1 ) v1 on ( v1.n1 = t1.n1 ) when matched then update set t1.c1 = v1.c1 Plan hash value: 3917951292 ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id  | Operation                   | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |   0 | MERGE STATEMENT             |      |      1 |        |       |       |  3356 (100)|          |      0 |00:02:32.95 |    1683 |       |       |          | |   1 |  MERGE                      | T1   |      1 |        |       |       |            |          |      0 |00:02:32.95 |    1683 |       |       |          | |   2 |   VIEW                      |      |      1 |        |       |       |            |          |      0 |00:02:32.95 |    1683 |       |       |          | |*  3 |    HASH JOIN                |      |      1 |      1 |    38 |  8304K|  3356   (2)| 00:00:01 |      0 |00:02:32.95 |    1683 |    33M|  8026K|   32M (0)| |   4 |     TABLE ACCESS FULL       | T1   |      1 |    500K|  2441K|       |   243   (3)| 00:00:01 |    500K|00:00:00.02 |     805 |       |       |          | |*  5 |     VIEW                    |      |      1 |    400K|    12M|       |  1850   (2)| 00:00:01 |    400K|00:02:33.14 |     878 |       |       |          | |*  6 |      WINDOW SORT PUSHED RANK|      |      1 |    400K|  3906K|  7856K|  1850   (2)| 00:00:01 |    400K|00:02:32.93 |     878 |    25M|  1830K|   22M (0)| |   7 |       TABLE ACCESS FULL     | T2   |      1 |    400K|  3906K|       |   243   (3)| 00:00:01 |    400K|00:00:00.01 |     878 |       |       |          | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - MRG$1    3 - SEL$F5BB74E1    4 - SEL$F5BB74E1 / "T1"@"SEL$1"    5 - SEL$3        / "from$_subquery$_007"@"SEL$2"    6 - SEL$3    7 - SEL$3        / "T2"@"SEL$3" Outline Data -------------   /*+       BEGIN_OUTLINE_DATA       IGNORE_OPTIM_EMBEDDED_HINTS       OPTIMIZER_FEATURES_ENABLE('21.1.0')       DB_VERSION('21.1.0')       ALL_ROWS       OUTLINE_LEAF(@"SEL$3")       OUTLINE_LEAF(@"SEL$F5BB74E1")       MERGE(@"SEL$2" >"SEL$1")       OUTLINE_LEAF(@"SEL$5")       OUTLINE_LEAF(@"SEL$4")       OUTLINE_LEAF(@"MRG$1")       OUTLINE(@"SEL$1")       OUTLINE(@"SEL$2")       NO_ACCESS(@"MRG$1" "from$_subquery$_009"@"MRG$1")       NO_ACCESS(@"MRG$1" "V1"@"MRG$1")       FULL(@"MRG$1" "T1"@"MRG$1")       LEADING(@"MRG$1" "from$_subquery$_009"@"MRG$1" "V1"@"MRG$1" "T1"@"MRG$1")       USE_MERGE_CARTESIAN(@"MRG$1" "V1"@"MRG$1")       USE_MERGE_CARTESIAN(@"MRG$1" "T1"@"MRG$1")       NO_ACCESS(@"SEL$F5BB74E1" "from$_subquery$_007"@"SEL$2")       FULL(@"SEL$F5BB74E1" "T1"@"SEL$1")       LEADING(@"SEL$F5BB74E1" "from$_subquery$_007"@"SEL$2" "T1"@"SEL$1")       USE_HASH(@"SEL$F5BB74E1" "T1"@"SEL$1")       SWAP_JOIN_INPUTS(@"SEL$F5BB74E1" "T1"@"SEL$1")       NO_ACCESS(@"SEL$4" "from$_subquery$_004"@"SEL$4")       FULL(@"SEL$5" "T2"@"SEL$5")       FULL(@"SEL$3" "T2"@"SEL$3")       END_OUTLINE_DATA   */ Predicate Information (identified by operation id): ---------------------------------------------------    3 - access("N1"="T1"."N1")    5 - filter("RN"=1)    6 - filter(ROW_NUMBER() OVER ( PARTITION BY "N1" ORDER BY INTERNAL_FUNCTION("N2") DESC )<=1) 73 rows selected. --//时间在id=6上。 SCOTT@book01p> @ dpccpu 2r8rr3pht5cvn 0 PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  2r8rr3pht5cvn, child number 0 ------------------------------------- merge /*+ gather_plan_statistics monitor */ --nenad into t1 using ( select n1,c1 from   ( select n1,c1,       row_number() over (partition by n1 order by n2 desc) rn  from t2   ) where rn = 1 ) v1 on ( v1.n1 = t1.n1 ) when matched then update set t1.c1 = v1.c1 Plan hash value: 3917951292 -------------------------------------------------------------------------------------------- | Id  | Operation                   | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | %ASH SAMPLES -------------------------------------------------------------------------------------------- |   0 | MERGE STATEMENT             |      |       |       |       |  3356 (100)|          | |   1 |  MERGE                      | T1   |       |       |       |            |          | |   2 |   VIEW                      |      |       |       |       |            |          | |*  3 |    HASH JOIN                |      |     1 |    38 |  8304K|  3356   (2)| 00:00:01 |   1% (   1% CPU   0% I/O) |   4 |     TABLE ACCESS FULL       | T1   |   500K|  2441K|       |   243   (3)| 00:00:01 | |*  5 |     VIEW                    |      |   400K|    12M|       |  1850   (2)| 00:00:01 | |*  6 |      WINDOW SORT PUSHED RANK|      |   400K|  3906K|  7856K|  1850   (2)| 00:00:01 |  99% (  99% CPU   0% I/O) |   7 |       TABLE ACCESS FULL     | T2   |   400K|  3906K|       |   243   (3)| 00:00:01 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    3 - access("N1"="T1"."N1")    5 - filter("RN"=1)    6 - filter(ROW_NUMBER() OVER ( PARTITION BY "N1" ORDER BY               INTERNAL_FUNCTION("N2") DESC )<=1) --//99%的CPU资源在id=6。 --//作者通过bpftrace定位smbgetqbPart频繁调用800001次。而19c调用0. --//通过pstack观察也可以同样定位: $ seq 10000 | xargs -IQ pstack 6849 >| gg.txt --//注:我的测试环境密集执行pstack,按ctrl+c中断后,相关进程很容易出现挂起情况,不知道原因。 --//sql执行结束按ctrl+c中断pstack的执行。  awk '/#0/{print $4}' gg.txt | sort  |uniq -c | sort -nr     226 smbgetqbPart       3 __read_nocancel       1 rwosmf       1 qerstUpdateStats       1 expeal --//大部分调用函数smbgetqbPart。 $ pstack 6849 #0  0x000000000e250f7d in smbgetqbPart () #1  0x000000001500e027 in sorgetqbf () #2  0x0000000004d9b504 in qerwnFetch () #3  0x000000000a261506 in qerstFetch () #4  0x0000000004cd1903 in qervwFetch () #5  0x000000000a261506 in qerstFetch () #6  0x0000000014dfbda7 in rwsfcd () #7  0x000000000a261506 in qerstFetch () #8  0x000000001516b8a5 in qerhnFetch () #9  0x000000000a261506 in qerstFetch () #10 0x0000000004cd1903 in qervwFetch () #11 0x000000000a261506 in qerstFetch () #12 0x0000000014dfbda7 in rwsfcd () #13 0x000000000a261506 in qerstFetch () #14 0x0000000004dd99dd in qerusFetch () #15 0x000000000a261506 in qerstFetch () #16 0x0000000014ffbf49 in updaul () #17 0x0000000014ff8f90 in updThreePhaseExe () #18 0x00000000041ab3e0 in upsexe () #19 0x0000000014ef6ab5 in opiexe () #20 0x0000000014f6cf9d in kpoal8 () #21 0x0000000014eefdf8 in opiodr () #22 0x0000000015294359 in ttcpip () #23 0x00000000030025c2 in opitsk () #24 0x0000000003007920 in opiino () #25 0x0000000014eefdf8 in opiodr () #26 0x0000000002ffe2ab in opidrv () #27 0x0000000003e8bd15 in sou2o () #28 0x0000000000e91ae0 in opimai_real () #29 0x0000000003e9915c in ssthrdmain () #30 0x0000000000e91924 in main () SCOTT@book01p> @ fix "PUSHED RANK" SCOTT@book01p>  @pr ============================== SESSION_ID                    : 147 BUGNO                         : 30822446 VALUE                         : 1 SQL_FEATURE                   : QKSFM_EXECUTION_30822446 DESCRIPTION                   : enable window pushed rank optimization with partition by keys OPTIMIZER_FEATURE_ENABLE      : 21.1.0 EVENT                         : 0 IS_DEFAULT                    : 1 CON_ID                        : 3 PL/SQL procedure successfully completed. SCOTT@book01p> alter session set "_FIX_CONTROL"='30822446:OFF'  ; Session altered. SCOTT@book01p> @ g8.txt 0 rows merged. Elapsed: 00:00:00.60 SCOTT@book01p> @ dpc '' '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  2r8rr3pht5cvn, child number 1 ------------------------------------- merge /*+ gather_plan_statistics monitor */ --nenad into t1 using ( select n1,c1 from   ( select n1,c1,       row_number() over (partition by n1 order by n2 desc) rn  from t2   ) where rn = 1 ) v1 on ( v1.n1 = t1.n1 ) when matched then update set t1.c1 = v1.c1 Plan hash value: 3917951292 ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id  | Operation                   | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |   0 | MERGE STATEMENT             |      |      1 |        |       |       |  3356 (100)|          |      0 |00:00:00.56 |    1683 |       |       |          | |   1 |  MERGE                      | T1   |      1 |        |       |       |            |          |      0 |00:00:00.56 |    1683 |       |       |          | |   2 |   VIEW                      |      |      1 |        |       |       |            |          |      0 |00:00:00.56 |    1683 |       |       |          | |*  3 |    HASH JOIN                |      |      1 |      1 |    38 |  8304K|  3356   (2)| 00:00:01 |      0 |00:00:00.56 |    1683 |    33M|  8026K|   32M (0)| |   4 |     TABLE ACCESS FULL       | T1   |      1 |    500K|  2441K|       |   243   (3)| 00:00:01 |    500K|00:00:00.02 |     805 |       |       |          | |*  5 |     VIEW                    |      |      1 |    400K|    12M|       |  1850   (2)| 00:00:01 |    400K|00:00:00.56 |     878 |       |       |          | |*  6 |      WINDOW SORT PUSHED RANK|      |      1 |    400K|  3906K|  7856K|  1850   (2)| 00:00:01 |    400K|00:00:00.46 |     878 |    25M|  1830K|   22M (0)| |   7 |       TABLE ACCESS FULL     | T2   |      1 |    400K|  3906K|       |   243   (3)| 00:00:01 |    400K|00:00:00.01 |     878 |       |       |          | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - MRG$1    3 - SEL$F5BB74E1    4 - SEL$F5BB74E1 / "T1"@"SEL$1"    5 - SEL$3        / "from$_subquery$_007"@"SEL$2"    6 - SEL$3    7 - SEL$3        / "T2"@"SEL$3" Predicate Information (identified by operation id): ---------------------------------------------------    3 - access("N1"="T1"."N1")    5 - filter("RN"=1)    6 - filter(ROW_NUMBER() OVER ( PARTITION BY "N1" ORDER BY INTERNAL_FUNCTION("N2") DESC )<=1) --//逻辑读一样。执行计划一样。 4.附上测试使用dpccpu.sql脚本: $ cat dpccpu.sql with  "sql" as (select SQL_ID,CHILD_NUMBER,PLAN_HASH_VALUE,'' FORMAT from v$sql where sql_id='&1'),  "ash" as (           select sql_id,sql_plan_line_id,child_number,sql_plan_hash_value           ,round(count(*)/"samples",2) load           ,nvl(round(sum(case when session_state='ON CPU' then 1 end)/"samples",2),0) load_cpu           ,nvl(round(sum(case when session_state='WAITING' and wait_class='User I/O' then 1 end)/"samples",2),0) load_io           from "sql" join           (             select sql_id,sql_plan_line_id,sql_child_number child_number,sql_plan_hash_value,session_state,wait_class,count(*) over (partition by sql_id,sql_plan_hash_value) "samples"             FROM V$ACTIVE_SESSION_HISTORY           ) using(sql_id,child_number) group by sql_id,sql_plan_line_id,child_number,sql_plan_hash_value,"samples"  ),  "plan" as (         -- get dbms_xplan result         select          sql_id,child_number,n,plan_table_output          -- get plan line id from plan_table output          ,case when regexp_like (plan_table_output,'^[|][*]? *([0-9]+) *[|].*[|]$') then           regexp_replace(plan_table_output,'^[|][*]? *([0-9]+) *[|].*[|]$','\1')           END SQL_PLAN_LINE_ID          from (select rownum n,plan_table_output,SQL_ID,CHILD_NUMBER from "sql", table(dbms_xplan.display_cursor("sql".SQL_ID,"sql".CHILD_NUMBER,"sql".FORMAT)))  ) select PLAN_TABLE_OUTPUT||CASE        -- ASH load to be displayed        WHEN LOAD >0 THEN TO_CHAR(100*LOAD,'999')||'% (' || TO_CHAR(100*LOAD_CPU,'999')||'% CPU'|| TO_CHAR(100*LOAD_IO,'999')||'% I/O)'        -- header        WHEN REGEXP_LIKE (PLAN_TABLE_OUTPUT,'^[|] *Id *[|]')  THEN ' %ASH SAMPLES'        end plan_table_output from "plan" left outer join "ash" using(sql_id,child_number,sql_plan_line_id) order by sql_id,child_number,n;

相关推荐