UPDATE emp e SET e.dname = ( SELECT d.dname FROM dept d WHERE d.deptno = e.deptno ) WHERE EXISTS ( SELECT 1 FROM dept d WHERE d.deptno = e.deptno );
이 방식의 단점은 SET 절의 서브쿼리가 업데이트할 행마다 반복 실행된다는 점이다.
단 건의 업데이트는 비효율이 크지 않지만 대량 업데이트 일수록 단점이 커진다.
오라클에서는 이를 수정가능 조인뷰로 처리할수 있고 아래와 같다.
UPDATE ( SELECT e.dname AS e_dname, d.dname AS d_dname FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE e.deptno IS NOT NULL ) SET e_dname = d_dname;
주의할 점은 1:M 관계에서 M 에 해당하는 컬럼만 수정이 가능한 제약이 있다.
위의 경우에서는 dept 에 속한 컬럼을 수정하려고 하면 에러가 날 것이다.
UPDATE ( SELECT e.empno,, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE e.empno = 7788 ) SET dname = 'RESEARCH';
=> 에러발생
ora-01779 cannot modify a column which maps to a non key-preserved table
# 타 DBMS 에서는..
- PostgreSQL: 조인이 포함된 뷰는 기본적으로 수정 불가 (단, INSTEAD OF 트리거를 사용하면 우회 가능) - MySQL: 일부 조건에서 조인 뷰 업데이트가 가능, 오라클만큼 유연하지는 않으며 제약이 많다. - SQL Server: 조인 뷰 업데이트는 제한적, 대부분 INSTEAD OF 트리거를 사용
SELECT * FROM ( SELECT parsing_schema_name, sql_id, plan_hash_value, executions, buffer_gets, -- logical reads disk_reads, -- physical reads rows_processed, cpu_time, -- total CPU time in microseconds elapsed_time, -- total elapsed time in microseconds ROUND(cpu_time / DECODE(executions, 0, 1, executions) / 1000000, 2) AS avg_cpu_sec, ROUND(elapsed_time / DECODE(executions, 0, 1, executions) / 1000000, 2) AS avg_elapsed_sec, SUBSTR(sql_text, 1, 100) AS sql_text_snippet FROM v$sqlarea WHERE parsing_schema_name NOT IN ('SYS', 'SYSTEM') AND executions > 0 ORDER BY cpu_time DESC ) WHERE ROWNUM <= 20;
-- sql full text 확인 SET LONG 100000 SET PAGESIZE 500 SET LINESIZE 150
--SELECT DBMS_LOB.SUBSTR(SQL_FULLTEXT, 100000, 1) AS full_sql_text SELECT DBMS_LOB.SUBSTR(SQL_FULLTEXT, DBMS_LOB.GETLENGTH(SQL_FULLTEXT), 1) -- SELECT SQL_FULLTEXT FROM v$sql WHERE sql_id = 'gngtvs38t0060';
-- 바인드 값 SELECT sql_id, name, position, datatype_string, value_string, was_captured, last_captured FROM v$sql_bind_capture WHERE sql_id = '91gau055wpf2p' ORDER BY position;
-- ACS 확인 SELECT sql_id, sql_fulltext, IS_BIND_SENSITIVE, IS_BIND_AWARE, LAST_LOAD_TIME, SQL_PROFILE, SQL_PLAN_BASELINE, LAST_ACTIVE_TIME FROM v$sql WHERE sql_id =''
CREATE USER USR_NORECO1 IDENTIFIED BY "user123" default tablespace TS_NORECO1 QUOTA UNLIMITED ON TS_NORECO1; CREATE USER USR_NORECO2 IDENTIFIED BY "user123" default tablespace TS_NORECO2 QUOTA UNLIMITED ON TS_NORECO2; CREATE USER USR_RECO IDENTIFIED BY "user123" default tablespace TS_RECO QUOTA UNLIMITED ON TS_RECO;
grant connect to USR_NORECO1, USR_NORECO2, USR_RECO; grant resource to USR_NORECO1, USR_NORECO2, USR_RECO;
3) 테이블 생성
CREATE TABLE USR_NORECO1.TAB1(A INT, B TIMESTAMP, C VARCHAR2(10)); CREATE TABLE USR_NORECO2.TAB1(A INT, B TIMESTAMP, C VARCHAR2(10)); CREATE TABLE USR_RECO.TAB1(A INT, B TIMESTAMP, C VARCHAR2(10));
col table_name for a20 col owner for a20 set linesize 200
select owner, table_name, tablespace_name from dba_tables where owner like 'USR%';
INSERT INTO USR_NORECO1.TAB1 values(1, SYSDATE, 'A'); INSERT INTO USR_NORECO1.TAB1 values(2, SYSDATE, 'AA'); INSERT INTO USR_NORECO2.TAB1 values(1, SYSDATE, 'B'); INSERT INTO USR_NORECO2.TAB1 values(2, SYSDATE, 'BA'); INSERT INTO USR_RECO.TAB1 values(1, SYSDATE, 'C'); INSERT INTO USR_RECO.TAB1 values(2, SYSDATE, 'CA');
SQL> select systimestamp from dual;
4) 1차 백업
rman target /
RUN { ALLOCATE CHANNEL c1 DEVICE TYPE DISK; BACKUP DATABASE FORMAT '/data/backup/db_%U'; BACKUP ARCHIVELOG ALL FORMAT '/data/backup/arch_%U'; BACKUP CURRENT CONTROLFILE FORMAT '/data/backup/ctl_%U'; RELEASE CHANNEL c1; }
5) 추가 트랜잭션 발생
INSERT INTO USR_NORECO1.TAB1 values(3, systimestamp, 'AB'); INSERT INTO USR_NORECO2.TAB1 values(3, systimestamp, 'BB'); INSERT INTO USR_RECO.TAB1 values(3, systimestamp, 'CB');
INSERT INTO USR_NORECO1.TAB1 values(4, SYSDATE, 'AC'); INSERT INTO USR_NORECO1.TAB1 values(5, SYSDATE, 'AAA');
INSERT INTO USR_NORECO2.TAB1 values(4, SYSDATE, 'BC'); INSERT INTO USR_NORECO2.TAB1 values(5, SYSDATE, 'BBB');
INSERT INTO USR_RECO.TAB1 values(4, SYSDATE, 'CC'); INSERT INTO USR_RECO.TAB1 values(5, SYSDATE, 'CBB');
col b for a30 select * from USR_RECO.TAB1; select * from USR_NORECO1.TAB1;
SQL> SELECT systimestamp FROM DUAL;
* 목표 복구시점은 drop 전 이다.
6) 아카이브 로그 생성
ALTER SYSTEM SWITCH LOGFILE; DROP TABLE USR_RECO.TAB1; ALTER SYSTEM SWITCH LOGFILE;
col name for a70 set linesize 300
SELECT thread#, sequence#, first_time, next_time, name, applied, deleted FROM v$archived_log ORDER BY thread#, sequence#;
3. RMAN 아카이브 백업
RMAN> BACKUP ARCHIVELOG ALL FORMAT '/data/backup/arch_%U';
백업파일 확인
ls -l /data/backup/
4. recodb VM start
/data/backup 에 백업이 완료 되었고, 이 디스크를 recodb 에 연결이 필요하다.
rm -rf /app/oracle/admin/oclasm/adump mkdir -p /app/oracle/admin/oclasm/adump ls -l /app/oracle/admin/oclasm/adump
rm -rf /app/oracle/oradata/oclasm/ mkdir -p /app/oracle/oradata/oclasm/ ls -l /app/oracle/oradata/oclasm/
rm -rf /app/oracle/arch/oclasm/ mkdir -p /app/oracle/arch/oclasm/ ls -l /app/oracle/arch/oclasm/
3) nomount
s1) echo $ORACLE_SID export ORACLE_SID=oclasm
sqlplus / as sysdba startup nomount pfile='/home/oracle/initoclasm.ora';
s2) echo $ORACLE_SID export ORACLE_SID=oclasm rman target / RESTORE CONTROLFILE FROM '/data/backup/ctl_0j4tjtbp_1_1'; ALTER DATABASE MOUNT;
report schema;
RUN { SET NEWNAME FOR DATAFILE 1 TO '/app/oracle/oradata/oclasm/system01.dbf'; SET NEWNAME FOR DATAFILE 3 TO '/app/oracle/oradata/oclasm/sysaux01.dbf'; SET NEWNAME FOR DATAFILE 4 TO '/app/oracle/oradata/oclasm/undotbs01.dbf'; SET NEWNAME FOR DATAFILE 8 TO '/app/oracle/oradata/oclasm/ts_reco01.dbf';