티스토리 뷰
기존에 19c를 운영하다 11g 환경에서 유지보수를 하게되어 버전별로 차이를 공부하고 그 내용을 정리해보고자 합니다. 또한 11g에서 사용할 수 없는 기능이 무엇인지 알기 위한 목적도 있습니다.
Oracle Database(오라클 데이터베이스) 12c Release 1이 발표된 지 2년이 지났다. 여러 가지 변화가 있다. 데이터베이스 아키텍처에서는 멀티테넌트(Multitentant) 개념이 생겼으며, 여러 기능 등이 추가됐다.
이번 칼럼에서는 12c에서 추가된 SQL 기능 중 하나 인 Top-N 쿼리의 새로운 기능에 대해서 살펴보고자 한다. 이전 버전 Oracle Database에서는 Top-N 쿼리는 구현하기 위해서는 ROWUNM을 이용한 형식으로 작성해야 된다. 예를 들어 메일 게시판에서 아이디가 xxx@gmail.com인 내역을 도착시간 기준으로 10 rows만 출력하기 위해서는 뽑기 위해서는 <리스트 1>과 같이 쿼리를 쓸 수 있다.
<리스트 1> 예시 상황에서의 쿼리
select 종류, 제목, 도착시간, 크기
from (select /*+ index_desc(메일,메일_아이디_도착시간) */
rownum 순번,번호, 종류,제목,도착시간, 크기
from 메일
where 메일_아이디 = 'xxx@gmail.com'
and rownum < = 10
order by 도착시간 desc )
where 순번 between 1 and 10 ;
위 쿼리에서도 처음 10 rows을 가지고 오는 경우에는 문제 없지만 Page 뒤로 넘어 갈수록 View 안에서 읽어 정렬해야 되는 데이터가 늘어난다. 즉 10 Page “where 순번 between 100 and 110”에 해당되는 10건만 가져온다고 하더라도 110 rows 읽고 정렬해야 된다. 즉 뒤로 갈수록 부하가 가는 쿼리라고 할 수 있다. 그래서 성능을 보장하기 위해서는 각 페이지에 출력되는 rowed 주소를 알아야 하며, 그 주소로 필요한 데이터만 출력해야 된다.
<리스트 2> 메일 테이블 인덱스만 이용해 랜덤 액세스 하는 쿼리
SELECT /*+ ORDER USE_NL(정보,메일) */
메일.종류, 메일.제목, 메일.도착시간, 메일.크기, CEIL(정보.총건수/20) 페이지수
FROM (select 데이터주소, 총건수
from (SELECT /*+ INDEX(메일, 메일아이디_도착시간_idx) */ ROWID 데이터주소,
ROW_NUMBER() OVER (ORDER BY 도착시간 DESC, ROWID DESC ) 순번,
COUNT(메일_아이디) OVER ( PARTITION BY 1) 총건수
FROM 메일
<리스트 2>는 메일 테이블의 인덱스만을 이용해서 해당 페이지에서 출력될 ROWID만 출력하여 그 정보를 가지고 테이블에 랜덤 엑세스 하는 구조이다. 이런 구조 형식이면 페이지가 뒤로 넘어 갈수록 늘어지는 현상은 없다.
이와 같이 12c 1 버전 이하에서는 목록쿼리를 작성하기 위해서는 rownum을 사용해야 한다. 또한 위 예제는 단일 테이블인데 다수의 테이블의 조인해서 나오는 목록쿼리라면 난이도는 더 올라간다. 12c에서는 다음과 같이 목록쿼리 작성하기 위한 새로운 구문(Syntax) “row_limiting_clause”가 추가됐다. Order by 뒤에 기술해 사용하면 된다.
<그림 1>에서 OFFSET은 쿼리 결과값이 나오기 전에 제한할(SKIP) 행의 수를 지정한다. 음수을 지정하지 않으며, Null으로 지정하거나 쿼리에서 반환되는 출력건수와 OFFSET이 동일할 경우 0 Rows을 반환한다. 또한 소수점이 있는 경우는 잘리는 특징을 가지고 있다. FETCH는 지정한 rows(or percentage)을 기준으로 rows 건수를 출력한다. 이 FETCH 절을 생략한 경우는 전체를 반환하거나 시작된 offset rows에 +1을 출력한다. 예제를 통해 주의사항과 사용방법을 살펴보자. 확인하기 쉽도록 순번 컬럼을 추가했다.
<리스트 3> 쿼리 예제
## 도착시간 기준으로 10 Rows 만 추출.
SQL> select 메일_아이디,제목,도착시간,순번
2 from 메일
3 where 메일_아이디 = 'xxxx@gmail.com'
4 order by 도착시간 fetch next 10 rows only;
메일_아이디 제목 도착시간 순번
--------------- ------------------------------ ------------------- ---
xxxx@gmail.com /1000323d_DelegateInvocationHa 2015-07-10 22:58:06 1
xxxx@gmail.com /1000e8d1_LinkedHashMapValueIt 2015-07-11 22:58:06 2
생략 ~
xxxx@gmail.com /101419a4_NormalDataCollector 2015-07-18 22:58:06 9
xxxx@gmail.com /101b40ef_EncapsInputStreamFac 2015-07-19 22:58:06 10
Fetch 구문을 추가 되면서 원하는 rows만 출력하게 되었다. 다시 말해 between과 틀린 점은 Top-N 쿼리로 형식으로 동작한다는 점이다. 앞에서 출력한 rows만큼 생략하고 출력하기 위해서는 rowset절이 들어가야 된다. 하단의 예는 위에서 출력한 10 rows을 제외하고 2 rows을 출력한다.
FETCH절은 ROWS 뿐만 아니라 Percent 단위로 출력이 가능하다. 메일 테이블에서 ‘xxxx@gmail.com’ 메일 아이디를 가지고 있는 rows는 100 row이므로 1 row에 1%로 계산하면 된다.
<리스트 4> FETCH절을 Percent 단위로 출력
SQL> select count(*) from 메일
2 where 메일_아이디 = 'xxxx@gmail.com' ;
COUNT(*)
----------
100
마지막으로 row only, row ties의 차이를 설명하겠다. 데이터를 추출하는 값에 중복 값이 있을 경우 같이 출력하는지 여부의 차이다. Percent도 동일하게 동작한다. 이렇게 Top-N Query를 생성하는 것이 간단해졌다. 하지만 Trace을 떠서 실행 내역을 보면 기존 rownum을 이용해서 출력하는 방법과 동일하다. MSSQL처럼 별도의 컬럼을 이용하는 것이 아니라 12c 이전 버전에서 사용하는 방식대로 옵티마이저가 대신 계산해서 풀어주는 것이다. 여전히 인덱스 여부와 조인 방식에 따라 쿼리 성능이 중요하게 작용할 것으로 예상한다.
데이터베이스 관리 부분 New features
1.온라인작업
1-1. 향상된 온라인 DDL 기능
drop index
drop constraint
set unused column
alter index unusable
alter index visible
alter index invisible
online 키워드를 붙여서 온라인 작업으로 실행 가능.
예 : drop index test idx 01 online;
1-2. 온라인 재구성 작업에서 사용 가능한 Lock Timeout
테이블의 온라인 재정의 작업이 끝날 때는 DBMS REDEFINITION의
finish_redef_table 프로시저가 실행함으로써 완료되며
락을 획득할 때까지 대기하는 시간을
ddl_lock_timeout 파라미터로 프로시저 내에 정의해서 사용할 수 있다.
1-3. 데이터파일온라인이동
alter database 명령에 move datafile 옵션을 사용
alter database move datafile
' /u01 /app/oracle/oradata/NEW12C/datafile/o1_mf_users_01.dbf '
to
' / u01 /app/oracle/oradata/NEW12C/datafile/o1_mf_users .dbf ' ;
파일이 이미 존재하는 경우는 해당 작업은 실패 한다. (책의 예시는 오타로 보임)
12c에서는 데이터 파일을 적절히 온라인으로 rename이나 이동을 수행한다.
keep 사용시 원본 유지
' /uO1/app/oracle/oradata/orcl/usersO1_orcl.dbf' keep;
reuse 사용시 덮어쓰기
'/uO1/app/oracle/oradata/orcl/usersO1 orcl .dbf' reuse;
1-4. 특정 테이블이나 파티션의 스토리지 절에 관련된 정의를 재정의하는 단일 명령
테이블스페이스변경
Compress 변경
SecurueFile이나 BasicFile 스토리지에 LOB 컬럼 변경
dbms_redefintion 패키지에 신규로 지원되는
redef_table 프로시저를 통해서 이루어진다.
VPD 정책이 설정되어 있는 테이블의 재구성 작업 지원
정책복사
dbms_redefintion.cons_ vpd_none:
원본 테이블에 VPD 정책이 없음을 지정한다(디폴트).
만약 이 테이블에 VPD 정책이 있다면 에러가 발생한다.
dbms_redefintion.cons_vpd_auto:
VPD 정책이 원본 테이블에서 새로운 테이블로 자동으로 복사됨을 지정한다.
dbms_redefintion.cons_ vpd_manual:
VPD 정책을 수동으로 재정의 과정에서 원본 테이블에서 신규 테이블로 복사되는 것을 지정한다.
dbms_redefintion.cons_vpd_auto 이 되지 않을 때 사용.
2. 데이터베이스 모니터링과 관리
2-1. Oracle Enterprise Manager Database Express
미들웨어가 사라진 가벼운 버전
기존의 Oracle Enterprise Manager Database Control을 대체 한다.
주요 4개 영역
Database Configuration : 초기화 파라미터, 메모리, 데이터베이스 기능 사용 현황, 현재 데이터베이스속성
Storage: 테이블 스페이스, 언두 관리, 리두 로그 그룹, 아카이브 로그, 컨트롤 파일
Security: 유저,롤, 프로파일
Performance: Performance Hub와 SQL Tuning Advisor
-> 뒤에 또 언급되지만 결국 Oracle Enterprise Manager Database Control 이 필요하다. 대체라고 보기엔 무리가 있다.
2-2. Real-time 데이터베이스 작업 모니터링
12c의 Real-time SQL 모니터링은 SQL문의 병렬 실행과 DDL 문장에 대해 모니터링을 시작한다.
그밖의 SQL문은 단일 실행에서 CPU나 I/0 를 소모하면서 수행한 시간이 5초 이상이면 모니터링을 수행한다.
2-3 Real-time ADDM 모니터링
CPU 부하가 높고 I/0 부하가 큰 경우 오라클은 현재 성능 문제를 찾는 데 도움을 줄 ADDM 실행한다.
3. 기타관리기능
3-1. PGA 사이즈제한
PGA AGGREGATE LIMIT 파라미터가 추가 되었다.
디폴트로 PGA AGGREGATE LIMIT는 2GB, PGA_AGGREGATE_TARGET 값의 200%, 3MB x PROCESSES 초기화 파라미터 값
중 가장 큰 값으로 설정된다. 또한 이 사이즈는 전체 시스템의 물리 메모리의 합계에서 SGA의 크기의 뺀 사이즈의 120%를 초과할 수 없다.
3-2. 새로운 관리자 권한
권한을 더욱 세분화 하였다.
SYSBACKUP : 데이터베이스상의 백업과 복구 작업에 수행할 때 필요한 모든 작업이 가능
SYSDG : 데이터 가드 작업을 수행할 때 띨요한 작업이 가능. 이 권한은 Data guard Broker 또는 DGMGRL 커맨드라인 인터페이스를 사용할 수 있는 권한
SYSKM : TDE 관리자 작업을 수행하는 데 팔요한 모든 작업이 가능
3-3. Real Application Testing 변경사항와 기타 변경사항
3-3-1. 오라클 Database Control에서 삭제
RAT기능은 12c Database Express에서 제공하지 않는다.
3-3-2. 데이터 마스킹 변경사항
오라클 데이터베이스 12c에서는 Enterprise Manager Cloud Control 12c를 사용해서 데이터 세브세팅이라는 새로운 마스킹 기능을 제공한다.
서브세팅된 데이터를 가진 테이블의 특정 컬럼을 삭제하는 기능
데이터 펌프 익스포트 파일에 쓰는 Mask 인라인 기능
3-3-3. Database Replay 새로운 기능
3-3-3-1. 통합된 Database Replay
복수 개의 소스 데이터베이스에서 캡처된 워크로드와 이를 가지고 단일 테스트 시스템에서 재생해볼 수 있는 통합된 Database Replay 기능을 제공한다
데이터베이스 통합
스트레스 테스트
스케일업 테스트
3-3-3-2. Database Replay 유저 맵핑
DBMS_WORKLOAD_REPOSITORY PL/SQL 패키지의 set_user_mapping 프로시저를 통해 맵핑 가능.
3-3-3-3. Database Replay ASH 데이터 비교 리포트
Summary: DB Time을 기반으로 캡처와 Replay를 수행한 Activity의 요약 정보
(전체 DB, CPU, Wait, 1/0 Time)와 Wait Time(예를 들어 log file sync, 1/0 wait 기타) 분포
Top SQL: 캡처와 Replay 수행 모두에서 ASH상의 Top SQL문의 비교 리포트 제공
Long Running SQL: 캡처와 Replay 수행 모두에서 ASH상에서 장기간 수행되는 SQL 문의 리포트제공
Common SQL: 캡처와 Replay 모두에 공통적으로 수행된 SQL 문을 추출한다. 필터링은 SQL문이 두 실행 사이에 공통되는 기준을 변경 할 수 있다. TOP SQL문은 평균 웅답 시간이나 전체 Database Time 간의 차이를 기준으로 비교된다.
Top Object: 캡처와 Replay 모두에 가장 빈번히 사용된 Object의 전체 Wait Time 리포트
3-3-4. 오라클 Database Replay Workload Intelligence
WI는 데이터베이스 캡처 동안 발생하는 캡처 파일을 분석해서 다양한 패턴이나 현재의 트랜드를 결정하는 기능을 제공한다.
3-3-5. 패치 인벤토리 쿼리
지금까지 오라클의 인벤토리를 조회할 수 있는 유일한 방법은 Opatch 유틸리티를 사용하는 것 이었다. 오라클 데이터베이스 12c부터는 이제 실시간으로 오라클 데이터베이스 인벤토리를 보기 위해 dbms_qopatch 패키지를 사용할 수 있다.
3-3-6. 오라클 DNFS 새로운 기능
비동기식 I/O 요청 개수를 조정하는 dNFS_BATCH_SIZE라는 새로운 파라미터를 지원한다. NFS 프로토콜을 지정할 수 있는 NFS_VERSION 파라미터가 사용된다.
3-3-7. 항상된네트워크압축
SQLNET .COMPRESSION
SQLNET .COMPRESSION LEVEL
커넥션 계층 서비스 레벨 또는 데이터베이스 레벨에서 설정할 수 있다.
3-3-8. 큰 사이즈의 네트워크 버퍼
Session Data Unit(SDU) 사이즈는 512바이트에서 2MB까지 지원한다.
3-3-9. 멀티프로세스, 멀티스레드 오라클
스레드 사용으로 리소스 감소. OS 인증 방식을 더 이상 사용하지 못한다. 데이터베이스 서버상의 LISTENER.ORA 파일에 DEDICATED_THROUGH_BORKER_LISTENER = ON 파라미터를 설정해야 한다.
3-3-10. 데이터베이스에서 복수 개의 플래시 디바이스를 지원하는 스마트 플래시 캐시
복수 개의 플래시 캐시 디바이스를 추가하기 위해서 간단히 DB_FLASH_CACHE_FILE 파라미터에 각 디바이스의 경로를 리스트로 지정하면 된다. 16개 디바이스까지 지원한다.
3-3-11. 새로운 오라클 스케줄러의 Script Job
12c에서는 새로운 Script Job이 추가되어 오라클 스케줄러에서 특정 Job 타입을 쉽게 실행할 수 있게 되었다.
SQL_SCRIPT : SQL*Plus 인터프리터를 사용한다.
EXTERNAL_SCRIPT : OS 셀 인터프리터를 실행하는데 사용.
BACKUP_SCRIPT : RMAN 작업.
오라클 데이터베이스 12c PL/SQL의 새로운 기능
로우 패턴매칭
- 데이터의 특정 패턴이 존재할 경우, 이를 검색해 줌
- 일/월/분기별 등 특정 기간 동안의 데이터 추이에서 특정 패턴 검색에 유리함(예 : 주식시황, 기간별 매출추이 등)
DROP TABLE sales_history PURGE;
CREATE TABLE sales_history (
id NUMBER,
product VARCHAR2(20),
tstamp TIMESTAMP,
units_sold NUMBER,
CONSTRAINT sales_history_pk PRIMARY KEY (id)
);
ALTER SESSION SET nls_timestamp_format = 'DD-MON-YYYY';
INSERT INTO sales_history VALUES ( 1, 'TWINKIES', '01-OCT-2014', 17);
INSERT INTO sales_history VALUES ( 2, 'TWINKIES', '02-OCT-2014', 19);
INSERT INTO sales_history VALUES ( 3, 'TWINKIES', '03-OCT-2014', 23);
INSERT INTO sales_history VALUES ( 4, 'TWINKIES', '04-OCT-2014', 23);
INSERT INTO sales_history VALUES ( 5, 'TWINKIES', '05-OCT-2014', 16);
INSERT INTO sales_history VALUES ( 6, 'TWINKIES', '06-OCT-2014', 10);
INSERT INTO sales_history VALUES ( 7, 'TWINKIES', '07-OCT-2014', 14);
INSERT INTO sales_history VALUES ( 8, 'TWINKIES', '08-OCT-2014', 16);
INSERT INTO sales_history VALUES ( 9, 'TWINKIES', '09-OCT-2014', 15);
INSERT INTO sales_history VALUES (10, 'TWINKIES', '10-OCT-2014', 17);
INSERT INTO sales_history VALUES (11, 'TWINKIES', '11-OCT-2014', 23);
INSERT INTO sales_history VALUES (12, 'TWINKIES', '12-OCT-2014', 30);
INSERT INTO sales_history VALUES (13, 'TWINKIES', '13-OCT-2014', 31);
INSERT INTO sales_history VALUES (14, 'TWINKIES', '14-OCT-2014', 29);
INSERT INTO sales_history VALUES (15, 'TWINKIES', '15-OCT-2014', 25);
INSERT INTO sales_history VALUES (16, 'TWINKIES', '16-OCT-2014', 21);
INSERT INTO sales_history VALUES (17, 'TWINKIES', '17-OCT-2014', 35);
INSERT INTO sales_history VALUES (18, 'TWINKIES', '18-OCT-2014', 46);
INSERT INTO sales_history VALUES (19, 'TWINKIES', '19-OCT-2014', 45);
INSERT INTO sales_history VALUES (20, 'TWINKIES', '20-OCT-2014', 30);
COMMIT;
-- 한국인 입장으로 다시 표기
ALTER SESSION SET nls_timestamp_format = 'YYYY-MM-DD';
SET PAGESIZE 50
COLUMN product FORMAT A10
COLUMN tstamp FORMAT A11
COLUMN graph FORMAT A50
-- 데이터를 출력한다.
SELECT id,
product,
tstamp,
units_sold,
RPAD('#', units_sold, '#') AS graph
FROM sales_history
ORDER BY id;
ID PRODUCT TSTAMP UNITS_SOLD GRAPH
---------- ---------- ----------- ---------- --------------------------------------------------
1 TWINKIES 2014-10-01 17 #################
2 TWINKIES 2014-10-02 19 ###################
3 TWINKIES 2014-10-03 23 #######################
4 TWINKIES 2014-10-04 23 #######################
5 TWINKIES 2014-10-05 16 ################
6 TWINKIES 2014-10-06 10 ##########
7 TWINKIES 2014-10-07 14 ##############
8 TWINKIES 2014-10-08 16 ################
9 TWINKIES 2014-10-09 15 ###############
10 TWINKIES 2014-10-10 17 #################
11 TWINKIES 2014-10-11 23 #######################
12 TWINKIES 2014-10-12 30 ##############################
13 TWINKIES 2014-10-13 31 ###############################
14 TWINKIES 2014-10-14 29 #############################
15 TWINKIES 2014-10-15 25 #########################
16 TWINKIES 2014-10-16 21 #####################
17 TWINKIES 2014-10-17 35 ###################################
18 TWINKIES 2014-10-18 46 ##############################################
19 TWINKIES 2014-10-19 45 #############################################
20 TWINKIES 2014-10-20 30 ##############################
20 rows selected.
COLUMN start_tstamp FORMAT A11
COLUMN peak_tstamp FORMAT A11
COLUMN end_tstamp FORMAT A11
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product -- 데이터의 그룹화 과정, 여기서는 product 별로 패턴을 찾기로 함
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp, -- 패턴매칭으로 가져올 컬럼명을 새로 지정함
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno -- 패턴을 만족한 개수
ONE ROW PER MATCH -- 패턴을 만족하는 ROW 1개만 보여줌(중복제거 효과), ALL ROWS : 패턴을 만족하는 과정의 모든 ROW를 보여줌
AFTER MATCH SKIP TO LAST DOWN -- 현재 패턴을 만족 하는 마지막 DOWN 시작점부터 다시 패턴을 찾기 시작함
PATTERN (STRT UP+ FLAT* DOWN+) -- 패턴을 정의 : UP이 1개 이상, FLAT은 0개 이상, DOWN은 1개 이상인 경우
DEFINE -- 패턴의 변수를 정의 : STRT의 경우 하단에 정의하지 않았으므로 모든 row에 매칭된다.
UP AS UP.units_sold > PREV(UP.units_sold), -- UP : 이전 units_sold 보다 큰 경우
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold), -- FLAT : 이전 units_sold와 같은 경우
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold) -- DOWN : 이전 units_sold와 작은 경우
) MR
ORDER BY MR.product, MR.start_tstamp;
PRODUCT START_TSTAM PEAK_TSTAMP END_TSTAMP MNO
---------- ----------- ----------- ----------- ----------
TWINKIES 01-OCT-2014 03-OCT-2014 06-OCT-2014 1
TWINKIES 06-OCT-2014 08-OCT-2014 09-OCT-2014 2
TWINKIES 09-OCT-2014 13-OCT-2014 16-OCT-2014 3
TWINKIES 16-OCT-2014 18-OCT-2014 20-OCT-2014 4
4 rows selected.
-- ONE ROW PER MATCH를 ALL ROWS PER MATCH로 변경
COLUMN start_tstamp FORMAT A11
COLUMN peak_tstamp FORMAT A11
COLUMN end_tstamp FORMAT A11
COLUMN final_peak_tstamp FORMAT A11
COLUMN final_end_tstamp FORMAT A11
COLUMN cls FORMAT A5
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
FINAL LAST(UP.tstamp) AS final_peak_tstamp, -- Final : 가장 마지막 패턴 매칭값이 나옴
FINAL LAST(DOWN.tstamp) AS final_end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls -- 분류자(패턴 정의시 사용한 변수)
ALL ROWS PER MATCH -- 패턴을 만족하는 모든 ROW가 나타남
AFTER MATCH SKIP TO LAST DOWN
PATTERN (STRT UP+ FLAT* DOWN+)
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold),
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold)
) MR
ORDER BY MR.product, MR.mno, MR.tstamp;
PRODUCT TSTAMP START_TSTAM PEAK_TSTAMP END_TSTAMP FINAL_PEAK_ FINAL_END_T MNO CLS ID UNITS_SOLD
---------- -------------------- ----------- ----------- ----------- ----------- ----------- ---------- ----- ---------- ----------
TWINKIES 2014-10-01 2014-10-01 2014-10-03 2014-10-06 1 STRT 1 17
TWINKIES 2014-10-02 2014-10-01 2014-10-02 2014-10-03 2014-10-06 1 UP 2 19
TWINKIES 2014-10-03 2014-10-01 2014-10-03 2014-10-03 2014-10-06 1 UP 3 23
TWINKIES 2014-10-04 2014-10-01 2014-10-03 2014-10-03 2014-10-06 1 FLAT 4 23
TWINKIES 2014-10-05 2014-10-01 2014-10-03 2014-10-05 2014-10-03 2014-10-06 1 DOWN 5 16
TWINKIES 2014-10-06 2014-10-01 2014-10-03 2014-10-06 2014-10-03 2014-10-06 1 DOWN 6 10
TWINKIES 2014-10-07 2014-10-07 2014-10-08 2014-10-09 2 STRT 7 14
TWINKIES 2014-10-08 2014-10-07 2014-10-08 2014-10-08 2014-10-09 2 UP 8 16
TWINKIES 2014-10-09 2014-10-07 2014-10-08 2014-10-09 2014-10-08 2014-10-09 2 DOWN 9 15
TWINKIES 2014-10-10 2014-10-10 2014-10-13 2014-10-16 3 STRT 10 17
TWINKIES 2014-10-11 2014-10-10 2014-10-11 2014-10-13 2014-10-16 3 UP 11 23
TWINKIES 2014-10-12 2014-10-10 2014-10-12 2014-10-13 2014-10-16 3 UP 12 30
TWINKIES 2014-10-13 2014-10-10 2014-10-13 2014-10-13 2014-10-16 3 UP 13 31
TWINKIES 2014-10-14 2014-10-10 2014-10-13 2014-10-14 2014-10-13 2014-10-16 3 DOWN 14 29
TWINKIES 2014-10-15 2014-10-10 2014-10-13 2014-10-15 2014-10-13 2014-10-16 3 DOWN 15 25
TWINKIES 2014-10-16 2014-10-10 2014-10-13 2014-10-16 2014-10-13 2014-10-16 3 DOWN 16 21
TWINKIES 2014-10-17 2014-10-17 2014-10-18 2014-10-20 4 STRT 17 35
TWINKIES 2014-10-18 2014-10-17 2014-10-18 2014-10-18 2014-10-20 4 UP 18 46
TWINKIES 2014-10-19 2014-10-17 2014-10-18 2014-10-19 2014-10-18 2014-10-20 4 DOWN 19 45
TWINKIES 2014-10-20 2014-10-17 2014-10-18 2014-10-20 2014-10-18 2014-10-20 4 DOWN 20 30
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
FINAL LAST(UP.tstamp) AS peak_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST DOWN
PATTERN (STRT UP+ DOWN{1} UP+) -- 패턴 : UP 1회 이상, DOWN 1회, UP 1회 이상
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold)
) MR
ORDER BY MR.product, MR.tstamp;
PRODUCT TSTAMP START_TSTAM PEAK_TSTAMP MNO CLS ID UNITS_SOLD
---------- -------------------- ----------- ----------- ---------- ----- ---------- ----------
TWINKIES 2014-10-06 2014-10-06 2014-10-13 1 STRT 6 10
TWINKIES 2014-10-07 2014-10-06 2014-10-13 1 UP 7 14
TWINKIES 2014-10-08 2014-10-06 2014-10-13 1 UP 8 16
TWINKIES 2014-10-09 2014-10-06 2014-10-13 1 DOWN 9 15
TWINKIES 2014-10-10 2014-10-06 2014-10-13 1 UP 10 17
TWINKIES 2014-10-11 2014-10-06 2014-10-13 1 UP 11 23
TWINKIES 2014-10-12 2014-10-06 2014-10-13 1 UP 12 30
TWINKIES 2014-10-13 2014-10-06 2014-10-13 1 UP 13 31
8 rows selected.
-- 패턴 매칭을 시작점을 정의
-- AFTER MATCH SKIP TO NEXT ROW : 패턴을 만족시키는 ROW 바로 뒤 ROW부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP PAST LAST ROW : 현재 패턴을 만족시키는 마지막 ROW 부터 패턴매칭을 다시 시작함
-- AFTER MATCH SKIP TO FIRST pattern_variable : 첫번째 pattern_variable 부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP TO LAST pattern_variable : 마지막 pattern_variable 부터 다시 패턴매칭을 시작함
-- AFTER MATCH SKIP TO pattern_variable : AFTER MATCH SKIP TO LAST pattern_variable 와 동일 기능
SELECT *
FROM sales_history MATCH_RECOGNIZE (
PARTITION BY product
ORDER BY tstamp
MEASURES STRT.tstamp AS start_tstamp,
LAST(UP.tstamp) AS peak_tstamp,
LAST(DOWN.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno
ONE ROW PER MATCH
AFTER MATCH SKIP TO NEXT ROW -- 패턴을 만족시키는 ROW 바로 뒤 ROW부터 다시 패턴매칭을 시작함
PATTERN (STRT UP+ FLAT* DOWN+)
DEFINE
UP AS UP.units_sold > PREV(UP.units_sold),
FLAT AS FLAT.units_sold = PREV(FLAT.units_sold),
DOWN AS DOWN.units_sold < PREV(DOWN.units_sold)
) MR
ORDER BY MR.product, MR.start_tstamp;
PRODUCT START_TSTAM PEAK_TSTAMP END_TSTAMP MNO
---------- ----------- ----------- ----------- ----------
TWINKIES 2014-10-01 2014-10-03 2014-10-06 1
TWINKIES 2014-10-02 2014-10-03 2014-10-06 2
TWINKIES 2014-10-06 2014-10-08 2014-10-09 3
TWINKIES 2014-10-07 2014-10-08 2014-10-09 4
TWINKIES 2014-10-09 2014-10-13 2014-10-16 5
TWINKIES 2014-10-10 2014-10-13 2014-10-16 6
TWINKIES 2014-10-11 2014-10-13 2014-10-16 7
TWINKIES 2014-10-12 2014-10-13 2014-10-16 8
TWINKIES 2014-10-16 2014-10-18 2014-10-20 9
TWINKIES 2014-10-17 2014-10-18 2014-10-20 10
10 rows selected.
-- 새로운 형태의 데이터 생성
CREATE TABLE sales_audit (
id NUMBER,
product VARCHAR2(20),
tstamp TIMESTAMP,
CONSTRAINT sales_audit_pk PRIMARY KEY (id)
);
ALTER SESSION SET nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS';
INSERT INTO sales_audit VALUES ( 1, 'TWINKIES', '01-OCT-2014 12:00:01');
INSERT INTO sales_audit VALUES ( 2, 'TWINKIES', '01-OCT-2014 12:00:02');
INSERT INTO sales_audit VALUES ( 3, 'DINGDONGS', '01-OCT-2014 12:00:03');
INSERT INTO sales_audit VALUES ( 4, 'HOHOS', '01-OCT-2014 12:00:04');
INSERT INTO sales_audit VALUES ( 5, 'HOHOS', '01-OCT-2014 12:00:05');
INSERT INTO sales_audit VALUES ( 6, 'TWINKIES', '01-OCT-2014 12:00:06');
INSERT INTO sales_audit VALUES ( 7, 'TWINKIES', '01-OCT-2014 12:00:07');
INSERT INTO sales_audit VALUES ( 8, 'DINGDONGS', '01-OCT-2014 12:00:08');
INSERT INTO sales_audit VALUES ( 9, 'DINGDONGS', '01-OCT-2014 12:00:09');
INSERT INTO sales_audit VALUES (10, 'HOHOS', '01-OCT-2014 12:00:10');
INSERT INTO sales_audit VALUES (11, 'HOHOS', '01-OCT-2014 12:00:11');
INSERT INTO sales_audit VALUES (12, 'TWINKIES', '01-OCT-2014 12:00:12');
INSERT INTO sales_audit VALUES (13, 'TWINKIES', '01-OCT-2014 12:00:13');
INSERT INTO sales_audit VALUES (14, 'DINGDONGS', '01-OCT-2014 12:00:14');
INSERT INTO sales_audit VALUES (15, 'DINGDONGS', '01-OCT-2014 12:00:15');
INSERT INTO sales_audit VALUES (16, 'HOHOS', '01-OCT-2014 12:00:16');
INSERT INTO sales_audit VALUES (17, 'TWINKIES', '01-OCT-2014 12:00:17');
INSERT INTO sales_audit VALUES (18, 'TWINKIES', '01-OCT-2014 12:00:18');
INSERT INTO sales_audit VALUES (19, 'TWINKIES', '01-OCT-2014 12:00:19');
INSERT INTO sales_audit VALUES (20, 'TWINKIES', '01-OCT-2014 12:00:20');
COMMIT;
COLUMN tstamp FORMAT A20
COLUMN start_tstamp FORMAT A20
COLUMN end_tstamp FORMAT A20
COLUMN cls FORMAT A10
SELECT *
FROM sales_audit MATCH_RECOGNIZE (
--PARTITION BY product -- 생략 가능함
ORDER BY tstamp -- 생략 가능함
MEASURES FIRST(TWINKIES.tstamp) AS start_tstamp,
FINAL LAST(TWINKIES.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST TWINKIES
PATTERN(TWINKIES{2,} DINGDONGS{2} HOHOS{1} TWINKIES{3,}) -- TWINKIES가 2번 이상, DINGDONGS가 2번, HOHOS가 1번, TWINKIES가 3번 이상
DEFINE
TWINKIES AS TWINKIES.product='TWINKIES',
DINGDONGS AS DINGDONGS.product='DINGDONGS',
HOHOS AS HOHOS.product='HOHOS'
) MR
ORDER BY MR.mno, MR.tstamp;
TSTAMP START_TSTAMP END_TSTAMP MNO CLS ID PRODUCT
-------------------- -------------------- -------------------- ---------- ---------- ---------- ----------
2014-10-01 12:00:12 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 12 TWINKIES
2014-10-01 12:00:13 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 13 TWINKIES
2014-10-01 12:00:14 2014-10-01 12:00:12 2014-10-01 12:00:20 1 DINGDONGS 14 DINGDONGS
2014-10-01 12:00:15 2014-10-01 12:00:12 2014-10-01 12:00:20 1 DINGDONGS 15 DINGDONGS
2014-10-01 12:00:16 2014-10-01 12:00:12 2014-10-01 12:00:20 1 HOHOS 16 HOHOS
2014-10-01 12:00:17 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 17 TWINKIES
2014-10-01 12:00:18 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 18 TWINKIES
2014-10-01 12:00:19 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 19 TWINKIES
2014-10-01 12:00:20 2014-10-01 12:00:12 2014-10-01 12:00:20 1 TWINKIES 20 TWINKIES
SELECT *
FROM sales_audit MATCH_RECOGNIZE (
--PARTITION BY product
ORDER BY tstamp
MEASURES FIRST(TWINKIES.tstamp) AS start_tstamp,
FINAL LAST(TWINKIES.tstamp) AS end_tstamp,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
AFTER MATCH SKIP TO LAST TWINKIES
PATTERN(TWINKIES+ (DINGDONGS | HOHOS){3} TWINKIES+) -- TWINKIES 1번 이상, DINGDONGS 또는 HOHOS가 3회, TWINKIES 가 1회 이상
DEFINE
TWINKIES AS TWINKIES.product='TWINKIES',
DINGDONGS AS DINGDONGS.product='DINGDONGS',
HOHOS AS HOHOS.product='HOHOS'
) MR
ORDER BY MR.mno, MR.tstamp;
TSTAMP START_TSTAMP END_TSTAMP MNO CLS ID PRODUCT
-------------------- -------------------- -------------------- ---------- ---------- ---------- ----------
2014-10-01 12:00:01 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 1 TWINKIES
2014-10-01 12:00:02 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 2 TWINKIES
2014-10-01 12:00:03 2014-10-01 12:00:01 2014-10-01 12:00:07 1 DINGDONGS 3 DINGDONGS
2014-10-01 12:00:04 2014-10-01 12:00:01 2014-10-01 12:00:07 1 HOHOS 4 HOHOS
2014-10-01 12:00:05 2014-10-01 12:00:01 2014-10-01 12:00:07 1 HOHOS 5 HOHOS
2014-10-01 12:00:06 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 6 TWINKIES
2014-10-01 12:00:07 2014-10-01 12:00:01 2014-10-01 12:00:07 1 TWINKIES 7 TWINKIES
2014-10-01 12:00:12 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 12 TWINKIES
2014-10-01 12:00:13 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 13 TWINKIES
2014-10-01 12:00:14 2014-10-01 12:00:12 2014-10-01 12:00:20 2 DINGDONGS 14 DINGDONGS
2014-10-01 12:00:15 2014-10-01 12:00:12 2014-10-01 12:00:20 2 DINGDONGS 15 DINGDONGS
2014-10-01 12:00:16 2014-10-01 12:00:12 2014-10-01 12:00:20 2 HOHOS 16 HOHOS
2014-10-01 12:00:17 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 17 TWINKIES
2014-10-01 12:00:18 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 18 TWINKIES
2014-10-01 12:00:19 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 19 TWINKIES
2014-10-01 12:00:20 2014-10-01 12:00:12 2014-10-01 12:00:20 2 TWINKIES 20 TWINKIES
16 rows selected.
Oracle Native Left Outer Join 문법개선
- 12c 이전에는 한 번에 한 테이블에만 outer 조인이 가능했으나 12c부터는 2개 이상의 복수개의 테이블로 outer 조인이 가능하다.
-- 11g에서 실행할 경우 에러가 발생
SELECT COUNT(*)
FROM SCOTT.EMP A, SCOTT.DEPT B, SCOTT.BONUS C
WHERE B.DEPTNO = A.DEPTNO(+)
AND C.ENAME = A.ENAME(+);
ERROR AT LINE 3:
ORA-01417: a tabe may be outer joined to at most one other table
-- 12c에서는 오류 없이 쿼리가 실행된다.
SELECT COUNT(*)
FROM SCOTT.EMP A, SCOTT.DEPT B, SCOTT.BONUS C
WHERE B.DEPTNO = A.DEPTNO(+)
AND C.ENAME = A.ENAME(+);
COUNT(*)
----------
0
실행계획 :
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 40 | 7 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 40 | | |
|* 2 | HASH JOIN OUTER | | 1 | 40 | 7 (0)| 00:00:01 |
| 3 | MERGE JOIN CARTESIAN | | 1 | 20 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | BONUS | 1 | 7 | 2 (0)| 00:00:01 |
| 5 | BUFFER SORT | | 4 | 52 | 2 (0)| 00:00:01 |
| 6 | INDEX FAST FULL SCAN| PK_DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | EMP | 14 | 280 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Top-n 쿼리의 새로운 기능 (row limiting)
select count(*) from emp;
COUNT(*)
----------
14
select empno, hiredate from emp order by hiredate asc;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
7902 1981-12-03 00:00:00
7934 1982-01-23 00:00:00
7788 1987-04-19 00:00:00
7876 1987-05-23 00:00:00
14 rows selected.
-- 8번째 row를 건너뛰고 조회됨
select empno, hiredate from emp order by hiredate offset 8 rows;
EMPNO HIREDATE
---------- -------------------
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
7902 1981-12-03 00:00:00
7934 1982-01-23 00:00:00
7788 1987-04-19 00:00:00
7876 1987-05-23 00:00:00
6 rows selected.
-- 10개의 row를 가져옴
select empno, hiredate from emp
order by hiredate fetch first 10 rows only;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
7839 1981-11-17 00:00:00
7900 1981-12-03 00:00:00
10 rows selected.
-- 25%만큼의 데이터만 가져옴
select empno, hiredate from emp
order by hiredate fetch first 25 percent rows only;
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
select empno, hiredate from emp
order by hiredate fetch next 25 percent rows only; -- first / next는 서로 동일한 기능을 하였다.
EMPNO HIREDATE
---------- -------------------
7369 1980-12-17 00:00:00
7499 1981-02-20 00:00:00
7521 1981-02-22 00:00:00
7566 1981-04-02 00:00:00
-- 4개의 row를 건너뛰고, 5번째 row부터 25% 가져옴
select empno, hiredate from emp
order by hiredate offset 4 rows fetch next 25 percent rows only;
EMPNO HIREDATE
---------- -------------------
7698 1981-05-01 00:00:00
7782 1981-06-09 00:00:00
7844 1981-09-08 00:00:00
7654 1981-09-28 00:00:00
-- with ties절은 마지막 row가 서로 동률일 경우 동률인 row를 모두 가져옴
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary
FETCH FIRST 5 PERCENT ROWS ONLY;
EMPLOYEE_ID LAST_NAME SALARY
----------- ------------------------- ----------
132 Olson 2100
128 Markle 2200
136 Philtanker 2200
127 Landry 2400
135 Gee 2400
119 Colmenares 2500
6 rows selected.
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary
FETCH FIRST 5 PERCENT ROWS WITH TIES;
EMPLOYEE_ID LAST_NAME SALARY
----------- ------------------------- ----------
132 Olson 2100
128 Markle 2200
136 Philtanker 2200
127 Landry 2400
135 Gee 2400
119 Colmenares 2500
131 Marlow 2500
140 Patel 2500
144 Vargas 2500
182 Sullivan 2500
191 Perkins 2500
11 rows selected.
union, union all 분기문장 동시실행
create table big_table
as
select object_id, object_name
from (select object_id, object_name from dba_objects where rownum <=1000) a
, (select level from dual connect by level <= 1000) b
;
create index big_table_idx1 on big_table(object_id asc);
analyze table big_table compute statistics;
select count(*) cnt from big_table where object_id = 885;
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
------------------------------------------------------------------------------------
select count(*) cnt from big_table where object_id = 885
union all
select count(*) cnt from big_table where object_id = 237
union all
select count(*) cnt from big_table where object_id = 420
union all
select count(*) cnt from big_table where object_id = 557
union all
select count(*) cnt from big_table where object_id = 880
;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 6 | 10 (0)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
| 2 | SORT AGGREGATE | | 1 | 3 | | |
|* 3 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 3 | | |
|* 5 | INDEX RANGE SCAN| BIG_TABLE_IDX1 | 1000 | 3000 | 5 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
오라클 데이터베이스 12c DDL의 새로운 기능
VARCHAR2, NVARCHAR2 RAW 데이터 타입의 최대 길이 증가
- VARCHAR2, NVARCHAR2, RAW 데이터 타입이 32,767 BYTE까지 저장가능
- 확장 데이터 타입의 활성화
select name, value from v$parameter where name = 'max_string_size';
NAME VALUE
---------------- ----------------
max_string_size STANDARD
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001));
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001))
*
ERROR at line 1:
ORA-00910: specified length too long for its datatype
CONN / AS SYSDBA
SHUTDOWN IMMEDIATE;
STARTUP UPGRADE;
ALTER SYSTEM SET max_string_size=extended;
@?/rdbms/admin/utl32k.sql -- recyclebin에 테이블이 있을 경우 에러발생, recyclebin을 비우고 작업하자
SHUTDOWN IMMEDIATE;
STARTUP;
select name, value from v$parameter where name = 'max_string_size';
NAME VALUE
---------------- ----------------
max_string_size EXTENDED
CREATE TABLE EXTEND_TABLE (DATA_VARCHAR VARCHAR2(4001), DATA_NVARCHAR2 NVARCHAR2(2001), DATA_RAW RAW(2001));
Table created.
desc extend_table;
Name Null? Type
----------------------------------------------------------------- -------- --------------------------------------------
DATA_VARCHAR VARCHAR2(4001)
DATA_NVARCHAR2 NVARCHAR2(2001)
DATA_RAW RAW(2001)
CREATE TABLE t1 (
id NUMBER,
varchar2_data VARCHAR2(32767),
nvarchar2_data NVARCHAR2(16383),
raw_data RAW(32767)
);
Table created.
INSERT INTO t1
SELECT 1,
RPAD('X', 32767, 'X') AS varchar2_data,
RPAD('X', 16383, 'X') AS nvarchar2_data,
UTL_RAW.cast_to_raw(RPAD('X', 32767, 'X')) as raw_data
FROM dual;
SELECT id,
LENGTH(varchar2_data),
LENGTH(nvarchar2_data),
LENGTH(raw_data)
FROM t1;
ID LENGTH(VARCHAR2_DATA) LENGTH(NVARCHAR2_DATA) LENGTH(RAW_DATA)
---------- --------------------- ---------------------- ----------------
1 32767 16383 32767
1 row selected.
-- 인덱스가 LOB 타입으로 자동으로 생성됨
SELECT index_name, index_type
FROM user_indexes
WHERE table_name = 'T1';
INDEX_NAME INDEX_TYPE
---------------------------------------- ---------------------------
SYS_IL0000093481C00004$$ LOB
SYS_IL0000093481C00003$$ LOB
SYS_IL0000093481C00002$$ LOB
- 블록사이즈가 8K인 경우 B*Tree 인덱스의 최대 키 길이는 6,398바이트이며, 이 길이를 초과하는 데이터를 insert하거나, update 시 실패할 수 있다.
- substr 함수를 이용한 Function-based Index를 생성하거나 standard_hash 함수를 통해 컬럼 사이즈를 축소하면 해결 가능하다.
-- 크기초과로 인덱스 생성 불가능
create index t1_idx01 on t1(varchar2_data asc);
create index t1_idx01 on t1(varchar2_data asc)
*
ERROR at line 1:
ORA-01450: maximum key length (6398) exceeded
Identity 컬럼
- Sequence generator로부터 정수값의 증가와 감소를 지정할 수 있음
- 규칙
- 테이블당 1개만 생성가능
- number 타입 컬럼만 가능
- default 지정 불가능
- Not Null, Not Deferrable 제약조건 암시적으로 정의됨
- 암호화 가능
- CTAS 명령을 실행해서 만든 테이블 컬럼은 Identity 컬럼 속성은 상속받지 않음
create table identify_table (s_key number generated as identity primary key, data varchar2(30));
insert into identify_table (data) values ('test');
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 test
insert into identify_table (data) values ('test222');
update identify_table set data='11111' where s_key=1;
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
insert into identify_table values (3, '3333');
insert into identify_table values (3, '3333')
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column
-- 컬럼을 재정의하면 데이터를 직접 입력할 수 있다.
alter table identify_table modify ( s_key number generated by default as identity);
insert into identify_table values (5, '55555');
commit;
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
5 55555
-- 현재 시퀀스보다 큰 수를 수동으로 입력하고
-- 이후 자동으로 시퀀스로 채번하게 되면 UNIQUE 오류가 발생할 수 있다.
select * from identify_table;
S_KEY DATA
---------- ------------------------------
1 11111
2 test222
5 55555
21 3333
22 4444
23 test55555
insert into identify_table (data) values ('666666');
insert into identify_table (data) values ('77777');
insert into identify_table (data) values ('77777')
*
ERROR at line 1:
ORA-00001: unique constraint (JIGI.SYS_C0010318) violated
-- 시퀀스가 자동으로 생성됨
select sequence_name, cache_size, last_number from user_sequences;
SEQUENCE_NAME CACHE_SIZE LAST_NUMBER
------------------------------ ---------- -----------
ISEQ$$_93500 20 41
-- 테이블 생성 스크립트를 뽑으면 아래와 같음
CREATE TABLE JIGI.IDENTIFY_TABLE
(
S_KEY NUMBER DEFAULT "JIGI"."ISEQ$$_93500".nextval NOT NULL,
DATA VARCHAR2(30 BYTE)
);
Cascade Truncate 문
- 부모 테이블을 Truncate해서 자식 테이블까지 연쇄적으로 Truncate 되는 문장을 지원함
create table parent(id number primary key);
create table child(cid number primary key, pid number);
alter table child add constraint fk_parent_child foreign key(pid)
references parent(id) on delete cascade;
insert into parent values(1);
insert into parent values(2);
insert into child values(1,1);
insert into child values(2,1);
insert into child values(3,2);
commit;
select * from parent;
ID
----------
1
2
select * from child;
CID PID
---------- ----------
1 1
2 1
3 2
truncate table parent cascade;
select * from parent;
no rows selected
select * from child;
no rows selected
Invisible 컬럼
- 아래의 경우 컬럼명이 보이지 않음
- Select * from table 과 같은 와일드카드 문자를 사용한 문장
- SQL*PLUS에서 DESC 명령
- PL/SQL %ROWTYPE 선언
- INSERT INTO SELECT * 문장
create table invisible (id number, invisible_col number invisible);
desc invisible;
Name Null? Type
-------------------------------- -------- --------------------------------------------
ID NUMBER
insert into invisible values (1, 1);
insert into invisible values (1, 1)
*
ERROR at line 1:
ORA-00913: too many values
insert into invisible (id, invisible_col) values (1, 1);
select * from invisible;
ID
----------
1
select id, invisible_col from invisible;
ID INVISIBLE_COL
---------- -------------
1 1
- 참고사항 : 토드 11에서도 안보인다.
col owner format a30
col table_name format a30
col column_name for a20
select owner, table_name, column_name, hidden_column
from dba_tab_cols
where table_name = 'INVISIBLE';
OWNER TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ -------------------- ---
JIGI INVISIBLE INVISIBLE_COL YES
JIGI INVISIBLE ID NO
alter table invisible modify(invisible_col visible);
desc invisible;
Name Null? Type
--------------------------------------- -------- --------------------------------------------
ID NUMBER
INVISIBLE_COL NUMBER
- 참고 : inivisible로 변경된 컬럼은 가장 마지막으로 위치가 바뀐다. 테이블의 컬럼을 순서를 바꾸고 싶은 경우 위치하고 싶은 컬럼 뒤 모든 컬럼을 invisible -> visible 함으로서 컬럼의 순서를 조정할 수 있다
오라클 시퀀스를 기반으로 한 디폴트 값
- identity 컬럼과는 다르게 여러개의 컬럼에 선언가능
- 시퀀스가 미리 생성되어 있어야 한다.
- 시퀀스가 삭제된 상태에서 insert 작업시 에러가 발생한다.
- 테이블 소유자와 디폴트 값을 할당하는 컬럼의 유저는 시퀀스의 select 권한이 필요하다.
- 시퀀스가 적용된 컬럼에 수동으로 값을 지정하여 입력할 수 있다.
create sequence test_seq start with 1;
create table seq_table (id number default test_seq.nextval, test varchar2(10));
insert into seq_table values(null, '1');
insert into seq_table values(default, '2');
insert into seq_table (test) values('3');
insert into seq_table values(100, '4');
commit;
select * from seq_table;
ID TEST
---------- ----------
1
1 2
2 3
100 4
insert into seq_table (test) values('5');
commit;
select * from seq_table;
ID TEST
---------- ----------
1
1 2
2 3
100 4
3 5
NULL 값이 입력되었을 때의 디폴트 값
create table sales_information (
store_id number
, sales_date date default on null to_date('20991231', 'YYYYMMDD') not null
, sale_number number
, product_id number
, quantity number default on null 0 not null
, constraint pk_sales_information primary key (product_id, sales_date, sale_number)
);
insert into sales_information values (1, null, 1, 12345, null);
select * from sales_information;
STORE_ID SALES_DATE SALE_NUMBER PRODUCT_ID QUANTITY
---------- ------------------- ----------- ---------- ----------
1 2099-12-31 00:00:00 1 12345 0
select table_name, column_name, default_on_null from user_tab_columns where table_name ='SALES_INFORMATION';
TABLE_NAME COLUMN_NAME DEF
------------------------------ -------------------- ---
SALES_INFORMATION STORE_ID NO
SALES_INFORMATION SALES_DATE YES
SALES_INFORMATION SALE_NUMBER NO
SALES_INFORMATION PRODUCT_ID NO
SALES_INFORMATION QUANTITY YES
시퀀스 관련 새로운 기능
- 세션단위로 생성되는 시퀀스
conn scott/tiger
create global temporary table gtt (id number, seq_number number);
grant all on gtt to jigi;
create sequence seq_session start with 1 session;
grant all on seq_session to jigi;
insert into gtt values ( 1, seq_session.nextval);
insert into gtt values ( 2, seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 1
2 2
commit;
select * from scott.gtt;
no rows selected
insert into gtt values ( 1, seq_session.nextval);
insert into gtt values ( 2, seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 3
2 4
commit;
conn jigi/oracle
select * from scott.gtt;
no rows selected
insert into scott.gtt values ( 1, scott.seq_session.nextval);
insert into scott.gtt values ( 2, scott.seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 1
2 2
commit;
select * from scott.gtt;
no rows selected
insert into scott.gtt values ( 1, scott.seq_session.nextval);
insert into scott.gtt values ( 2, scott.seq_session.nextval);
select * from scott.gtt;
ID SEQ_NUMBER
---------- ----------
1 3
2 4
동일한 컬럼에 대한 다른 종류의 멀티 인덱스
- 동일 컬럼에 서로 다른 인덱스 타입으로 2개 이상의 인덱스를 만들 수 있다.
- 단, 1개의 인덱스만 visible로 허용된다. 나머지 인덱스는 invisible로 생성가능
create table emp_tab as select * from scott.emp;
create index emp_tab_ix01 on emp_tab(hiredate, deptno);
-- 동일컬럼에 비트맵 인덱스를 바로 생성하려고 하면 에러가 난다.
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno);
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno)
*
ERROR at line 1:
ORA-01408: such column list already indexed
-- 두번째 인덱스를 생성하기 위해 처음 인덱스를 invisible로 변경하면 인덱스가 생성된다.
alter index emp_tab_ix01 invisible;
Index altered.
create bitmap index emp_tab_ix02 on emp_tab(hiredate, deptno);
Index created.
- 이 기능은 가용성을 유지하는 목적으로 유용하다. 기존과 다른 새로운 인덱스를 새롭게 만들어야 하는 경우, invisible 속성으로 새로운 유형의 인덱스를 만들고 기존 인덱스를 삭제한 후 새롭게 만든 인덱스를 visible 하면 된다.
with 쿼리의 새로운 기능
- with 절 내에서 PL/SQL 기능을 사용할 수 있다.
- 단, PL/SQL 내에서 이러한 형태의 with 절은 사용할 수 없다.
create table test_table (id number); insert into test_table values (1); insert into test_table values (2); commit; select * from test_table; ID ---------- 1 2 with function plus_one(p_id number) return number is begin return p_id + 1; end; select plus_one(id) from test_table; / PLUS_ONE(ID) ------------ 2 3
오라클 데이터베이스 12c PL/SQL의 새로운 기능
뷰에서 Bequeath 절 사용
- BEQUEATH CURRENT_USER : 해당 뷰를 호출한(사용하는) 계정의 권한으로 뷰를 실행
- BEQUEATH DEFINER : 해당 뷰를 생성한 계정의 권한으로 뷰를 실행
PL/SQL 서브프로그램이 허가된 리스트
create or replace function helper (v_input number)
return number
accessible by (api) is -- 해당 FUNCTION은 API라는 PL/SQL에서만 호출가능
begin
return v_input + 1;
end;
JIGI@2016-11-22 11:32:45> select helper(1) from dual;
select helper(1) from dual
*
ERROR at line 1:
ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-904: insufficient privilege to access object HELPER
create or replace function api (v_input number)
return number
is
v_return number;
begin
v_return := helper(v_input);
return v_return;
end;
JIGI@2016-11-22 11:33:08> select api(1) from dual;
API(1)
----------
2
JIGI@2016-11-22 11:35:54>
PL/SQL에서 SQL 인터페이스를 통한 PL/SQL 지정 데이터 타입 사용
- 11g까지는 PL/SQL 전용 데이터타입(boolean, 연관배열, record 타입 등)을 바인딩 할 수 없었으나, 12c에서 사용가능해짐
- 일부 제한사항이 존재함
- PL/SQL 전용데이터 타입이 미리 정의되어 있거나 PACKAGE SPEC에 선언되어 있어야 함
- 연관배열을 사용시 배열은 PLS_INTEGER 데이터 타입에 인덱스화가 되어 있어야함
- PL/SQL 함수 사용 시 PL/SQL 전용 데이터 타입은 SQL로 리턴되지 못함
- BOOLEAN 값은 STATICS SQL 쿼리에서 호출되는 PL/SQL 함수의 인수가 되지 못함
- SQL 문장 내에서는 PACKAGE SPEC에 선언되는 RETURN 타입을 가진 함수는 사용 할 수 없음
CREATE OR REPLACE PROCEDURE ANSWER_ME (P_R BOOLEAN)
IS
BEGIN
IF P_R THEN
DBMS_OUTPUT.PUT_LINE('ANSWER IS TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('ANSWER IS FALSE');
END IF;
END;
SET SERVEROUTPUT ON
DECLARE
V_SQL VARCHAR2(1000);
V_BOOLEAN BOOLEAN := TRUE;
BEGIN
V_SQL := 'BEGIN ANSWER_ME(:X); END;';
EXECUTE IMMEDIATE V_SQL USING V_BOOLEAN;
END;
ANSWER IS TRUE
PL/SQL procedure successfully completed.
PL/SQL 프로그램 단위에서 호출자 권한의 보안 권한 변경
- PL/SQL 프로그램에서 프로시저를 생성 시 호출자 권한을 정의하려는 경우, PL/SQL 프로그램 유닛의 소유자가 INHERIT ANY PRIVILEGE나 INHERIT PRIVILEGE 권한을 가져야 함.
- 12c에서는 호환성을 위해 기본적으로 grant inherit any privileges to public가 모든 계정에 적용되어 있다.
grant inherit privileges on user scott to public;
grant inherit privileges on user to tiger;
grant inherit any privileges to tiger;
위 3가지 방법으로 권한을 부여가능함
PL/SQL 패키지와 독립 서브프로그램에 롤 부여
-- 테이블 생성
CREATE TABLE need_privs (id NUMBER);
INSERT INTO need_privs VALUES (1);
COMMIT;
-- function 생성
CREATE OR REPLACE FUNCTION get_new_value(v_input IN NUMBER)
RETURN NUMBER
-- AUTHID definer -- 해당 function을 만든 사용자 권한으로 실행한다는 의미
AUTHID current_user -- 해당 function을 호출자(실행자) 권한으로 실행한다는 의미
AS
v_number NUMBER := 0;
BEGIN
SELECT id + v_input INTO v_number FROM scott.need_privs;
RETURN v_number;
END;
SCOTT@2016-11-22 14:51:11> select get_new_value(1) from dual;
GET_NEW_VALUE(1)
----------------
2
-- 실행 권한 부여
SCOTT@2016-11-22 15:01:35> grant execute on get_new_value to hr;
Grant succeeded.
SCOTT@2016-11-22 15:01:45> conn hr/hr
Connected.
-- 권한이 없어서 오류발생
HR@2016-11-22 15:01:48> select scott.get_new_value(1) from dual;
select scott.get_new_value(1) from dual
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SCOTT.GET_NEW_VALUE", line 7
-- Role을 만들어본다.
HR@2016-11-22 15:02:04> conn scott/tiger
Connected.
SCOTT@2016-11-22 15:05:56> create role run_get_new_value;
create role run_get_new_value
*
ERROR at line 1:
ORA-01031: insufficient privileges
SCOTT@2016-11-22 15:06:11> conn /as sysdba
Connected.
SYS@2016-11-22 15:06:42> grant create role to scott;
Grant succeeded.
SYS@2016-11-22 15:07:14> conn scott/tiger
Connected.
SCOTT@2016-11-22 15:07:19> create role run_get_new_value;
Role created.
SCOTT@2016-11-22 15:07:32> grant select on need_privs to run_get_new_value;
Grant succeeded.
-- 12c에 새로생긴 기능
SCOTT@2016-11-22 15:07:57> grant run_get_new_value to function get_new_value;
Grant succeeded.
SCOTT@2016-11-22 15:08:25> conn hr/hr
Connected.
-- 결과가 잘 나옴
HR@2016-11-22 15:10:20> select scott.get_new_value(1) from dual;
SCOTT.GET_NEW_VALUE(1)
----------------------
2
HR@2016-11-22 15:10:27>
PL/SQL의 기타 새로운 기능
- function에 result_cache 절 지원 : Result Cache가 가능해짐
- Pluggable 데이터베이스 트리거 지원
- before unplug : 데이터베이스가 언플러그 되기 전에 실행됨
- after clone : PDB가 복제되고 나서 실행됨, 이후 트리거는 제거됨.
- 디버깅을 위한 PL/SQL 지시어 추가
-- 디버깅을 위한 새로운 파라미터 제공
CREATE OR REPLACE procedure test_procedure
is
begin
dbms_output.put_line('$$plsql_unit_owner : ' || $$plsql_unit_owner);
dbms_output.put_line('$$plsql_unit_type : ' || $$plsql_unit_type);
end test_procedure;
/
HR@2016-11-22 15:39:00> exec test_procedure;
$$plsql_unit_owner : HR
$$plsql_unit_type : PROCEDURE
오라클 MultiTenant 기능은 Oracle 12c 버전에서 처음 소개되었습니다. 현재는 Oracle DBMS 버전이 18c, 19c, 20c 까지 나온 상태라 이 기능도 꽤 연륜이 쌓였다고 할 수 있겠습니다.
개념은 그닥 복잡하지 않습니다. "DB 안에 여러 DB들이 들어가 있는 구조" 입니다. ^^
Multi-Tenant 라는 단어에서 Multi 는 "여러개" 의 뜻이고, Tenant 는 "세입자" 라는 뜻입니다.
여러 세입자(DB)가 큰 집에 옹기종기 모여산다는 개념^^ 되겄심다.
클라우드(Cloud)에 대해서 공부 좀 하신 분들은 쉽게 이해가 가는 구조입니다.
원래 클라우드라는 게 여러 서비스/업무/플랫폼 등을 사용자는 모르게, 한곳(데이터센터?)에 잘 담아서 서비스 하는 개념입니다. (너무 대충 성의없이 얘기했나?? ㅎㅎ)
보통 클라우드라고 하면 인터넷망을 통해 접근하는 것만 생각하는데, 이런 것을 "Public Cloud" 라고 하고,
우리 전산실내에서 폐쇄적으로(인터넷망을 거치지 않고) 구축한 클라우드를 "Private Cloud" 라고 구분하고 있습니다.
이 멀티테넌트의 개념은 Private Cloud 형태를 DBMS 내에 구축했다고 보면 되겠습니다.
그럼, 뭣허러 이렇게 쓰자는 거지??
뭔가 좋은 점이 있으니 이런 아키텍쳐가 만들어졌을 겁니다. ㅎㅎ 당연히 좋은 점이 있습니다.
우리 전산실에 싱글DB 10개가 있다고 생각해 보죠~
각 싱글DB들은 DB서버(하드웨어) 하나씩을 차지하고 있습니다.
각각의 서버 CPU, Memory 사용량을 보면 거의 대부분 10~30% 정도 밖에 사용을 안합니다.
이유는 당연히 100% 다 쓰면 시스템이 서버리거나 거북이처럼 기어가니까 만일의 사태에 대비해 항상 여유빵빵하게 시스템을 운영하는 것이지요.
결국, 각 DB서버들은 한달에 한번? 또는 일년에 한번? 정도만 시스템을 많이 사용하고 대부분의 경우는 70% 정도의 자원이 항상 놀고 있는 것이지요. 얘네들을 다 합쳐놓으면? ㅎㅎ
이 경우는 만일의 사태를 대비한 여유분을 무식하게 70% x 10 = 700% 를 다 가져갈 필요가 없겠죠?
반절 수준인 350% 정도만 가져가도 충분합니다. 그러면, 전체적으로 가져가야(운영해야) 하는 시스템자원 양이 확 줄게됩니다.
비용 세이브~~
이게 바로 콘솔리데이션(Consolidation)의 효과이죠~~
이것을 쉽게 할수 있도록 한 것이 멀티테넌트 기능 되겠습니다.
(출처: 오라클 다큐먼트)
위 그림에서는 hrpdb 와 salespdb 의 2개의 DB가 있습니다.
얘네들은 MYCDB 라는 큰 DB 안에 들어있는 구조입니다.
밖에서(시스템상에서) 보면 달랑 MYCDB 라는 DB 1개만 보입니다.
하지만, DB를 사용하는 사용자 입장에서 보면 hrpdb 와 salespdb 2개가 별개로 각각 존재하는 것처럼 보입니다.
시스템상으로는 1개의 DB 이기때문에 패치, 백업 등의 작업을 통으로 1번만 해주면 됩니다. 관리가 수월해지죠~
hrpdb 에서 salespdb 를 직접 들여다보거나 데이터를 변경하거나 할 수 없습니다. 논리적으로는 서로 다른 DB인 셈이기 때문입니다.
hrpdb, salepdb 와 같이 셋방살이 하고 있는 세입자(tenant) DB들을 유식한 말로 PDB (Pluggable DB) 라고 합니다.
MYCDB 처럼 hrpdb, salespdb 를 담고 있는(contain) 집주인 DB를 유식한 말로 CDB (Container DB) 라고 합니다.
Container 라는 단어는 느낌이 팍 오기 때문에 설명이 필요없고... Pluggable ? 이건 뭐지??
이게 나중에 좀더 빠져들어가 보면 알 수 있는데, DB를 USB 꼽듯이 꼽았다(Plug) 뽑았다(Unplug) 하기가 매우 쉽기 때문에 이런 이름이 붙었다고 하네요~
아무튼, 결론적으로 Multi-Tenant 는 DB 통합, Private Cloud 구축에 아주 유용한 기능이라고 할 수 있겠습니다.
아~ 이 기능은 Oracle DB들만 가능합니다. 저 컨테이너 DB 에 MySQL, DB2, Sybase 등 아무 DB나 막 갖다꽂을 수는 없습니다.
출처:
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=hanajava&logNo=220805858837
[엑시엄] 오라클 데이터베이스 12c의 새로운 기능 Top-N Query
엑시엄이 보는 DB 세상 오라클 데이터베이스 12c의 새로운 기능 Top-N Query Oracle Database(오라...
blog.naver.com
http://wiki.gurubee.net/pages/viewpage.action?pageId=30966187
10. 오라클 데이터베이스 12c 관리의 새로운 기능 - [종료]구루비 DB 스터디 - 개발자, DBA가 함께 만
Added by 고경민, last edited by 고경민 on 1월 13, 2017 (view change) 1.온라인작업 1-1. 향상된 온라인 DDL 기능 drop index drop constraint set unused column alter index unusable alter index visible alter index invisible online 키워드
wiki.gurubee.net
http://wiki.gurubee.net/pages/viewpage.action?pageId=30441535
06. SQL, PLSQL의 새로운 기능 - [종료]구루비 DB 스터디 - 개발자, DBA가 함께 만들어가는 구루비 지식
Added by 임갑중, last edited by 임갑중 on 12월 02, 2016 (view change) 오라클 데이터베이스 12c PL/SQL의 새로운 기능 로우 패턴매칭 데이터의 특정 패턴이 존재할 경우, 이를 검색해 줌 일/월/분기별 등 특정
wiki.gurubee.net
Database New Features Guide
https://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT003
Oracle Database 12c Release 1 (12.1.0.2) New Features
This chapter contains descriptions of the features that are available in Oracle Database 12c Release 1 (12.1.0.2). This chapter contains the following sections: 1.1 Advanced Index Compression Advanced Index Compression works well on all supported indexes,
docs.oracle.com
https://jack-of-all-trades.tistory.com/286
오라클 멀티테넌트 DB 기본개념 정리 (Oracle Multi-Tenant DB Basics)
오라클 MultiTenant 기능은 Oracle 12c 버전에서 처음 소개되었습니다. 현재는 Oracle DBMS 버전이 18c, 19c, 20c 까지 나온 상태라 이 기능도 꽤 연륜이 쌓였다고 할 수 있겠습니다. 개념은 그닥 복잡하지 않
jack-of-all-trades.tistory.com
'Database > Oracle Database' 카테고리의 다른 글
[오라클] Null 값 저장 (0) | 2022.09.26 |
---|---|
[오라클] Schema Objects (0) | 2022.09.26 |
[오라클] TEMPORARY TABLESPACE 관련 (0) | 2022.02.28 |
[오라클] buffer busy wait 조회 (0) | 2022.02.27 |
[오라클] 오브젝트 락 걸렸을 때 오브젝트 찾고 세션 킬하는 방법 (0) | 2022.02.26 |