[Oracle block]
DB_BLOCK_SIZE 파라미터로 사이즈 조절 가능. 동적 변경은 불가.
사용자가 입력한 데이터를 하드디스크에 저장하거나 읽어들일 때 1건씩 처리하는 구조가 아닌 block단위로 작업한다.
block size가 크면 데이터가 작은 경우 공간이 낭비될 수 있고, wait time이 많이 생길 수 있다.
block size가 작으면 한 번에 담을 수 있는 데이터 양이 작아져 disk I/O가 많아진다.
OLTP면 block size를 8k, DW면 16k정도를 쓴다.
** 상세 구조
block header : 일반적인 blcok의 정보(위치, segment 형태)를 가짐.
table/row directory : 클러스터에 있는 테이블에 관한 정보 / block내의 row관련 정보.
free space : new row insert나 update 시 사용. PCTFREE, PCTUSED에 의해 결정.
row data : 실제 테이블 데이터와 인덱스 데이터가 저장됨.
** PCTUSED : 이걸로 지정된 값을 넘는 free space가 생기면 해당 block을 빈 공간으로 인식하고 block에 insert를 한다. PCTUSED+PCTFREE<=100이어야 한다.
** 만약 block에 delete가 돼서 빈 공간이 생겨도 11g이상 oracle부터는 빈 공간을 빈 공간으로 인식하지 않는다.(=PCTUSED가 없다.) 왜냐면 빈 공간으로 인식하면 그 공간에 데이터를 써야되는데 그러면 여기저기 왔다갔다 하면서 써야되고 header같은 것도 다시 써줘야 해서 시간이 오래 걸린다.
** Row Chaining : block size보다 큰 값이 insert 되면 2개 block이 묶이게 된다. 만약 이러면 I/O과정에서 2개의 block을 올렸다내렸다 해야돼서 안 좋다. 해결방법은 block size 크게 만드는 것.
** Row Migration : 기존에 데이터가 있던 block에 free space보다 큰 데이터를 insert를 할 때 발생. 여유 공간이 없으니 다른 block으로 이사를 가는 느낌. PCTFREE가 작다면 migration이 자주 발생. 늘리면 해결됨. 또는 reorg 작업을 해서 해결.
** reorg : 빈 공간을 반환해서 조회 성능을 높여주고 저장공간을 효율적으로 사용하도록 만든다. 이 작업을 할 때는 주말출근해서 작업해야된다.
[실습 – block 수 확인]
어제(51일차) 마지막에 한 [extent 할당 과정] 에 이어서 실습.
6. 테이블 정보 조회
select TABLE_NAME,
TABLESPACE_NAME,
PCT_FREE, -- default:10
PCT_USED, -- ASMM방식에선 사용X
INITIAL_EXTENT/1024, -- 초기할당 extent size
NEXT_EXTENT/1024, -- 다음할당 extent size
PCT_INCREASE -- 다음할당 extent size 증가값 (default 0)
from dba_tables
where table_name='EXTENT_TEST1';
7. delete 수행 후 통계정보 수집 후 block수 확인
delete from scott.extent_test1;
commit;
-- 통계 정보 수집
analyze table scott.extent_test1 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name = 'EXTENT_TEST1';
** delete 후에도 저장된 블럭 수는 이전과 동일. 저장공간을 반환하지 않았기 때문
8. truncate 후 통계정보 수집 후 block수 확인
truncate table scott.extent_test1;
-- 통계 정보 수집
analyze table scott.extent_test1 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name = 'EXTENT_TEST1';
** 저장된 block수 0으로 바뀜.
empty_blocks는 8임. -> 테이블 초기 extent=block 8개는 무조건 할당됨. 그래서 DEFERRED_SEGMENT_CREATION 을 끄면 create table하자마자 초기 extent(8block)이 생성되는 것.
초기 extent : 표준 테이블 header block, 메타데이터 저장용.
[reorg]
테이블 내 빈 블럭을 정리하고 저장된 행을 재배치하는 기법.
테이블 내 데이터가 추가, 삭제, 갱신되면서 공간이 흩어져 저장되고 중간에 비어있는 공간이 발생.
PCTUSED를 사용하지 않으면 delete로 인해 공간이 비어있어도 해당 공간을 재활용하지 않고 그대로 테이블 내 dirty block으로 가지고 있음.
비어 있는 공간이 많은 경우 실제 저장된 데이터에 비해 많은 블럭을 조회하면서 성능 문제가 발생함.
** reorg 방법
1) tablespace 재배치(동일 tablespace도 가능)
> alter table 테이블명 move tablespace 테이블스페이스명;
2) index rebuild
> alter index 인덱스명 rebuild;
** reorg 대상 확인
테이블 내 저장된 실블럭수와 할당된 블럭 수의 차이가 심한 경우 reorg를 진행.
delete, update가 자주 발생하는 테이블의 경우 주기적으로 reorg를 진행.
1. 테이블 할당된 블럭 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name = 'EXTENT_TEST1';
2. 실 블럭수 확인(실제 데이터가 차지하고 있는 블럭수)
SELECT COUNT(DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) ||
DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "실사용 블록수"
FROM scott.extent_test1;
[실습 – reorg 전후 할당된 블럭수 비교]
1. 테이블 생성
create table scott.extent_test2(no number, name varchar2(20), addr varchar2(20));
2. 대용량 insert
begin
for i in 1..500000 loop
insert into scott.extent_test2 values(i, dbms_random.string('a',19), dbms_random.string('q',19));
end loop;
commit;
end;
/
3. 현재 할당된 block수 확인
analyze table scott.extent_test2 compute statistics;
select table_name,
num_rows,
blocks,
empty_blocks
from dba_tables
where table_name='EXTENT_TEST2';
4. delete 후 할당된 블럭수 확인
delete from scott.extent_test2;
commit;
-- 통계 정보 수집
analyze table scott.extent_test2 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name = 'EXTENT_TEST2';
-- 조회
select * from scott.extent_test2;
-- 데이터는 0건이더라도 총 3520개 블럭을 불러오며 조회함. = 성능저하 발생
5. 실제 블럭수 확인
SELECT COUNT(DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) ||
DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "실사용 블록수"
FROM scott.extent_test2;
-- 이걸 쓰면 0블럭 나오는데 위에 4번에서 block수 확인 쿼리 쓰면 3520블럭 나옴.
-- 실제 사용 블럭 수와 해당 테이블에 할당된 블럭 수의 차이가 많이 나는 경우 reorg 진행 필요.
6. reorg 진행
alter table scott.extent_test2 move tablespace users;
또는
alter table scott.extent_test2 move;
-- tbs생략 시 기존 tbs에서 reorg 진행됨.
-- 정석적인 reorg는 이게 맞고. truncate를 해도 reorg와 같은 효과가 나오긴 한다.
7. 실 블럭수 및 할당 블럭수 확인
-- 통계 정보 수집
analyze table scott.extent_test2 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name = 'EXTENT_TEST2';
-- blocks가 3520에서 0으로 바뀜.
[extent management]
테이블스페이스 내 테이블 데이터가 입력되면 extent가 할당됨.
이때 extent 관리하는 방법을 정의할 수 있음.
1) DMT(Dictionary Management Tablespace)
– extent 할당 및 관리를 Dictionary에서 관리.
– Dictionary는 system tablespace에 저장.
– 중앙에서 관리하는 것은 용이하지만 속도가 느리다.
– 11g부터 사용 불가.
2) LMT(Locally Management Tablespace)
– extent 할당 및 관리를 각 tablespace에서 각각 관리.
– extent 현황을 각 tbs header에 저장.
– 8i 이후로는 LMT가 default.
– extent할당 방식에 따라 uniform, autoallocate 2가지로 나뉨.
** uniform
– 추가 할당 extent size를 일정하게 유지.
** autoallocate
– insert 양에 따라 추가 할당 extent size를 자동으로 조절.
[실습]
1. tablespace 내 extent 관리 방식 조회
select TABLESPACE_NAME,
BLOCK_SIZE, -- tbs별로 block size 지정 가능(default db_block_size와 동일)
INITIAL_EXTENT,
NEXT_EXTENT,
PCT_INCREASE,
EXTENT_MANAGEMENT, -- DMT vs LMT
ALLOCATION_TYPE -- UNIFORM vs SYSTEM(AUTOALLOCATE)
from dba_tablespaces;
2. tablespace 생성
1) DMT(12c 생성 불가)
create tablespace tbs_test1
datafile '/home/oracle/oradata/db1/tbs_test01.dbf' size 10m
extent management dictionary;
-- ORA-12913 : Cannot create dictionary managed tablespace
2) LMT
2-1) uniform
create tablespace tbs_test1
datafile '/home/oracle/oradata/db1/tbs_test01.dbf' size 50m
extent management local
uniform size 10m;
2-2) system(autoallocate)
create tablespace tbs_test2
datafile '/home/oracle/oradata/db1/tbs_test02.dbf' size 50m
extent management local
autoallocate;
-- 조회
select TABLESPACE_NAME,
BLOCK_SIZE,
INITIAL_EXTENT,
NEXT_EXTENT,
PCT_INCREASE,
EXTENT_MANAGEMENT,
ALLOCATION_TYPE
from dba_tablespaces
where tablespace_name like 'TBS_TEST%';
3. table 생성
create table scott.lmt_test1(no number) tablespace tbs_test1;
create table scott.lmt_test2(no number) tablespace tbs_test2;
insert into scott.lmt_test1 values(1);
insert into scott.lmt_test2 values(1);
commit;
select TABLE_NAME,
TABLESPACE_NAME,
INITIAL_EXTENT/1024, -- 초기 할당 extent size
NEXT_EXTENT/1024, -- next 할당 extent size
PCT_INCREASE
from dba_tables
where table_name like 'LMT_TEST%';
-- 자동관리 방식인 TBS_TEST2 tablespace에 생성된 LMT_TEST2 테이블의 NEXT_EXTENT size는 1m로 확인됨.
4. 통계정보 수집 및 블럭 현황
-- 통계 정보 수집
analyze table scott.lmt_test1 compute statistics;
analyze table scott.lmt_test2 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name like 'LMT_TEST%';
[segment space management]
segment 내 공간 할당 및 관리 방법을 정의하는 기능.
auto, manual로 관리.
tablespace별로 설정 가능.
dba_tablespaces 에서 조회 가능.
pct_free, pct_used, pctincrease 등을 설정.
1. manual segment space management (MSSM) : segment 내 저장 공간을 수동으로 관리하는 방식.
2. auto segment space management (ASSM) : segment 내 저장 공간을 자동으로 관리하는 방식. pctused 사용X.
** segment 내 space 관리 정책
1) pct_free
– 블럭 내 미리 할당하는 여유 공간
– update만을 위해 남겨두는 공간
– update 이후 row size가 커지는 경우 블럭 내 저장공간이 부족할 경우 row migration 발생(성능 저하 발생)
– update가 빈번한 테이블의 경우 pct_free 여유있게 설정
– pct_free가 큰 경우 보다 적은 수의 row가 저장
– default 10
2) pct_used
– 해당 블럭을 다시 재사용 블럭으로 인식하기 위한 임계값
– pct_used가 50%인 경우 전체 블럭의 50%미만으로 사용율이 떨어지면 freelist에 등록, 재사용 가능
– ASSM일 경우 사용X
3) pctincrease
– next extent의 사이즈의 증가 비율
[실습]
1. 조회
select tablespace_name,
segment_space_management
from dba_tablespaces;
2. tablespace 생성
-- 2-1) auto
create tablespace TBS_TEST3
datafile '/home/oracle/oradata/db1/tbs_test03.dbf' size 10m
segment space management auto;
-- 2-2) manual
create tablespace TBS_TEST4
datafile '/home/oracle/oradata/db1/tbs_test04.dbf' size 10m
default storage(initial 1m
next 1m
pctincrease 0);
create tablespace TBS_TEST5
datafile '/home/oracle/oradata/db1/tbs_test05.dbf' size 10m
segment space management manual
default storage(initial 1m
next 1m
pctincrease 0);
-- 조회
select TABLESPACE_NAME,
SEGMENT_SPACE_MANAGEMENT,
INITIAL_EXTENT,
NEXT_EXTENT,
PCT_INCREASE
from dba_tablespaces
where tablespace_name like 'TBS_TEST%';
3. table 생성
create table SCOTT.assm_test1(no number) tablespace TBS_TEST3;
create table SCOTT.assm_test2(no number) tablespace TBS_TEST5;
create table SCOTT.assm_test3(no number)
tablespace TBS_TEST4
pctfree 20
pctused 20
storage(initial 2m
next 2m
pctincrease 50);
insert into scott.assm_test1 values(10);
insert into scott.assm_test2 values(10);
insert into scott.assm_test3 values(10);
commit;
select TABLE_NAME,
TABLESPACE_NAME,
PCT_FREE,
PCT_USED,
INITIAL_EXTENT,
NEXT_EXTENT,
PCT_INCREASE
from dba_tables
where table_name like 'ASSM_TEST%';
--> ASSM_TEST1 테이블의 경우 테이블 생성 시 별도 storage 정책을 명시하지 않았기 때문에 tablespace 관리 정책(AUTO)을 따름. TBS_TEST3 테이블스페이스 생성 시 별도의 storage 정책이 없었으므로 default 관리 정책에 따라 테이블이 생성됨.
--> ASSM_TEST2 테이블의 경우 TBS_TEST5 테이블스페이스에 저장되어 있는데 이 테이블스페이스는 수동관리 방식이므로 테이블스페이스 생성 시 명시한 storage 정책대로 테이블이 관리되면 PCT_USED 지정이 가능.
--> ASSM_TEST3 테이블의 경우 TBS_TEST4 테이블스페이스에 저장되어 있는데 별도의 storage 옵션을 갖는 ASSM 관리 방식이다. 하지만 테이블 생성 시 별도의 storage 옵션을 사용하였기 때문에 몇몇 옵션(PCT_USED, PCT_INCREASE 등)을 제외하고는 테이블 자체적인 storage 옵션이 지정되어 관리된다.
[실습 – pct_free 크기에 따른 저장공간 차이]
pct_test1 table : pct_free 10%(default)
pct_test2 table : pct_free 50% 로 생성 후
동일한 데이터를 대량 insert 시 최종적으로 할당된 블럭수를 비교
1. table 생성 및 데이터 삽입
create table scott.pct_test1(no number, name varchar2(10));
create table scott.pct_test2(no number, name varchar2(10)) pctfree 50;
begin
for i in 1..500000 loop
insert into scott.pct_test1
values(i, DBMS_RANDOM.string('A',4));
end loop;
commit;
end;
/
begin
for i in 1..500000 loop
insert into scott.pct_test2
values(i, DBMS_RANDOM.string('A',4));
end loop;
commit;
end;
/
select table_name, pct_free, pct_used
from dba_tables
where table_name like 'PCT_TEST%';
2. 두 테이블에 저장된 블럭 수 비교
-- 통계 정보 수집
analyze table scott.pct_test1 compute statistics;
analyze table scott.pct_test2 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name like 'PCT_TEST%';
-- PCT_TEST1 : 1126 + 26 블럭
-- PCT_TEST2 : 1882 + 38 블럭
pct_test1의 경우 free가 작아서 한 블럭에 더 많은 데이터를 담을 수 있어서 블럭 수가 더 적다.
[실습 – pct_free 크기에 따른 row migration 차이]
1. 전체 update 수행
update scott.pct_test1
set name = 'AAAAAAAAAA';
commit;
update scott.pct_test2
set name = 'AAAAAAAAAA';
commit;
2. 블럭 수 비교
-- 통계 정보 수집
analyze table scott.pct_test1 compute statistics;
analyze table scott.pct_test2 compute statistics;
-- block 수 확인
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS
from dba_tables
where table_name like 'PCT_TEST%';
-- PCT_TEST1 : 2638 + 50 블럭
-- PCT_TEST2 : 1882 + 38 블럭
pct_test1의 경우 free가 작아서 update 이후 많은 수의 블럭이 추가됨. -> row migration 발생.
pct_test2의 경우 free가 커서 update 이후 블럭수 변화 없음. -> 기존 블럭의 free에서 처리 다 함.
[row chain]
block size에 비해 큰 row가 입력되는 경우 인근에 있는 둘 이상의 블럭에 저장되는 상태
[실습]
1. table 생성
create table scott.row_chain1(a varchar2(4000), b varchar2(4000), c varchar2(4000));
2. insert 수행
insert into scott.row_chain1 values(DBMS_RANDOM.STRING('A',4000),DBMS_RANDOM.STRING('A',4000),DBMS_RANDOM.STRING('A',4000));
insert into scott.row_chain1 values(lpad('A',4000,'A'),lpad('B',4000,'B'),lpad('C',4000,'C'));
commit;
3. 블럭 수 확인
analyze table scott.row_chain1 compute statistics;
select TABLE_NAME,
NUM_ROWS,
BLOCKS,
EMPTY_BLOCKS,
chain_cnt -- row chain 횟수
from dba_tables
where table_name like 'ROW_CHAIN%';
[deferred segment creation]
– table 생성 시 segment를 즉시 할당할 지 여부를 결정하는 파라미터
– deferred_segment_creation
– 11g 부터 true default
select name, value
from v$parameter
where name like %deferred%';
[case1. users tbs에 새로 table 생성 후 seq 적용]
아무리해도 안된다 ㅋㅋㅋ
-- sequence 생성
create sequence sequence_test1;
-- table 생성
create table scott.deferred_test1
(no number default sequence_test1.nextval,
name varchar2(10));
-- insert 후 조회
insert into scott.deferred_test1 (name) values ('a');
commit;
insert into scott.deferred_test1 values(sequence_test1.nextval, 'b');
commit;
select * from scott.deferred_test1;
create sequence seq_test1;
create table scott.deferred_test11 (no number);
insert into scott.deferred_test11 values(seq_test1.nextval);
select * from scott.deferred_test11;
-- scott으로 실행
create sequence seq_test111;
create table deferred_test111 (no number);
insert into deferred_test111 values(seq_test111.nextval);
commit;
select * from scott.deferred_test111;
[case2. users tbs에 기존 table truncate 후 seq 적용]
[case3. system tbs에 새로 table 생성 후 seq 적용]