Thedestination of a row is determined by the internal hash function applied to therow by the database. The hashing algorithm is designed to evenly distributesrows across devices so that each partition contains about the same number ofrows.
官方文档说明hashpartition 能够平衡每个分区上面的行的个数,做了个小测试,记录下来,供大家参考。
1. 创建一个hash分区表 , 一共四个分区,分区名称由系统自动生成。
--也可以替换为 create table hash_t (id number ) partition by hash(id) (partition&part_name1,partition &part_name2,partition &part_name3,partition&part_name4) ;
dexter@ORCL>create tablehash_t (id number ) partition by hash(id) partitions 4 ;
Tablecreated.
--查看一下表的统计信息,可以看到blocks为空但是segment已经创建
dexter@ORCL> select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME ,NUM_ROWS , BLOCKS , segment_created fromuser_tab_partitions ;
TABLE_NAMEPARTITION_NAMETABLESPACE_NAMENUM_ROWS BLOCKSSEG
---------- ------------------------------ ---------------------------------------- ---------- ---
HASH_T SYS_P29 USERSYES
HASH_T SYS_P28 USERSYES
HASH_T SYS_P30 USERSYES
HASH_T SYS_P31 USERSYES
--已经分配了extent
dexter@ORCL> select * from user_extents where segment_name='HASH_T' ;
SEGMENT_NAPARTITION_NAMESEGMENT_TYPETABLESPACE_NAMEEXTENT_ID BYTES BLOCKS
---------- ------------------------------ ------------------------------------------------ ---------- --------------------
HASH_T SYS_P28 TABLE PARTITION USERS 0 65536 8
HASH_T SYS_P29 TABLE PARTITION USERS 0 65536 8
HASH_T SYS_P30 TABLE PARTITION USERS 0 65536 8
HASH_T SYS_P31 TABLE PARTITION USERS 0 65536 8
--查看一下参数
dexter@ORCL> show parameter deferred_segment_creation
NAME TYPEVALUE
------------------------------------ -----------------------------------------
deferred_segment_creationboolean TRUE
--在11.2.0.1版本的oracle数据库中分区表不受deferred_segment_creation的影响,不会延迟分配segment
--但是在11.2.0.2版本的oracle数据库中加入了这个功能,官方文档中有提及,最下面有测试结果
/*
参数说明
DEFERRED_SEGMENT_CREATION specifies the semantics of deferred segment creation.
If set to true, then segments for tables and their dependent objects (LOBs,indexes) will not be created until the first row is inserted into thetable.
Before creating a set of tables, if it is known that a significant number ofthem will not be populated, then consider setting this parameter to true.
This saves disk space and minimizes install time.
*/
2. 初始化一些数据
dexter@ORCL> insert into hash_t select level from dual connectby level <= 100000 ;
100000rows created.
dexter@ORCL> commit ;
Commitcomplete.
3. 查看一下分区统计信息
--我们来收集一下统计信息,使用dbms_stats收集分区表的统计信息更加准确
dexter@ORCL> execdbms_stats.gather_table_stats('dexter','hash_t',cascade=>true);
PL/SQLprocedure successfully completed.
--可以看到分布的比较均匀
dexter@ORCL> select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME ,NUM_ROWS , BLOCKS fromuser_tab_partitions ;
TABLE_NAMEPARTITION_NAMETABLESPACE_NAMENUM_ROWSBLOCKS
---------- ------------------------------ ---------------------------------------- ----------
HASH_T SYS_P29 USERS 24956 43
HASH_T SYS_P28 USERS 24945 43
HASH_T SYS_P30 USERS 25209 43
HASH_T SYS_P31 USERS 24890 43
4. 插入 partition key 为7887 的 数据到分区表中
--在做一下测试看一下是否真的均匀分配
dexter@ORCL> select * from hash_t partition (sys_p29) where rownum <2 ;
ID
----------
7887
--插入一些id=7887 的数据 到分区表中
dexter@ORCL> insertinto hash_t select 7887 from dual connect by level <= 100000 ;
100000rows created.
dexter@ORCL>commit ;
Commitcomplete.
--再来分析一下
dexter@ORCL> execdbms_stats.gather_table_stats('dexter','hash_t',cascade=>true);
PL/SQLprocedure successfully completed.
--可以看到数据只分布到了sys_p29这个分区里面,也就是说当partition key 经过hash function 运算后放在了某一分区后,那么相同的partition key 的row就会在同一分区里面 , partition key 不会跨分区
--所以说hash partition 在每个partition 之间均匀分布数据也不是绝对的 , 因此最好不要使用 基数较低的 column 作为partition column
dexter@ORCL> select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME ,NUM_ROWS , BLOCKS fromuser_tab_partitions ;
TABLE_NAMEPARTITION_NAMETABLESPACE_NAMENUM_ROWSBLOCKS
---------- ------------------------------ ---------------------------------------- ----------
HASH_T SYS_P29 USERS 124956 244
HASH_T SYS_P28 USERS 24945 43
HASH_T SYS_P30 USERS 25209 43
HASH_T SYS_P31 USERS 24890 43
5. 再次验证测试结果
--再来测试一下其他情况的数据是否均匀分配
--清空数据
dexter@ORCL> truncate table hash_t ;
Tabletruncated.
dexter@ORCL>exec dbms_stats.gather_table_stats('dexter','hash_t',cascade=>true);
PL/SQLprocedure successfully completed.
dexter@ORCL>select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME , NUM_ROWS , BLOCKS from user_tab_partitions ;
TABLE_NAMEPARTITION_NAMETABLESPACE_NAMENUM_ROWSBLOCKS
---------- ------------------------------ ---------------------------------------- ----------
HASH_T SYS_P29 USERS 0 0
HASH_T SYS_P28 USERS 0 0
HASH_T SYS_P30 USERS 0 0
HASH_T SYS_P31 USERS 0 0
--初始化数据,id值只有 1,2,3
dexter@ORCL> insert into hash_t selectmod(level,3) from dual connect by level <= 100000 ;
100000rows created.
dexter@ORCL> commit ;
Commitcomplete.
dexter@ORCL>execdbms_stats.gather_table_stats('dexter','hash_t',cascade=>true);
PL/SQLprocedure successfully completed.
--可以看到,因为partitionkey 无法跨 分区 , 所以只有三个分区里面拥有数据
dexter@ORCL> select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME ,NUM_ROWS , BLOCKS fromuser_tab_partitions ;
TABLE_NAMEPARTITION_NAMETABLESPACE_NAMENUM_ROWSBLOCKS
---------- ------------------------------ ---------------------------------------- ----------
HASH_T SYS_P29 USERS 33333 58
HASH_T SYS_P28 USERS 0 0
HASH_T SYS_P30 USERS 33333 58
HASH_T SYS_P31 USERS 33334 58
6. 附录:11.2.0.3 版本数据库 分区表 延迟分配segment 测试
_sys@FAKE>select version from v$instance ;
VERSION
----------------------------------
11.2.0.3.0
_sys@FAKE>show parameter defe
NAME TYPEVALUE
------------------------------------ ----------------------------------------------------
deferred_segment_creationboolean TRUE
_dexter@FAKE>create table hash_t (id number )
2partition by hash(id)
3(partition &part_name1 tablespace users,
4partition &part_name2 tablespace example,
5partition &part_name3,
6partition &part_name4) ;
Enter value for part_name1: p_t1
old 3:(partition &part_name1 tablespace users,
new 3:(partition p_t1 tablespace users,
Enter value for part_name2: p_t2
old 4: partition &part_name2 tablespaceexample,
new 4: partition p_t2 tablespaceexample,
Enter value for part_name3: p_t3
old 5: partition &part_name3,
new 5: partition p_t3,
Enter value for part_name4: p_t4
old 6: partition &part_name4)
new 6: partition p_t4)
Tablecreated.
_dexter@FAKE>select TABLE_NAME, PARTITION_NAME, TABLESPACE_NAME , NUM_ROWS , BLOCKS , segment_created fromuser_tab_partitions where table_name='HASH_T'
TABLE_NAMEPARTITION_NAMETABLESPACE NUM_ROWS BLOCKS SEGMENT_
---------- ------------------------------ ---------- ---------- ------------------
HASH_T P_T1 USERS NO
HASH_T P_T2 EXAMPLE NO
HASH_T P_T3 USERS NO
HASH_T P_T4 USERS NO