database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
PostgreSQL
Firebird
ㆍOracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
Oracle Q&A 23958 게시물 읽기
No. 23958
[질문] 이미 들어가 있는 데이터 UPDATE시.. 다시 조회
작성자
마린보이
작성일
2005-09-05 19:07
조회수
2,420

안녕하세요.

 

이미 데이터가 들어가 있는경우

 

SELECT 를 이용해서 조사를 하거나

 

혹은 EXCEPTION을 캐치 해서 UPDATE를 하게 되는데요

 

모 좀 깔끔하게 한큐에 되는 방법은 없는지..

 

고수 여러분들에 답변을 듣고 싶습니다.

이 글에 대한 댓글이 총 8건 있습니다.

update 문에 조건을 주면 한방에 됩니다...

 

음~질문에 원하는 답이 이게 아닌가^^

 

 

단테님이 2005-09-06 08:38에 작성한 댓글입니다. Edit

어떤 Language를 사용하느냐에 따라 지원여부가 다르긴 하지만,

저같은 경우는 일단 Update문을 던진 다음에 AffectdedRow가

0건인 경우에 Insert를 칩니다...^^

나그네님이 2005-09-06 10:25에 작성한 댓글입니다. Edit

 

질문을 정확히 이해를 잘 못했는지는 모르겠지만 두가지로 생각해 볼 수 있을듯 합니다.

 

1. 데이타가 있을 경우엔 update, 없을 경우엔 insert를 해야한다.

이럴 경우엔 오라클 버전 9i 아래에선 select 해본 후 insert인지 update인지를 판단 하고, update/insert를 하지요.

exception을 발생시켜서 처리한다는건 일단 에러를 발생해서 처리를 한다는 것이기 때문에 방법에 따른 결과는 동일하다 하더라도 올바른 방법은 아닐 듯합니다.

만약 9i 아상의 버전을 사용하신다면 merge into를 사용하시면 insert 혹은 update를 select문을 별도로 날리지 않고 하실 수 있습니다.

 

2. insert가 아니라 단순히 update만 하면 되는거라면 단테님 말씀대로 update문에 조건만 주심 됩니다...

이현석(dreamlhs)님이 2005-09-06 10:46에 작성한 댓글입니다.

이문제는 트랜잭션 문제를 생각하셔야 합니다.

 

제 의견은 이현석님의 의견과 정반대 인데요..

 

인서트 후 exception 받아서 update하는 것이 가장 안전합니다.

 

그 이유는 좀 길지만 ....

 

참고하실 수 있는 글을 제가 올려놓은 것이 있습니다.

 

각 케이스별 테스트 및 동시 사용자 상태에서의 효과 까지 올려 놓았습니다.

 

검색어 창에서 "MERGE INTO 질문입니다." 를 치시면 찾아 보실 수 있습니다.

^^

 

김흥수(protokhs)님이 2005-09-06 15:05에 작성한 댓글입니다.
이 댓글은 2005-09-06 15:06에 마지막으로 수정되었습니다.

요새 참 이상하게도 제가 댓글만 달면 흥수님하고 같이 들어가게 되네요...^^

 

흥수님께서 예전에 작성하신 글을 읽어보긴 했습니다.

 

근데 글올리신 마린보이 님은 데이타가 어떤지, 트랜잭션이 어떤지에 대한 정보는 주지 않으시고 단지 깔끔하게 한큐에 되는 방법을 원하셨기에 그런 말씀을 드린 것이구요,

주어진 정보내에서 얘기 하자면 제가 말씀드린 두가지 방법이 그나마 바람직하단 말씀을 드린겁니다.

 

exception캐치를 어디서 하는지는 모르겠으나,

was에서 하든 dbms에서 하든 exception발생 자체가 부담입니다.

최소한 로그 한줄이라도 써야 하기 때문이죠.

그래서 가급적 exception은 발생시키지 말자는 취지에서 말씀드린 겁니다.

exception은 말그대로 예외상황입니다.

데이타가 있는지 없는지를 보는건 예외사항이 아니라 정당한 트랜잭션 행위중의 하나 일 뿐입니다.

 

데이터 일관성 측면에서 안전은 하겠지만 방법은 아닌듯 합니다.

차라리 에러를 내고 빠져버리는게 맞을듯......

 

 

이현석(dreamlhs)님이 2005-09-06 18:09에 작성한 댓글입니다.

아..한가지만 더요..

 

굳이 exception을 발생해야 한다면 그래도 오라클에서 하는걸 권합니다.was에서 하는건 왠지 아닐꺼 같다는 느낌이 팍 드네요...(시간적인 차이가 아무래도 있을테니깐요...)

이현석(dreamlhs)님이 2005-09-06 18:10에 작성한 댓글입니다.

이현석님께...

방금 님께 메일 한통 띄우고

쭉 검색하다보니

님의 답글이 있으시네요...

 

그리고 나서 정말 보니까...

 

님께서 답글 달고 나면 제가 달았더군요^^

 

뭐 ...

우연입니다.

그리고 단지 의견이 차이난 것 뿐이구요..

 

어케하다보니 그리 되었네요....

 

그리고 exception 잡아서 한다는 거는...

 

PL-SQL 내부에서만 입니다.

 

그리고....

 

과거에(물론 지금도 그럴지 모르지만) 많이 쓰이던 한 방법입니다.

어찌보면 공룡 화석 같은 PL-SQL 프로그래밍 테크닉이구요...

 

그리고 님의 말씀...

예외는 역시 예외이다!

 

이것 전적으로 맞는 말씀입니다.

 

사실 저 역시 예외를 일반적인 것으로 사용하도록 한 PL-SQL정책이 마음에 안듭니다.

 

특히 dup_val_on_index 이거 보다 No_data_Found 이거가 더 마음에 안듭니다.

 

데이타를 가져오려고 했는데 단지 없다는 것이 예외라니!

 

마음에 안듭니다.

 

예를 들어 파일을 열려고 하는데 파일이 없으면 에러다!

 

이건 맞지만 파일을 읽는데 읽을 자료가 없다고 예외라고 하는 격이니까요....

 

그렇지만 어떻게 합니까?

오라클은 이런 것을 예외로 합니다.(물론 dup은 예외가 타당하다고 봅니다.)

 

그리고 님의 말씀대로 실제로 exception은 상당한 오버헤드가 있습니다.

 

제가 테스트해본 기억으로는 최소 5배 가량 느렸었습니다.

가장 빠른 것은 update후 sql%rowcount 를 비교하여 insert 하는 것이 가장 빨랐습니다. 그리고 이런 방식이 9i의 merge입니다.

 

그러나

 

트랜잭션의미가 중요한 경우는 엄밀히 말하면 merge의 사용도 상호 배타적으로 하거나...

아예 테이블을 잠가놓고 해야한다고 생각합니다.

 

 

김흥수(protokhs)님이 2005-09-06 22:04에 작성한 댓글입니다.

찾아보니 그전에 테스트한다고 만들어 놓은 것이 있어서 세가지 방법의 성능을 비교하여 올립니다.

참고 하십시오.^^

 

Create or replace procedure p_transaction1
(
 ar_id   number
)
is
begin
 for lii in 1..10000 loop
  begin
   insert into t_transaction
   (
    id,
    cnt
   )
   values
   (
    ar_id,
    1
   );
  exception when dup_val_on_index then
   update t_transaction
   set  cnt = nvl(cnt,0) + 1
   where id = ar_id;
  end;
 end loop;
end;
/
Create or replace procedure p_transaction2
(
 ar_id   number
)
is
 liCnt   number;
begin
 for lii in 1..10000 loop
  Select
   count(*)
  into
   liCnt
  from t_transaction
  Where id = ar_id;
  If liCnt <= 0 Then
   insert into t_transaction
   (
    id,
    cnt
   )
   values
   (
    ar_id,
    1
   );
  else
   update t_transaction
   set  cnt = nvl(cnt,0) + 1
   where id = ar_id;
  end if;
 end loop;
end;
/
Create or replace procedure p_transaction3
(
 ar_id   number
)
is
begin
 for lii in 1..10000 loop
  update t_transaction
  set  cnt = nvl(cnt,0) + 1
  where id = ar_id;
  If SQL%RowCount <= 0 Then
   insert into t_transaction
   (
    id,
    cnt
   )
   values
   (
    ar_id,
    1
   );
  end if;
 end loop;
end;
/

 

1번은 예외 방법

2번은 select 후 update나 insert

3번은 일단 update 후 없으면 insert...

 

SQL> set timing on
SQL> exec p_transaction1(1);

PL/SQL 처리가 정상적으로 완료되었습니다.

경   과: 00:00:06.01
SQL> exec p_transaction2(1);

PL/SQL 처리가 정상적으로 완료되었습니다.

경   과: 00:00:01.02
SQL> exec p_transaction3(1);

PL/SQL 처리가 정상적으로 완료되었습니다.

경   과: 00:00:00.05
SQL>

 

 

결과는 3번이 가장 빠르고 2번이 그다음 1번이 제일 느립니다.^^

이현석님 말씀대로 exception이 오버헤드가 가장 크죠...

 

그러나 저같은 경우 안정성이 있다면 이정도 성능은 무시합니다.

김흥수(protokhs)님이 2005-09-06 22:11에 작성한 댓글입니다.
이 댓글은 2005-09-06 22:13에 마지막으로 수정되었습니다.
[Top]
No.
제목
작성자
작성일
조회
23961부서별, JOB별 합계 구하기 [5]
www
2005-09-05
1951
23960[질문]프로시져를 사용하는 원인 [1]
최규운
2005-09-05
1328
23959ORA-00911: 문자가 부적합합니다 [3]
최규운
2005-09-05
11319
23958[질문] 이미 들어가 있는 데이터 UPDATE시.. 다시 조회 [8]
마린보이
2005-09-05
2420
23957대용량 데이터 환경에서 clob 사용 및 관리에 관한 질문 [2]
궁금
2005-09-05
2858
23956instance level trace를 하려고 합니다. [1]
이은주
2005-09-05
1214
23955[질문]오라클 데이터좀(복원)..살려주세요... [2]
김성훈
2005-09-05
1223
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.017초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다