【DB筆試面試475】分區表性能注意事項有哪些?

  • 2019 年 10 月 11 日
  • 筆記

題目部分

分區表性能注意事項有哪些?

答案部分

在使用分區表的時候需要注意以下幾方面的內容:

① 在查詢分區表時盡量帶上分區鍵過濾條件,否則可能引起全分區掃描。

② 在設計分區表時,避免數據都進入默認分區,從而導致出現默認分區超大或各個分區大小嚴重不均衡的情況,失去分區表的意義。

③ 需要特別注意分區表性能比普通表性能差的情況。這種情況的本質原因是,雖然分區表的分區索引比全局索引要小很多,但是由於沒有掃描指定的分區,而是掃描了很多個小的索引,這些小索引的高度累計起來一般都比全局索引要高。索引的範圍檢索性能是由索引的高度(BLEVEL)決定的,而不是由索引的大小決定。所以,性能差異很明顯。示例如下所示:

--創建分區表和索引  DROP TABLE T_PART_20170619_LHR PURGE;  CREATE TABLE T_PART_20170619_LHR (ID INT,COL2 INT,COL3 INT)  PARTITION BY RANGE (ID)  (  PARTITION P1 VALUES LESS THAN (10000),  PARTITION P2 VALUES LESS THAN (20000),  PARTITION P3 VALUES LESS THAN (30000),  PARTITION P4 VALUES LESS THAN (40000),  PARTITION P5 VALUES LESS THAN (50000),  PARTITION P6 VALUES LESS THAN (60000),  PARTITION P7 VALUES LESS THAN (70000),  PARTITION P8 VALUES LESS THAN (80000),  PARTITION P9 VALUES LESS THAN (90000),  PARTITION P10 VALUES LESS THAN (100000),  PARTITION P11 VALUES LESS THAN (MAXVALUE)  );  INSERT INTO T_PART_20170619_LHR SELECT ROWNUM,ROWNUM+1,ROWNUM+2 FROM DUAL CONNECT BY ROWNUM <=110000;  COMMIT;  CREATE  INDEX IDX_PART_COL2_LHR ON T_PART_20170619_LHR(COL2) LOCAL;  CREATE  INDEX IDX_PART_COL3_LHR ON T_PART_20170619_LHR(COL3) ;  --構造普通表,表結構和數據量都與分區表一樣  DROP TABLE T_NM_20170619_LHR PURGE;  CREATE TABLE T_NM_20170619_LHR  (ID INT,COL2 INT,COL3 INT);  INSERT INTO T_NM_20170619_LHR SELECT ROWNUM,ROWNUM+1,ROWNUM+2 FROM DUAL CONNECT BY ROWNUM <=110000;  COMMIT;  CREATE  INDEX IDX_NM_COL2_LHR ON T_NM_20170619_LHR(COL2) ;  CREATE  INDEX IDX_NM_COL3_LHR ON T_NM_20170619_LHR(COL3) ;

分別查詢分區表和普通表:

LHR@orclasm > SELECT * FROM T_PART_20170619_LHR WHERE COL2=8 ;          ID       COL2       COL3  ---------- ---------- ----------           7          8          9  Elapsed: 00:00:00.00  Execution Plan  ----------------------------------------------------------  Plan hash value: 548042063  --------------------------------------------------------------------------------------------------------------------------  | Id  | Operation                          | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |  --------------------------------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT                   |                     |     1 |    39 |    13   (0)| 00:00:01 |       |       |  |   1 |  PARTITION RANGE ALL               |                     |     1 |    39 |    13   (0)| 00:00:01 |     1 |    11 |  |   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| T_PART_20170619_LHR |     1 |    39 |    13   (0)| 00:00:01 |     1 |    11 |  |*  3 |    INDEX RANGE SCAN                | IDX_PART_COL2_LHR   |     1 |       |    12   (0)| 00:00:01 |     1 |    11 |  --------------------------------------------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     3 - access("COL2"=8)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            0  db block gets           24  consistent gets            0  physical reads            0  redo size          658  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  LHR@orclasm > SELECT * FROM T_NM_20170619_LHR WHERE COL2=8 ;          ID       COL2       COL3  ---------- ---------- ----------           7          8          9  Elapsed: 00:00:00.00  Execution Plan  ----------------------------------------------------------  Plan hash value: 3820625032  -------------------------------------------------------------------------------------------------  | Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time     |  -------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT            |                   |     1 |    39 |     2   (0)| 00:00:01 |  |   1 |  TABLE ACCESS BY INDEX ROWID| T_NM_20170619_LHR |     1 |    39 |     2   (0)| 00:00:01 |  |*  2 |   INDEX RANGE SCAN          | IDX_NM_COL2_LHR   |     1 |       |     1   (0)| 00:00:01 |  -------------------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     2 - access("COL2"=8)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            0  db block gets            4  consistent gets            0  physical reads            0  redo size          662  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  可以看到,查詢分區表的邏輯讀為24,而普通表的邏輯讀僅為4。從執行計劃很明顯的看出,Oracle掃描分區表的11個分區,它們的索引詳情如下所示:  LHR@orclasm > SET TIMING ON  LHR@orclasm > SET AUTOTRACE OFF  LHR@orclasm > SELECT INDEX_NAME,    2          BLEVEL,    3          LEAF_BLOCKS,    4          NUM_ROWS,    5          DISTINCT_KEYS,    6          CLUSTERING_FACTOR    7     FROM USER_IND_STATISTICS    8    WHERE TABLE_NAME IN( 'T_NM_20170619_LHR');  INDEX_NAME                         BLEVEL LEAF_BLOCKS   NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR  ------------------------------ ---------- ----------- ---------- ------------- -----------------  IDX_NM_COL2_LHR                         1         244     110000        110000               299  IDX_NM_COL3_LHR                         1         244     110000        110000               299  Elapsed: 00:00:00.01  LHR@orclasm > SELECT INDEX_NAME,    2      BLEVEL,    3      LEAF_BLOCKS,    4      NUM_ROWS,    5      DISTINCT_KEYS,    6      CLUSTERING_FACTOR    7  FROM USER_IND_PARTITIONS    8  WHERE INDEX_NAME='IDX_PART_COL2_LHR';  INDEX_NAME                         BLEVEL LEAF_BLOCKS   NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR  ------------------------------ ---------- ----------- ---------- ------------- -----------------  IDX_PART_COL2_LHR                       1          21       9999          9999                24  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10001         10001                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  IDX_PART_COL2_LHR                       1          23      10000         10000                28  11 rows selected.  分區表的分區索引雖然很小,但是需要掃描11個小的分區索引,而索引的範圍檢索性能是由索引的高度(BLEVEL)決定的,而不是由索引的大小決定。所以,11個小的分區索引總高度為22,遠大於普通表的高度2。故可以把分區索引改造為全局索引或者想法讓Oracle少掃描一些分區索引,則比如性能會提升,如下所示:  LHR@orclasm > SELECT * FROM T_PART_20170619_LHR PARTITION(P1) WHERE COL2=8 ;          ID       COL2       COL3  ---------- ---------- ----------           7          8          9  Elapsed: 00:00:00.00  Execution Plan  ----------------------------------------------------------  Plan hash value: 4015980707  --------------------------------------------------------------------------------------------------------------------------  | Id  | Operation                          | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |  --------------------------------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT                   |                     |     1 |    39 |     2   (0)| 00:00:01 |       |       |  |   1 |  PARTITION RANGE SINGLE            |                     |     1 |    39 |     2   (0)| 00:00:01 |     1 |     1 |  |   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| T_PART_20170619_LHR |     1 |    39 |     2   (0)| 00:00:01 |     1 |     1 |  |*  3 |    INDEX RANGE SCAN                | IDX_PART_COL2_LHR   |     1 |       |     1   (0)| 00:00:01 |     1 |     1 |  --------------------------------------------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     3 - access("COL2"=8)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            0  db block gets            4  consistent gets            0  physical reads            0  redo size          658  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  LHR@orclasm > SELECT * FROM T_PART_20170619_LHR  WHERE ID<COL2 AND  COL2=8 ;          ID       COL2       COL3  ---------- ---------- ----------           7          8          9  Elapsed: 00:00:00.00  Execution Plan  ----------------------------------------------------------  Plan hash value: 4015980707  --------------------------------------------------------------------------------------------------------------------------  | Id  | Operation                          | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |  --------------------------------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT                   |                     |     1 |    39 |     2   (0)| 00:00:01 |       |       |  |   1 |  PARTITION RANGE SINGLE            |                     |     1 |    39 |     2   (0)| 00:00:01 |     1 |     1 |  |*  2 |   TABLE ACCESS BY LOCAL INDEX ROWID| T_PART_20170619_LHR |     1 |    39 |     2   (0)| 00:00:01 |     1 |     1 |  |*  3 |    INDEX RANGE SCAN                | IDX_PART_COL2_LHR   |     1 |       |     1   (0)| 00:00:01 |     1 |     1 |  --------------------------------------------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     2 - filter("ID"<"COL2" AND "ID"<8)     3 - access("COL2"=8)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            0  db block gets            4  consistent gets            0  physical reads            0  redo size          658  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  由此可見,在查詢分區表的時候,應該盡量加上分區鍵過濾條件,從而避免全分區掃描。如下查詢可看到分區表的優點:  LHR@orclasm > SELECT * FROM T_NM_20170619_LHR T WHERE T.ID IN (666,66666,77777,88888);          ID       COL2       COL3  ---------- ---------- ----------         666        667        668       66666      66667      66668       88888      88889      88890       77777      77778      77779  Elapsed: 00:00:00.01  Execution Plan  ----------------------------------------------------------  Plan hash value: 610368810  ---------------------------------------------------------------------------------------  | Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Time     |  ---------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT  |                   |    12 |   468 |   103   (1)| 00:00:02 |  |*  1 |  TABLE ACCESS FULL| T_NM_20170619_LHR |    12 |   468 |   103   (1)| 00:00:02 |  ---------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     1 - filter("T"."ID"=666 OR "T"."ID"=66666 OR "T"."ID"=77777 OR                "T"."ID"=88888)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            1  db block gets          336  consistent gets            0  physical reads            0  redo size          767  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            4  rows processed  LHR@orclasm > SELECT * FROM T_PART_20170619_LHR  T WHERE T.ID IN (666,66666,77777,88888);          ID       COL2       COL3  ---------- ---------- ----------         666        667        668       66666      66667      66668       77777      77778      77779       88888      88889      88890  Elapsed: 00:00:00.01  Execution Plan  ----------------------------------------------------------  Plan hash value: 4018516498  --------------------------------------------------------------------------------------------------------------  | Id  | Operation              | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |  --------------------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT       |                     |     3 |   117 |    53   (4)| 00:00:01 |       |       |  |   1 |  PARTITION RANGE INLIST|                     |     3 |   117 |    53   (4)| 00:00:01 |KEY(I) |KEY(I) |  |*  2 |   TABLE ACCESS FULL    | T_PART_20170619_LHR |     3 |   117 |    53   (4)| 00:00:01 |KEY(I) |KEY(I) |  --------------------------------------------------------------------------------------------------------------  Predicate Information (identified by operation id):  ---------------------------------------------------     2 - filter("T"."ID"=666 OR "T"."ID"=66666 OR "T"."ID"=77777 OR "T"."ID"=88888)  Note  -----     - dynamic sampling used for this statement (level=2)  Statistics  ----------------------------------------------------------            0  recursive calls            4  db block gets          217  consistent gets            0  physical reads            0  redo size          767  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            4  rows processed

本文選自《Oracle程式設計師面試筆試寶典》,作者:李華榮。

About Me:小麥苗

● 本文作者:小麥苗,只專註於資料庫的技術,更注重技術的運用

● 作者部落格地址:http://blog.itpub.net/26736162/abstract/1/

● 本系列題目來源於作者的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

● 題目解答若有不當之處,還望各位朋友批評指正,共同進步