Hakan factor
Hakan factor 用来表示在表中任何一个数据块所包含的记录数量的上限。对于一个表来说,Hakan factor 受一下几方面的影响:
- 表中列的数量
- 列的数量类型和长度
- 列是否具有非空约束
数据库大小 |
每块可以存储的最大记录数(抛出部分控制信息) |
2048 |
178(2048/11=186) |
4096 |
364(4096/11=194) |
8192 |
736(8192/11=744) |
16384 |
1481(16384/11=1489) |
32768 |
2971(32767/11=2978) |
下面我们来论证一下,(show_hakan函数来源于网络,函数的内容请参见文章底部):
SQL> create table tab1(c1 char(1));
表已创建。
SQL> execute show_hakan('tab1');
--Hakan factor for object 364291 (SCOTT.tab1) is 736 with flags 0
PL/SQL 过程已成功完成。
SQL> insert into tab1 select 'a' from dual connect by level < 1000;
已创建999行。
SQL> commit;
提交完成。
SQL> execute show_hakan('tab1');
--Hakan factor for object 364291 (SCOTT.tab1) is 736 with flags 0
PL/SQL 过程已成功完成。
SQL> create table tab2(c1 char(100),c2 char(300));
表已创建。
SQL> execute show_hakan('tab2');
--Hakan factor for object 364292 (SCOTT.tab2) is 736 with flags 0
PL/SQL 过程已成功完成。
SQL> insert into tab2 select 'a','b' from dual connect by level < 1000;
已创建999行。
SQL> commit;
提交完成。
SQL> execute show_hakan('tab2');
--Hakan factor for object 364292 (SCOTT.tab2) is 736 with flags 0
PL/SQL 过程已成功完成。
SQL> alter table tab2 modify c1 not null;
表已更改。
SQL> alter table tab2 modify c2 not null;
表已更改。
SQL> execute show_hakan('tab2');
--Hakan factor for object 364292 (SCOTT.tab2) is 19 with flags 0
PL/SQL 过程已成功完成。
从上面的情况也可以看出,oracle在计算 hakan factor时,是以可能发生的最大值为其计算结果。alter table minimize records_per_block
oracle并没有为我们提供显示修改或者查看hakan factor的功能,但是我们可以通过一些变通的方式来实现这些功能。alter table ... minimize RECOREDS_PER_BLOCK的工作过程如下:
- 扫描整个表
- 计算表中每个块中包含的记录数量
- 设置表的hakan factor为块记录数量的最大值
- 设置标志位为ox8000(),表示表的hakan factor通过records_per_block设置
通过recors_per_block设置hakan factor 后,当我们后续向表中添加记录时,每个数据块的记录数不会超过hakan factor设置的值。
SQL> create table tab1(c1 number);
表已创建。
SQL> alter table tab1 minimize records_per_block;
alter table tab1 minimize records_per_block
*
--第 1 行出现错误:
--ORA-28603: 不允许对空表使用语句
SQL> insert into tab1 values(1);
已创建 1 行。
SQL> commit;
提交完成。
SQL> insert into tab1 select * from tab1;
已创建 1 行。
SQL> /
已创建2行。
SQL> commit;
提交完成。
SQL> alter table tab1 minimize records_per_block;
表已更改。
SQL> execute show_hakan('tab1');
Hakan factor for object 364293 (SCOTT.tab1) is 3 with flags 8000
PL/SQL 过程已成功完成。
SQL> insert into tab1 select * from tab1;
已创建4行。
SQL> /
已创建8行。
SQL> commit;
提交完成。
SQL> select
ct, count(*)
from (
Select Dbms_Rowid.Rowid_Block_Number(Rowid), Count(*) Ct
from tab1
group by
dbms_rowid.rowid_block_number(rowid)
)
Group By Ct
order by ct 2 3 4 5 6 7 8 9 10
11 /
CT COUNT(*)
---------- ----------
4 4
SQL> create bitmap index i1 on tab1(c1);
索引已创建。
SQL> alter table tab1 nominimize records_per_block;
alter table tab1 nominimize records_per_block
*
第 1 行出现错误:
ORA-28602: 不允许对包含位图索引的表使用语句
SQL> create table tab2(c1 number);
表已创建。
SQL> create bitmap index i2 on tab2(c1);
索引已创建。
SQL> insert into tab2 values(1);
已创建 1 行。
SQL> commit;
提交完成。
SQL> alter table tab2 minimize records_per_block;
alter table tab2 minimize records_per_block
*
--第 1 行出现错误:
--ORA-28602: 不允许对包含位图索引的表使用语句
SYS.TAB$.SPARE1
oracle没有给我们提供直接的视图来查询hakan factor,我们可以通过手工解析表SYS.TAB$的spare1字段来获取有个hakan factor的信息。下面对spare1字段内容的解释来源与网络
- Lower bits (at least 12, perhaps as many as 15): Håkan factor.
- 0×08000: MINIMIZE RECORDS_PER_BLOCK in effect
- 0×10000: Seems to mean that the Håkan factor has been fixed higher than the value calculated from non-null columns. This could be e.g. if set by event 14529 (see below) or if non-null columns have been added after a bitmap index has been created.
- 0×20000: Table compression is enabled
create or replace procedure show_hakan(
i_table in varchar2,
i_owner in varchar2 default user
) as
m_obj number(8,0);
m_flags varchar2(12);
m_hakan number(8,0);
begin
select
obj#,
to_char(
bitand(
spare1, to_number('ffff8000','xxxxxxxx')
),
'xxxxxxxx'
) flags,
bitand(spare1, 32767) hakan -- 0x7fff
into
m_obj,
m_flags,
m_hakan
from
tab$
where obj# in (
select object_id
from dba_objects
where object_name = upper(i_table)
and object_type = 'TABLE'
and owner = upper(i_owner)
)
;
dbms_output.put_line(
'Hakan factor for object ' ||
m_obj || ' (' ||
i_owner || '.' ||
i_table || ') is ' ||
m_hakan || ' with flags ' ||
m_flags
);
end;
/
drop public synonym show_hakan;
Create Public Synonym Show_Hakan For Show_Hakan;
grant execute on show_hakan to public;
Hakan factor 对位图索引的影响
SQL> create table t1(c1 number);
表已创建。
SQL> insert into t1 values(1);
已创建 1 行。
SQL> /
已创建 1 行。
SQL> /
已创建 1 行。
SQL> alter table t1 minimize records_per_block;
表已更改。
SQL> create table t2 as select * from t1;
表已创建。
SQL> alter table t2 minimize records_per_block;
表已更改。
SQL> execute show_hakan('t1');
Hakan factor for object 78156 (EASY.t1) is 2 with flags 8000
PL/SQL 过程已成功完成。
SQL> execute show_hakan('t2');
Hakan factor for object 78157 (EASY.t2) is 2 with flags 8000
PL/SQL 过程已成功完成。
SQL> insert into t1 select * from t1;
已创建 3 行。
SQL> /
已创建 6 行。
SQL> /
已创建 12 行。
SQL> /
已创建 24 行。
SQL> /
已创建 48 行。
SQL> /
已创建 96 行。
SQL> /
已创建 192 行。
SQL> /
已创建 384 行。
SQL> /
已创建 768 行。
SQL> /
已创建 1536 行。
SQL> /
已创建 3072 行。
SQL> /
已创建 6144 行。
SQL> /
已创建 12288 行。
SQL> /
已创建 24576 行。
SQL> truncate table t2;
表被截断。
SQL> insert into t2 select * from t1;
已创建 49152 行。
SQL> commit;
提交完成。
select
ct, count(*)
from (
Select Dbms_Rowid.Rowid_Block_Number(Rowid), Count(*) Ct
from t1
group by
dbms_rowid.rowid_block_number(rowid)
)
Group By Ct
10 order by ct
11 /
CT COUNT(*)
---------- ----------
3 16384
select
ct, count(*)
from (
Select Dbms_Rowid.Rowid_Block_Number(Rowid), Count(*) Ct
from t2
group by
dbms_rowid.rowid_block_number(rowid)
)
Group By Ct
10 order by ct
11 /
CT COUNT(*)
---------- ----------
3 16384
SQL> alter table t1 nominimize records_per_block;
表已更改。
SQL> insert /*+append*/ into t1 select * from t1 where rownum<64;
已创建 63 行。
SQL> commit;
提交完成。
SQL> alter table t1 minimize records_per_block;
表已更改。
SQL> execute show_hakan('t1');
Hakan factor for object 78156 (EASY.t1) is 62 with flags 8000
PL/SQL 过程已成功完成。
select
ct, count(*)
from (
Select Dbms_Rowid.Rowid_Block_Number(Rowid), Count(*) Ct
from t1
group by
dbms_rowid.rowid_block_number(rowid)
)
Group By Ct
10 order by ct
11 /
CT COUNT(*)
---------- ----------
3 16384
63 1
SQL> create bitmap index i1 on t1(c1);
索引已创建。
SQL> create bitmap index i2 on t2(c1);
索引已创建。
SQL> select segment_name,blocks from user_segments where segment_name like 'I%';
SEGMENT_NAME BLOCKS
--------------------------------------------------------------------------------- ----------
I1 16
I2 8
SQL> insert into t2 select * from t2 where rownum<64;
已创建 63 行。
SQL> commit;
提交完成。
SQL> select segment_name,blocks from user_segments where segment_name like 'I%';
SEGMENT_NAME BLOCKS
--------------------------------------------------------------------------------- ----------
I1 16
I2 8