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 38574 게시물 읽기
No. 38574
순차적으로 증가하는 값으로 trigger 생성하기
작성자
김홍찬(chani282)
작성일
2011-05-29 23:46
조회수
5,610

 

a, b 가는 컬럼이 있는 테이블이 있는 테이블(가)이 있습니다.(a 는 pk)

여기서 b컬럼이 update 될 때마다 트리거를 이용하여 다른 테이블(나)에 넣고 싶은데

(가)테이블 b값은 몇번이고 update 될 수 있기때문에
변경된 순번을 같이 넣어주고 싶은데요

ex)
첫번째 update =>   a, 1, b
두번째 update =>   a, 2, b
n번째 update =>     b, n, b

sequence를 이용해보려 했으니 a값에 대해서 순차적인 값이 아니라 안되고...
기존 테이블에서 select count하여 하기엔 데이터가 쌓일수록 속도에 문제가 있을듯하구요...
컬럼데이터와 시퀀스를 병합할 수 있는 ... 먼가 기능이 없을까요..?

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

 답답하시겠네요...

아마도 설계자가 순번을 "a 컬럼별 순번" 이라고 정해놓았나보죠?

안타깝게도 성능도 최대로 만족하고 모양새도 나는 방법은 없어요

성능을 생각하면 시퀀스를 쓰세요... 아마도 이 것이 가장 비용이 작게 들 겁니다.

그런데 그게 원하는 바가 아니라면 select count 가 아닌 select max 를 쓰세요

그러면 히스토리가 저장되는 테이블에 키 컬럼이 a컬럼과 순번이라고 가정하면

first row - index range scan (min/max) 가 떨어져서 데이타가 쌓여도 성능이 크게 떨어지지는 않을 것입니다.

그러나 문제는 어떤 방법을 쓰더라도 특정 데이타에 의존적인 순번을 사용하면 그 특정데이타를 가져올 때 반드시 해당 데이타를 배타적으로 lock을 걸어야 안전하기 때문에 시퀀스에 비하면 select비용과 lock비용을 지불해야 합니다.(시퀀스도 오라클에서 내부적인 경량의 lock을 사용하여 구현되지만 말 그대로 경량이므로 테이블에 걸리는 lock에 비할 바가 아니랍니다.) 어떤방법이 상대적으로 더 빠르거나 느릴 수 있어도 기본적으로 두가지 비용이 들게 된다는 것입니다. select-count 에 비해 select-max 는 select 비용을 줄이기는 하지만 lock 이 걸리는 문제는 동일하고

select-for-update로 lock을 걸 경우 lock의 범위를 최소화하기 위해 히스토리 테이블 중에서 a컬럼이 특정 값인 경우만 lock을 걸게 될 공산이 큰데.... 그 경우는 동시 트랜잭션에서 해당 특정값을 처음으로 동시에 insert 하는 경우에는 충돌이 생길 가능성이 있게 되므로 전체 테이블을 lock을 걸거나 dbms_lock 같은 페키지를 사용하는 방법을 취하거나 해야 안전할 것입니다.

만약 insert의 실패가 그다지 중요하지 않으면 그냥 동시 트랜잭션중 하나를 실패시키도록 lock을 걸지 않고 코딩하는 것도 하나의 방법입니다.(개인적으로는 나쁜 방법이 아니라고 봅니다.-동시작업의 두번째 트랜잭션은 pk에로로 실패하겠죠?)

 

생각보다 복잡하다고 생각하실 수 있습니다.

그렇죠?

 

아마도 설계자가 얼마나 많은 고민 속에서 컬럼별 순번을 pk로 잡았는지는 모르지만 어떤 테이블도

논리적,물리적으로 컬럼별 순번인 테이블을 전부 단일 컬럼의 순번으로 키를 잡아도 프로그램이 동작하는데 전혀 문제가 없으며 오히려 더 잘 동작하고 프로그램도 더 짜기 쉽다는 것(위와 같은 경우 그냥 시퀀스를 쓰면 되니까 얼마나 편합니까?)을 알 필요가 있다고 봅니다.

김흥수(protokhs)님이 2011-05-30 10:45에 작성한 댓글입니다.
이 댓글은 2011-05-30 10:54에 마지막으로 수정되었습니다.

해당 (가)테이블의 구조변경이 가능하다면?
순번 컬럼을 추가로 관리하세요.
(나)테이블 스캔 없이 기능 구현이 가능합니다.


ALTER TABLE (가)테이블 ADD seq NUMBER DEFAULT 0;


CREATE OR REPLACE TRIGGER 트리거_(가)테이블
BEFORE UPDATE OF b ON (가)테이블
FOR EACH ROW
BEGIN
    -- (가)테이블의 순번컬럼 증가
    :new.seq = :old.seq + 1;
    -- (나)테이블에 (가)테이블의 변경사항 입력
    INSERT INTO (나)테이블 VALUES (:new.a, :new.seq, :new.b);
END;
/

마농(manon94)님이 2011-05-30 11:05에 작성한 댓글입니다.
이 댓글은 2011-05-30 11:06에 마지막으로 수정되었습니다.

 아 하나 중재안이 있는데요...

그나마 이것은 테이블 설계에 어느정도 관여할 수 있어야 합니다.

즉 원본테이블에 max순번 컬럼을 가져가는 것입니다.

이렇게하면 select 시간을 최대한 줄이겠죠...

그래도 역시 lock은 남고

김흥수(protokhs)님이 2011-05-30 11:12에 작성한 댓글입니다.

(나)테이블에 sequence를 대입하는 트리거를 만들어 주면됩니다. 

 

예를 들어, (나)테이블의 컬럼이 (a, s, b) 이고 sequene 이름이 seq 라고하면, 트리거 는 다음과 같이 만들면 됩니다.

 

CREATE OR REPLACE TRIGGER 트리거_(나)테이블
  BEFORE INSERT ON (나)테이블
  FOR EACH ROW
  WHEN (new.s is NULL)
  BEGIN
     SELECT seq.nextval INTO :new.s FROM DUAL;
  END;
/

 

(가)테이블의 트리거에서 (나)테이블의 s컬럼 값으로 NULL을 사용하면, (나)테이블의 트리거가 sequence값을 집어 넣어 줍니다.

 
CREATE OR REPLACE TRIGGER 트리거_(가)테이블
  BEFORE UPDATE OF b ON (가)테이블
  FOR EACH ROW
  BEGIN
     INSERT INTO (나)테이블 VALUES (:new.a, NULL, :new.b);
  END;
/

 

참고로, (나)테이블을 만들때, (..., s number default null, ...)과 같이 default 값을 정해주면, (가)테이블의 트리거는 다음처럼 만들 수 있읍니다.

 

CREATE OR REPLACE TRIGGER 트리거_(가)테이블
BEFORE UPDATE OF b ON (가)테이블
FOR EACH ROW
BEGIN
INSERT INTO (나)테이블 (a, b) VALUES (:new.a, :new.b);
END;

 

hopper(bunny)님이 2011-05-30 14:05에 작성한 댓글입니다.
이 댓글은 2011-05-30 23:01에 마지막으로 수정되었습니다.
[Top]
No.
제목
작성자
작성일
조회
38577조회시 * 사용 [3]
궁금이
2011-06-01
3379
38576프로시저 스크립트 내에서 자신의 프로시저명(이름) 구하는 방법
한동훈
2011-06-01
3198
38575오라클 설치시 out of memory 가 뜹니다... [1]
설치에러..
2011-05-31
4504
38574순차적으로 증가하는 값으로 trigger 생성하기 [4]
김홍찬
2011-05-29
5610
38573sql구간 구하기 질문이요 [2]
SQL초보
2011-05-27
4227
38572프로시져 내부 WHERE 절에서 '변수' 처리 사용할때... [5]
라클리
2011-05-27
5987
38571프로시져에서 시스템 테이블 사용시 에러 (ORA-00942) [2]
라클리
2011-05-26
5380
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.019초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다