BULLETIN CATEGORY BULLETIN TOPIC |
: SQL*Plus : ROWID에 대한 이해 |
올바른 환경에서의 ROWID의 사용은 SQL이나 PL/SQL Code의 실행을 보다 빠르게 하여 준다. 그러나 ROWID는 경우에 따라 Program을 전혀 엉뚱한 동작을 하게 만들 수 있으므로 ROWID의 사용은 특별한 주의를 기울여야 한다.
Oracle ROWID란 무엇인가 ? Oracle Table의 모든 Row는 ROWID라고 하는 물리적인 Address로 Assign 된다. 누군가가 ROWID을 사용하여 한 Table안의 서로 다른 Column에 대하여 설계하고, 제한하는 기능들을 사용한다 하더라도 이것은 Pseudo-Column이다. Oracle의 Pseudo Column은 Table의 실제적인 Column은 아니므로 Table의describe를 통해서는 보이지 않지만 매우 유용하게 사용된다. Pseudo Column의 다른 예는 Currval, Nextval ( Sequence Number Generator )와 Level ( For Hierarchical Queries ), Rownum ( A Row's Relative Number ) 같은 것들이 있다. 내부적으로 ROWID는 Binary 값을 가진다. 그러나 외부적으로 Display 될 때에는 Varchar2 Type의 Column에 저장된 3 Part의 Hexadecimal String으로 표현된다. 첫번째 부분( 1 - 8 ) 은 Block Id를 나타낸다. Substr Function을 사용하여 ROWID를 구분하여 Select해 보면, 위의 Select 구문은 다음과 같은 ROWID에 대하여 아래의 결과를 출력할 것이다. ROWID 0000033d.0000.0001 위의 예와 같이 Row의 값은 Block 내에서의 첫번째 Row이다. n It's Fast! ROWID를 사용하여 Table의 Row를 Access하는 것은 빠르다. 사실상 Rule-Based Optimizer에서는 ROWID를 이용하여 Access하는 것이 가장 상위로 Rank 된 Access 방법이다. 다음은 Access Path 선택의 Rule을 나타낸다. Rank Access Path 위에서처럼 가장 빠른 Access 방법은 ROWID를 사용하는 것이다. 이러한 Access 방법은 아래의 사항이 만족되어 질 때에만 사용 가능 하다. 1. Where 절에서 ROWID로 Row를 선택하거나 위의 사항을 만족한다면 Oracle Server는 해당하는 Physical Address를 가지고 Data Row를 Access 할 것이며 결과 또한 가장 빠를 것이다. 그러나 빠른 Access가 가능한 만큼 허점도 가지고 있는데, ROWID가 변할 수 있다는 점이 그것이다. ROWID 변경 Row의 Address는 서로 다른 환경하에서는 변할 수 있다. 예를 들면, Import 직후의 Export는 일반적으로 서로 다른 ROWID를 생성한다. 그러나 이 경우는 문제가 되지 않는다. 왜냐하면 ROWID가 User의 Transaction의 영역 밖에서 일어났기 때문이며, 이러한 변화는 전혀 고려할 만한 사항이 아니다. 반면에 어떤 User가 DML 작업을 하는 도중에 ROWID가 변하였다고 가정해보자. 아래는 이러한 문제점을 잘 보여주는 예제이다.
(Commit_After_In In Integer := 100, Requery_After_In In Integer := 1000) Is More_Data Boolean := True; Commit_Count Integer := 0; Cursor Trans_Cur Begin Insert Into Master_Table Update Transfer_Table Commit_Count := Commit_Count + 1; Loop 내에서는 Current Cursor Record의 ROWID을 Reference 하는 Insert 문장과 Update 문장이 함께 사용되고 있다. 또한 이 Cursor For Loop 안에서는 Argument로 넘겨받은 Interval 변수에 따라 Commit 문이 실행된다. Commit 문이 실행되면, Cursor에 의해 사용되던 ROWID는 변할 수 있다. 이러한 상황이 Single-User의 환경에서 발생하는 것이라면 아무런 문제가 없으나, Multi-User의 Concurrent Transaction 환경이라면 많은 문제가 발생할 것이다. * 다른 User 가 현재 사용하고 있는 ROWID를 Invalid 하게 하는Update나 Insert, 이러한 문제는 잘 드러나지 않을 뿐만 아니라 Error를 Detect 하기도 힘들고, 거의 Debug 가 불가능하다. 결 론 ROWID는 엄격한 제한 조건을 가지고 주의 깊게 사용되어야 한다. 대상 Row에 Lock을 걸지 않는 SQL문장내에는 ROWID를 사용해서는 안된다. Transfer_All Procedure의 경우 Error를 Fix 하기 위하여 2가지를 수정해야 한다. 첫째, Cursor의 선언 부분에 " For Update Of ROWID" 가 추가 되어야 하며, 이러한 수정이 Program을 다소 유연하지 못하게 만드는 것처럼 보일지도 모르지만, 확실히 Program을 신뢰성있게 만들어 준다. |
Oracle Korea Customer Support Technical Bulletins |