테마
L2 · ora-burger — 인수한 버거 프랜차이즈 POS
포트 1522 · 계정
dev/dev· 크기 04화까지 약 2.6GB → 14화의 파티션 복사본까지 넣으면 약 11.5GB(12GB 한도에 거의 닿는다) · 쓰는 화 04 · 1404화 전에 만든다. 그 전에는 필요 없고, 켜 두면 메모리만 먹는다.
왜 이 컨테이너가 따로 있나 — ORD vs ORD_RANDOM
| 테이블 | 행수 | 왜 중요한가 |
|---|---|---|
ORD | 1,000,000 | 주문. 인덱스 ORD_X01의 클러스터링 팩터(CF)는 22,223으로 테이블 블록 수와 비슷하다. 잘 정렬되어 있다 |
ORD_RANDOM | 1,000,000 | 컬럼 · 행수 · 인덱스 정의가 ORD와 완전히 같다. 적재 순서만 무작위다. CF는 999,958로 행수와 비슷하다. 완전히 흩어져 있다 |
ORD_ITEM / ORD_ITEM_RANDOM | 2,472,717 | 주문상세의 두 버전 |
ORD_LIST · ORD_RANGE | 1,000,000 | LIST / RANGE 파티션(각 25개 파티션) |
ORD_LIST_HASH | 1,000,000 | LIST 25 × HASH 8 = 서브파티션 200개 |
ORD_ITEM_LIST(_HASH) · ORD_ITEM_RANGE | 2,472,717 | 상세의 파티션 버전 |
ORD_TEMP / ORD_TEMP2 | 1,000,000 | 적재용 스테이징. 다 쓰면 지워도 된다(합 ~1GB) |
SHOP · ITEM · UITEM · UITEM_PRICE · COM_CD | 7~260 | 코드·마스터 |
행수와 컬럼, 인덱스가 전부 같은데 CF만 45배 차이가 난다. "같은 인덱스인데 왜 하나는 쓰고 하나는 안 쓰나"를 다른 변수 없이 보여 주는 대조군이다. 04화가 바로 이 차이를 다룬다.
⚠️ 크다.
ORD_LIST_HASH하나가 100만 행에 3GB다. 파티션이 없는ORD는 같은 100만 행에 176MB이니 17배다. 거의 비어 있는 서브파티션 200개에 저마다 최소 익스텐트가 잡히기 때문이다. 버그가 아니라 14화에서 잴 바로 그 현상이다.
만들기
1. 기동 + 권한 (공통 절차, 이름·포트·계정만 다르다)
01_첫_고객사_ora-hanorder.md §3의 launch_ora / wait_ora 함수를 정의해 둔 셸에서 실행한다.
bash
launch_ora ora-burger 1522 dev
wait_ora ora-burgerbash
MSYS_NO_PATHCONV=1 docker exec -i ora-burger sqlplus -s / as sysdba <<'SQL'
ALTER SESSION SET CONTAINER = FREEPDB1;
GRANT CONNECT, RESOURCE, CREATE VIEW, CREATE PROCEDURE, UNLIMITED TABLESPACE TO dev;
GRANT SELECT_CATALOG_ROLE, SELECT ANY DICTIONARY, ALTER SESSION TO dev;
ALTER USER dev QUOTA UNLIMITED ON USERS;
SQLPowerShell에서는
<<'SQL'을 쓸 수 없다.02_접속과_실행_방법.md§4의 here-string 형태로 바꿔 쓴다.
2. 데이터 적재 — 한 번에 (약 5분)
Git Bash: 이 폴더에서 실행한다.
bash
bash 00_적재_한번에.shPowerShell: 이 폴더의 오라클튜닝에센셜\에서 실행한다. 스크립트 실행 정책에 걸리지 않도록 함수로 붙여 넣는다.
powershell
$OutputEncoding = New-Object System.Text.UTF8Encoding $false # 한글 상품명이 ? 로 깨지지 않게
function Feed($File, $Seed) {
& { 'SET SQLBLANKLINES ON'
if ($Seed) { "EXEC DBMS_RANDOM.SEED($Seed)" }
(Get-Content $File -Encoding UTF8) -replace '15000000', '1000000'
''; 'EXIT' } | docker exec -i ora-burger sqlplus -s dev/dev@localhost/FREEPDB1 | Out-Null
" $File 완료 $(Get-Date -Format HH:mm:ss)"
}
Feed 2.sql; Feed 3.sql; Feed 4.sql 20120101
@"
CREATE TABLE ORD_ITEM_TMP NOLOGGING AS SELECT * FROM ORD_ITEM;
TRUNCATE TABLE ORD_ITEM;
INSERT /*+ APPEND */ INTO ORD_ITEM SELECT * FROM ORD_ITEM_TMP ORDER BY ORD_NO, ITEM_ID;
COMMIT;
DROP TABLE ORD_ITEM_TMP PURGE;
"@ | docker exec -i ora-burger sqlplus -s dev/dev@localhost/FREEPDB1 # 주문상품 정돈
Feed 5.sql 20120101
@"
EXEC DBMS_STATS.GATHER_SCHEMA_STATS('DEV', method_opt=>'FOR ALL COLUMNS SIZE 1', cascade=>TRUE, no_invalidate=>FALSE);
"@ | docker exec -i ora-burger sqlplus -s dev/dev@localhost/FREEPDB1원본 생성기(오라클튜닝에센셜/, 저자 배포본)는 한 글자도 고치지 않는다. sqlplus에 흘려 넣을 때 네 가지만 덧붙인다.
| 덧붙이는 것 | 왜 | 빼면 |
|---|---|---|
SET SQLBLANKLINES ON | 원본의 CREATE TABLE 문 안에 빈 줄이 있다 | sqlplus가 빈 줄에서 문장을 끊는다. 그러면 테이블이 안 생기고 전부 0행이 된다 |
15000000 → 1000000 | 원본 건수(1,500만)는 Free의 12GB 한도를 넘긴다 | ORA-12954로 멈춘다 |
DBMS_RANDOM.SEED(20120101)(4와 5 앞) | 4.sql은 난수로 주문 일시, 매장, 상품을 만들고 5.sql은 난수로 순서를 섞는다 | 설치할 때마다 행수와 CF가 조금씩 달라져서 04화의 숫자와 내 화면이 안 맞는다 |
| 주문상품 정돈(4와 5 사이) | 4.sql은 주문상품을 주문마다 일반 INSERT로 넣기 때문에, 어느 블록에 들어가는지가 설치마다 조금씩 다르다 | 5.sql의 무작위 복사본(ORD_ITEM_RANDOM)이 받는 순서까지 달라져서 14화의 숫자가 안 맞는다 |
그 README는 컨테이너를 하나만 쓰던 시절(
oracle-free, 계정tester)에 쓴 문서다. 위 스크립트가 그 1~5단계를 대신하므로 원본 README의 실행 절차는 따라 하지 않는다.1.sql은 Windows 경로와 DBA 권한을 쓰는 원본이라 컨테이너에서는 돌릴 수 없다. 원본 README는 데이터 설명을 읽을 때만 연다.7.sql과9.sql(파티션 복사본, 약 9GB 추가)은 14화 직전에 넣는다. 04화에는 필요 없다. 아래 4번 「14화 전에: 파티션 복사본」을 참고한다.
3. 검증 — 이게 맞아야 04화가 성립한다
검증 결과는 스크립트 끝에 자동으로 찍힌다. 손으로 다시 확인하려면 다음을 실행한다.
sql
SELECT COUNT(*) FROM ord; -- 1,000,000
SELECT COUNT(*) FROM ord_item; -- 2,472,717
SELECT index_name, clustering_factor, num_rows, leaf_blocks
FROM user_indexes WHERE index_name IN ('ORD_X01','ORD_RANDOM_X01');
-- 기대: ORD_X01 = 22,223 (좋음) / ORD_RANDOM_X01 = 999,958 (나쁨) · LEAF 둘 다 3,774
SELECT item_nm FROM item WHERE item_id = 1; -- 한우불고기버거 (??? 면 PowerShell 인코딩 — 위 첫 줄)시드를 고정했으므로 끝자리까지 같아야 한다. 다르면 시드 줄이 빠졌거나(그러면
ORD_ITEM행수부터 어긋난다) 원본 파일이 바뀐 것이다. 💡 이관하거나 복원한 뒤에는 통계가 함께 넘어오지 않을 수 있다. CF가 비어 있으면EXEC DBMS_STATS.GATHER_SCHEMA_STATS('DEV', method_opt=>'FOR ALL COLUMNS SIZE 1');을 실행한 뒤 다시 본다.
4. 14화 전에 — 파티션 복사본 (약 40분 · 약 9GB 추가)
Git Bash: 이 폴더에서 실행한다.
bash
bash 01_파티션_적재.shPowerShell: 오라클튜닝에센셜\에서, 위 2번의 Feed 함수를 정의해 둔 창에서 실행한다.
powershell
Feed 7.partition.sql; Feed "8.comment_2(partition).sql"; Feed 9.partition_hash.sql; Feed "10.comment_3(partition_hash).sql"
@"
BEGIN
FOR t IN (SELECT table_name FROM user_tables WHERE table_name IN
('ORD_ITEM','ORD_ITEM_RANDOM','ORD_LIST','ORD_RANGE','ORD_ITEM_LIST','ORD_ITEM_RANGE','ORD_LIST_HASH','ORD_ITEM_LIST_HASH')) LOOP
DBMS_STATS.GATHER_TABLE_STATS(USER, t.table_name, estimate_percent=>100, method_opt=>'FOR ALL COLUMNS SIZE 1', cascade=>TRUE, no_invalidate=>FALSE);
END LOOP;
END;
/
"@ | docker exec -i ora-burger sqlplus -s dev/dev@localhost/FREEPDB1통계를 100% 표본으로 모으는 데는 이유가 있다. 기본값(자동 표본)으로 모으면 큰 인덱스의 CF와 리프 블록 수를 표본으로 추정하므로, 설치할 때마다 수천씩 다르게 나온다(실측: 같은 데이터에서
ORD_ITEM_X01CF 61,722 대 63,045). 14화는 바로 그 숫자를 읽는다. 시간은 대부분9.sql(서브파티션 200개)이 쓴다. 멈춘 게 아니다.
검증: 결과는 스크립트 끝에 찍힌다.
| 테이블 | 행수 | 파티션 · 서브파티션 | 크기 |
|---|---|---|---|
ORD_LIST · ORD_RANGE | 1,000,000 | 25 · 0 | 384MB |
ORD_ITEM_LIST · ORD_ITEM_RANGE | 2,472,717 | 25 · 0 | 771MB(LIST) |
ORD_LIST_HASH | 1,000,000 | 25 · 200 | 3,072MB |
ORD_ITEM_LIST_HASH | 2,472,717 | 25 · 200 | 3,072MB |
공간이 빠듯할 때
파티션 복사본까지 넣으면 약 11.5GB다. 여유 공간이 필요하면 스테이징 테이블(약 1GB)을 지운다. 2~4.sql로 언제든 다시 만들 수 있다.
sql
DROP TABLE DEV.ORD_TEMP PURGE;
DROP TABLE DEV.ORD_TEMP2 PURGE;안 쓸 때는 끈다
bash
docker stop ora-burger # 04·14화가 아니면 꺼 둔다 (메모리 1~1.5GB 회수)📄 전체 스키마 그림: 오라클튜닝에센셜/데이터_조감도_ERD_인덱스.md 📚 데이터 출처: 『오라클 튜닝 에센셜』 저자가 배포한 생성기(도메인: 패스트푸드 주문)