聊聊Oracle 11g中的Reference Partition(下)

本文探讨了Oracle 11g的ReferencePartition特性在执行计划优化和管理方面的优势。通过实验对比了不同情况下的执行计划成本,并展示了在使用分区索引和直方图统计后的效果改善。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

上篇中,我们介绍了Reference Partition的创建、使用和原理。本篇将从性能和管理两个角度,讨论Reference Partition的作用。

 

4Reference Partition与执行计划

 

直观上看,Reference Partition应当是有益于执行计划的。主子表之间通过外键进行关联,最常用的业务场景就是借助外键列进行关联查询。如果主表记录是在一个或者几个分区上,那么子表对应的记录应该是在一个或者几个分区上。

这样,就从定义层面减少了数据访问量。下面通过一系列的实验进行证明。

 

 

SQL> explain plan for select * from t_master a, t_detail b where a.object_id=b.master_id;

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 2684484261

--------------------------------------------------------------------------------

| Id  | Operation            | Name     | Rows  | Bytes |TempSpc| Cost (%CPU)| T

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |          |   238K|    18M|       |   642   (3)| 0

|   1 |  PARTITION LIST ALL  |          |   238K|    18M|       |   642   (3)| 0

|   2 |   MERGE JOIN         |          |   238K|    18M|       |   642   (3)| 0

|   3 |    SORT JOIN         |          |   120K|  4936K|    12M|   222   (3)| 0

|   4 |     TABLE ACCESS FULL| T_MASTER |   120K|  4936K|       |   217   (1)| 0

|*  5 |    SORT JOIN         |          |   240K|  9403K|    23M|   419   (3)| 0

|   6 |     TABLE ACCESS FULL| T_DETAIL |   240K|  9403K|       |   412   (1)| 0

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   5 - access("A"."OBJECT_ID"="B"."MASTER_ID")

       filter("A"."OBJECT_ID"="B"."MASTER_ID")

 

19 rows selected

 

 

第一个语句我们没有加入分区条件,访问了所有的分区,路径中出现了“Partition List All”语句。注意:分区表的全表扫描,成本要大于扫描一张大表。分区表最大意义在于加入分区条件的查询语句。

第二个语句,我们加入主表的owner分区条件。

 

 

SQL> explain plan for select * from t_master a, t_detail b where a.object_id=b.master_id and owner='SCOTT';

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 3648887064

--------------------------------------------------------------------------------

| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT      |          |  2600 |   198K|   495   (1)| 00:00:06

|   1 |  PARTITION LIST SINGLE|          |  2600 |   198K|   495   (1)| 00:00:06

|*  2 |   HASH JOIN           |          |  2600 |   198K|   495   (1)| 00:00:06

|*  3 |    TABLE ACCESS FULL  | T_MASTER |  1312 | 49856 |    82   (0)| 00:00:01

|   4 |    TABLE ACCESS FULL  | T_DETAIL |   240K|  9403K|   412   (1)| 00:00:05

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("A"."OBJECT_ID"="B"."MASTER_ID")

   3 - filter("OWNER"='SCOTT')

 

17 rows selected

 

 

注意:该语句中,利用owner条件,扫描的重点集中在t_master的单一分区,进行了“Partition List Single”操作,扫描之后的结果,在子表中“一定对应”一个子表分区。所以对T_Detail的扫描也是Partition List Single

如果子表没有分区,我们进行一下实验。

 

 

SQL> create table t_normal as select * from t_detail;

Table created

 

SQL> commit;

Commit complete

 

SQL> exec dbms_stats.gather_table_stats(user,'T_NORMAL',cascade => true);

PL/SQL procedure successfully completed

 

 

查看执行计划:

 

 

SQL> explain plan for select * from t_master a, t_normal b where a.object_id=b.master_id and owner='SCOTT';

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1706510341

--------------------------------------------------------------------------------

| Id  | Operation              | Name     | Rows  | Bytes | Cost (%CPU)| Time

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT       |          |  2600 |   198K|   494   (1)| 00:00:0

|*  1 |  HASH JOIN             |          |  2600 |   198K|   494   (1)| 00:00:0

|   2 |   PARTITION LIST SINGLE|          |  1312 | 49856 |    82   (0)| 00:00:0

|*  3 |    TABLE ACCESS FULL   | T_MASTER |  1312 | 49856 |    82   (0)| 00:00:0

|   4 |   TABLE ACCESS FULL    | T_NORMAL |   240K|  9403K|   411   (1)| 00:00:0

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - access("A"."OBJECT_ID"="B"."MASTER_ID")

   3 - filter("OWNER"='SCOTT')

 

17 rows selected

 

 

请注意对T_NORMAL表的“Table Access Full”操作,它并没有涉及到分区。也就是说,从t_master中筛选到的记录owner=SCOTT’到T_NORMAL中,进行的是全表扫描操作。

从现在执行计划,我们的确看到了Reference Partition在执行计划上的优势。那么,还有无提升空间?

余地就是外键索引!为了避免大规模并发过程中出现死锁的情况,外键列是要求加索引的。笔者如果在Reference Partition的情况下,加入索引,会如何呢?

 

 

SQL> create index idx_t_detail_mas on t_detail(master_id) local;

Index created

 

SQL> exec dbms_stats.gather_table_stats(user,'T_DETAIL',cascade => true);

PL/SQL procedure successfully completed

 

 

执行计划:

 

 

SQL> explain plan for select * from t_master a, t_detail b where a.object_id=b.master_id and owner='SCOTT';

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

---------------------------------------

Plan hash value: 3648887064

------------------------------------------------

| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time

-----------------------------------------------------------

|   0 | SELECT STATEMENT      |          |  2600 |   198K|   495   (1)| 00:00:06

|   1 |  PARTITION LIST SINGLE|          |  2600 |   198K|   495   (1)| 00:00:06

|*  2 |   HASH JOIN           |          |  2600 |   198K|   495   (1)| 00:00:06

|*  3 |    TABLE ACCESS FULL  | T_MASTER |  1312 | 49856 |    82   (0)| 00:00:01

|   4 |    TABLE ACCESS FULL  | T_DETAIL |   240K|  9403K|   412   (1)| 00:00:05

--------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("A"."OBJECT_ID"="B"."MASTER_ID")

   3 - filter("OWNER"='SCOTT')

 

17 rows selected

 

 

执行计划没有改变,说明在CBO计算过程中,索引策略被分区策略成本值“打败”了。这个在很多没有特殊调优的分区表语句中十分常见。

笔者尝试了一下直方图路径,看是否可以生成更好的执行计划。

 

 

SQL> exec dbms_stats.gather_table_stats(user,'T_MASTER',cascade => true,method_opt => 'for all columns size auto');

 

PL/SQL procedure successfully completed

 

SQL> exec dbms_stats.gather_table_stats(user,'T_DETAIL',cascade => true,method_opt => 'for all columns size auto');

 

PL/SQL procedure successfully completed

 

 

执行计划情况:

 

 

SQL> explain plan for select * from t_master a, t_detail b where a.object_id=b.master_id and owner='SCOTT';

 

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

--------------------------------------------------

Plan hash value: 2296204501

------------------------------------------------------------------------------------------------------------------------

| Id  | Operation                           | Name             | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |

------------------------------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT                    |                  |    35 |  2730 |   136   (0)| 00:00:02 |       |       |

|   1 |  PARTITION LIST SINGLE              |                  |    35 |  2730 |   136   (0)| 00:00:02 |   KEY |   KEY |

|   2 |   NESTED LOOPS                      |                  |    35 |  2730 |   136   (0)| 00:00:02 |       |       |

|   3 |    NESTED LOOPS                     |                  |    36 |  2730 |   136   (0)| 00:00:02 |       |       |

|*  4 |     TABLE ACCESS FULL               | T_MASTER         |    18 |   684 |    82   (0)| 00:00:01 |     3 |     3 |

|*  5 |     INDEX RANGE SCAN                | IDX_T_DETAIL_MAS |     2 |       |     1   (0)| 00:00:01 |   KEY |   KEY |

|   6 |    TABLE ACCESS BY LOCAL INDEX ROWID| T_DETAIL         |     2 |    80 |     3   (0)| 00:00:01 |   KEY |   KEY |

------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   4 - filter("OWNER"='SCOTT')

   5 - access("A"."OBJECT_ID"="B"."MASTER_ID")

 

19 rows selected

 

 

索引路径走到,执行计划成本下降到136

说明:在使用Reference Partition的情况下,主子表外键连接的语句的确可以得到一定程度的性能提升。更容易生成更好的执行计划。

 

5、管理角度

 

从管理角度看,Reference Partition将主子表记录“牢牢”的绑定在一起,对应的分区也紧密关系在一起。

如果我们对主表分区进行操作处理,对应的子表分区也会进行自动的操作。下面我们操作t_master对象分区。

我们将主表分区p1摘除,仅从主从表记录关系看,数据库应该让先删除子表记录。

 

 

SQL> alter table t_master drop partition p1;

Table altered

 

 

摘除成功,说明Reference Partition连带影响子表分区被删除。

 

 

SQL> col num_rows for a10;

SQL> col high_value for a10;

SQL> col partition_name for a10;

SQL> col table_name for a10;

SQL> select table_name, partition_name, high_value,num_rows from dba_tab_partitions where table_owner='SYS' and table_name in

 

('T_DETAIL','T_MASTER');

 

TABLE_NAME PARTITION_ HIGH_VALUE   NUM_ROWS

---------- ---------- ---------- ----------

T_DETAIL   P0                         67992

T_DETAIL   P3                         97096

T_MASTER   P0         'PUBLIC'        33996

T_MASTER   P3         default         48548

 

 

主子表分区联动处理。

 

6、结论

 

Reference PartitionOracle 11g推出的一个重要的新特性。借助该特性,我们从定义分区表、管理分区表和使用分区表等多个方面,都可以得到很多好处。


第ⅰ部分 关键的数据库概念  第1章 oracle database 11g 体系结构  第2章 安装oracle database 11g 和创建数据库  第3章 升级到oracle database 11g  第4章 规划oracle 应用程序——方法、风险和标准 第ⅱ部分 sql 和sql*plus  第5章 sql 中的基本语法  第6章 基本的sql*plus 报表和命令  第7章 文本信息的收集与更改  第8章 正则表达式搜索  第9章 数值处理  第10章 日期:过去、现在及日期的差  第11章 转换函数与变换函数  第12章 分组函数  第13章 当一个查询依赖于另一个查询时  第14章 一些复杂的技术  第15章 更改数据:插入﹑更新﹑合并和删除  第16章 decode 和case:sql中的if-then-else  第17章 创建和管理表、视图、索引、群集和序列  第18章 分区 . 第19章 oracle 基本安全 第ⅲ部分 高 级 主 题  第20章 高级安全性——虚拟专用数据库  第21章 高级安全性:透明数据加密  第22章 使用表空间  第23章 用sql*loader 加载数据  第24章 使用data pump export 和data pump import  第25章 访问远程数据  第26章 使用物化视图  第27章 使用oracle text 进行文本搜索  第28章 使用外部表  第29章 使用闪回查询  第30章 闪回:表和数据库  第31章 sql 重放 第ⅳ部分 pl/sql  第32章 pl/sql 简介  第33章 应用程序在线升级  第34章 触发器  第35章 过程、函数与程序包  第36章 使用本地动态sql 和dbms_sql  第37章 pl/sql 调整 第ⅴ部分 对象关系数据库  第38章 实现对象类型、对象视图和方法  第39章 收集器(嵌套表和可变数组)  第40章 使用大对象  第41章 面向对象的高级概念 第ⅵ部分 oracle 中的java  第42章 java 简介  第43章 jdbc 程序设计  第44章 java 存储过程 第ⅶ部分 指 南  第45章 oracle 数据字典指南  第46章 应用程序和sql 调整指南  第47章 sql 结果缓存和客户端查询缓存  第48章 关于调整的示例分析  第49章 高级体系结构选项—— db保险库、内容db 和记录db  第50章 oracle 实时应用群集  第51章 数据库管理指南  第52章 oracle 中的xml 指南 第ⅷ部分 附 录 附录a 命令和术语参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值