暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

test drop partition 导致执行计划变化

原创 范计杰 2020-05-20
1112

创建测试表,索引,INSERT测试数据,并收集统计信息

create table dbmt.test_part(etime date,c1 varchar2(100))
partition by range(etime)
(
PARTITION "PART_202002"  VALUES LESS THAN ( TO_DATE(' 2020-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
PARTITION "PART_202003"  VALUES LESS THAN ( TO_DATE(' 2020-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
PARTITION "PART_202004"  VALUES LESS THAN ( TO_DATE(' 2020-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
PARTITION "PART_202005"  VALUES LESS THAN ( TO_DATE(' 2020-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
PARTITION "PART_202006"  VALUES LESS THAN ( TO_DATE(' 2020-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
);

insert into dbmt.test_part select to_date('20200201','yyyymmdd')+mod(abs(dbms_random.random()),3600*24*20)/(3600*24*20),'test' from dual connect by rownum<200000;

SQL> insert into dbmt.test_part select to_date('20200201','yyyymmdd')+mod(abs(dbms_random.random()),3600*24*20)/(3600*24*20),'test' from dual connect by rownum<200000;

199999 rows created.

Commit complete.

SQL> 

create index dbmt.idx_test_part on dbmt.test_part(etime) local;

SQL>  exec DBMS_STATS.GATHER_TABLE_STATS (ownname => '&TOWN' , tabname => '&TNAME' , cascade => true, estimate_percent => dbms_stats.auto_sample_size,method_opt=>'FOR TABLE FOR ALL COLUMNS SIZE REPEAT',  degree => 8,no_invalidate=>false); 
Enter value for town: DBMT
Enter value for tname: test_part

PL/SQL procedure successfully completed.



---第一次收统计信息时,表上只有2月份有数据,后面的分区统计信息为0,库上禁用了统计信息收集,所以后面大量INSERT后,统计信息也没更新
SET LINES 1000
COL TABLE_NAME FORMAT A30
COL PARTITION_NAME FORMAT A30
SELECT TABLE_NAME,PARTITION_NAME,NUM_ROWS,BLOCKS,LAST_ANALYZED,GLOBAL_STATS,STALE_STATS FROM  dba_tab_statistics where table_name='TEST_PART';

TABLE_NAME                     PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED     GLO STA
------------------------------ ------------------------------ ---------- ---------- ----------------- --- ---
TEST_PART                                                         199999        622 20200520 15:46:20 YES NO
TEST_PART                      PART_202004                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202003                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202005                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202006                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202002                        199999        622 20200520 15:46:20 YES NO

6 rows selected.

SQL> COL COLUMN_NAME FORMAT A30
SQL> SELECT COLUMN_NAME,LOW_VALUE,HIGH_VALUE,DENSITY FROM  dba_tab_col_statistics where table_name='TEST_PART';

COLUMN_NAME                    LOW_VALUE              HIGH_VALUE              DENSITY
------------------------------ ---------------------- -------------------------------
ETIME                          78780201010101         78780202010101       .000012835
C1                             74657374               74657374                                                                                                                                                                                                                                                                 1

set serveroutput ons
declare
v_low date;
v_high date;
begin
dbms_stats.convert_raw_value('78780201010101',v_low);
dbms_stats.convert_raw_value('78780202010101',v_high);
dbms_output.put_line(v_low);
dbms_output.put_line(v_high);
end;
/

20200201 00:00:00
20200202 00:00:00

测试SQL走INDEX SCAN

SQL> SELECT * FROM DBMT.TEST_PART WHERE ETIME>SYSDATE-1;

no rows selected

SQL> @x
Display execution plan for last statement for this session from library cache...

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  3xd8x4vy1v6gn, child number 0
-------------------------------------
SELECT * FROM DBMT.TEST_PART WHERE ETIME>SYSDATE-1

Plan hash value: 3223941850

------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name          | E-Rows |E-Bytes| Cost (%CPU)| Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |               |        |       |     4 (100)|       |       |
|   1 |  PARTITION RANGE ITERATOR                  |               |      1 |    13 |     4   (0)|   KEY |     5 |
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| TEST_PART     |      1 |    13 |     4   (0)|   KEY |     5 |
|*  3 |    INDEX RANGE SCAN                        | IDX_TEST_PART |      1 |       |     3   (0)|   KEY |     5 |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("ETIME">SYSDATE@!-1)



21 rows selected.

DROP PARTITION PART_202002后,测试SQL变为走FULL SCAN,后面的分区虽然统计信息为0,实际有大量数据

alter table  dbmt.test_part drop partition PART_202002;



SET LINES 1000
COL TABLE_NAME FORMAT A30
COL PARTITION_NAME FORMAT A30
SELECT TABLE_NAME,PARTITION_NAME,NUM_ROWS,BLOCKS,LAST_ANALYZED,GLOBAL_STATS,STALE_STATS FROM  dba_tab_statistics where table_name='TEST_PART';


TABLE_NAME                     PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED     GLO STA
------------------------------ ------------------------------ ---------- ---------- ----------------- --- ---
TEST_PART                                                         199999        622 20200520 15:46:20 YES YES  <<<DROP PARTITION STALE_STATS NO=>YES
TEST_PART                      PART_202004                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202003                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202005                             0          0 20200520 15:46:20 YES NO
TEST_PART                      PART_202006                             0          0 20200520 15:46:20 YES NO


COL COLUMN_NAME FORMAT A30
SELECT COLUMN_NAME,LOW_VALUE,HIGH_VALUE,DENSITY FROM  dba_tab_col_statistics where table_name='TEST_PART';

COLUMN_NAME                    LOW_VALUE         HIGH_VALUE            DENSITY
------------------------------ ----------------- ------------------ ----------
ETIME                          78780201010101    78780202010101     .000012835
C1                             74657374          74657374                    1

set serveroutput on
declare
v_low date;
v_high date;
begin
dbms_stats.convert_raw_value('78780201010101',v_low);
dbms_stats.convert_raw_value('78780202010101',v_high);
dbms_output.put_line(v_low);
dbms_output.put_line(v_high);
end;
/

20200201 00:00:00
20200202 00:00:00

PL/SQL procedure successfully completed.

---DROP 历史分区后,下面的查询走INDEX SCAN

SQL> SELECT * FROM DBMT.TEST_PART WHERE ETIME>SYSDATE-1;

no rows selected

SQL> @x
Display execution plan for last statement for this session from library cache...

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  3xd8x4vy1v6gn, child number 0
-------------------------------------
SELECT * FROM DBMT.TEST_PART WHERE ETIME>SYSDATE-1

Plan hash value: 4294476422

--------------------------------------------------------------------------------------------
| Id  | Operation                | Name      | E-Rows |E-Bytes| Cost (%CPU)| Pstart| Pstop |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |           |        |       |     3 (100)|       |       |
|   1 |  PARTITION RANGE ITERATOR|           |      1 |    13 |     3   (0)|   KEY |     4 |
|*  2 |   TABLE ACCESS FULL      | TEST_PART |      1 |    13 |     3   (0)|   KEY |     4 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ETIME">SYSDATE@!-1)



20 rows selected.

10053 对比DROP分区前后差异,

DROP分区前FULL SCAN IO 估算为171,DROP分区后IO估算为 3

---DROP分区前
Access path analysis for TEST_PART
***************************************
SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST_PART[TEST_PART] 
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE

 kkecdn: Single Table Predicate:"TEST_PART"."ETIME">SYSDATE@!-1
  Column (#1): ETIME(DATE)
    AvgLen: 8 NDV: 77912 Nulls: 0 Density: 0.000013 Min: 2458881.000000 Max: 2458882.000000
  Using prorated density: 2.5000e-06 of col #1 as selectivity of out-of-range/non-existent value pred
  Table: TEST_PART  Alias: TEST_PART
    Card: Original: 199999.000000  Rounded: 1  Computed: 0.500000  Non Adjusted: 0.500000
  Scan IO  Cost (Disk) =   171.000000  <<<<
  Scan CPU Cost (Disk) =   34650941.440000
  Cost of predicates:
    io = NOCOST, cpu = 500.000000, sel = 0.000003 flag = 2048  ("TEST_PART"."ETIME">SYSDATE@!-1)
  Total Scan IO  Cost  =   171.000000 (scan (Disk))
                         + 0.000000 (io filter eval) (= 0.000000 (per row) * 201285.167203 (#rows))
                       =   171.000000
  Total Scan CPU  Cost =   34650941.440000 (scan (Disk))
                         + 100642583.601286 (cpu filter eval) (= 500.000000 (per row) * 201285.167203 (#rows))
                       =   135293525.041286
  Access Path: TableScan
    Cost:  176.622676  Resp: 176.622676  Degree: 0
      Cost_io: 171.000000  Cost_cpu: 135293525
      Resp_io: 171.000000  Resp_cpu: 135293525
 ****** Costing Index IDX_TEST_PART
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_SCAN
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_FILTER
  Using prorated density: 2.5000e-06 of col #1 as selectivity of out-of-range/non-existent value pred
  Access Path: index (RangeScan)
    Index: IDX_TEST_PART
    resc_io: 4.000000  resc_cpu: 28856
    ix_sel: 2.5000e-06  ix_sel_with_filters: 2.5000e-06 
    Cost: 4.001199  Resp: 4.001199  Degree: 1
  Best:: AccessPath: IndexRange
  Index: IDX_TEST_PART
         Cost: 4.001199  Degree: 1  Resp: 4.001199  Card: 0.500000  Bytes: 0.000000

---DROP分区后

Access path analysis for TEST_PART
***************************************
SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST_PART[TEST_PART] 
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE

 kkecdn: Single Table Predicate:"TEST_PART"."ETIME">SYSDATE@!-1
  Column (#1): ETIME(DATE)
    AvgLen: 8 NDV: 77912 Nulls: 0 Density: 0.000013 Min: 2458881.000000 Max: 2458882.000000
  Using prorated density: 2.5000e-06 of col #1 as selectivity of out-of-range/non-existent value pred
  Table: TEST_PART  Alias: TEST_PART
    Card: Original: 199999.000000  Rounded: 1  Computed: 0.500000  Non Adjusted: 0.500000
  Scan IO  Cost (Disk) =   3.000000
  Scan CPU Cost (Disk) =   221555.760000
  Cost of predicates:
    io = NOCOST, cpu = 500.000000, sel = 0.000003 flag = 2048  ("TEST_PART"."ETIME">SYSDATE@!-1)
  Total Scan IO  Cost  =   3.000000 (scan (Disk))   <<<<
                         + 0.000000 (io filter eval) (= 0.000000 (per row) * 1286.167203 (#rows))
                       =   3.000000
  Total Scan CPU  Cost =   221555.760000 (scan (Disk))
                         + 643083.601286 (cpu filter eval) (= 500.000000 (per row) * 1286.167203 (#rows))
                       =   864639.361286
  Access Path: TableScan
    Cost:  3.035934  Resp: 3.035934  Degree: 0
      Cost_io: 3.000000  Cost_cpu: 864639
      Resp_io: 3.000000  Resp_cpu: 864639
 ****** Costing Index IDX_TEST_PART
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_SCAN
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_FILTER
  Using prorated density: 2.5000e-06 of col #1 as selectivity of out-of-range/non-existent value pred
  Access Path: index (RangeScan)
    Index: IDX_TEST_PART
    resc_io: 4.000000  resc_cpu: 28856
    ix_sel: 2.5000e-06  ix_sel_with_filters: 2.5000e-06 
    Cost: 4.001199  Resp: 4.001199  Degree: 1
  Best:: AccessPath: TableScan
         Cost: 3.035934  Degree: 1  Resp: 3.035934  Card: 0.500000  Bytes: 0.000000
最后修改时间:2020-05-20 17:27:33
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论