,我们可以通过手工解析表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 effect0×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 综上,我们可以使用下面的过程来查看hakan factor
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 对位图索引的影响
我们知道位图索引是通过起始rowid和结束rowid和位图的联合作用来定位数据。因此,我们处理需要知道起始rowid和终止rowid之外,还需要知道在每个数据块中的记录数量,而这往往是很难做到的,因为每个块中存储的记录数量是不等和变化的。在这种情况下,oracle计算每个数据块中记录数量的最大值,并根据这个最大值在位图中为每个数据块分配对应数量的标识位。而计算最大值的方法受hakan factor的影响。因此,如果我们减小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 ro