NLJ_PREFETCH 의 정렬 발생 0 6 1,473

by 양양 [Oracle Tuning] [2022.11.13 21:54:44]


정상1.JPG (43,151Bytes)
소트2.JPG (46,118Bytes)

안녕하세요. NLJ_PREFETCH 조인중 DRIVING TABLE 인덱스를 잘 골라도 정렬이

발생하는 이유가 알고싶어 문의드리게 되었습니다..

혹시나 가르침이나 사견이라도 주시면 굉장히 감사하겠습니다.

 

**1 테스트 환경

CREATE TABLE T1(T1_COL1 NUMBER, T1_COL2 NUMBER,T1_COL3 NUMBER);
CREATE TABLE T2(T2_COL1 NUMBER, T2_COL2 NUMBER, T2_COL3 NUMBER);

CREATE INDEX IDX_T1 ON T1(T1_COL1,T1_COL2);
CREATE INDEX IDX_T2 ON T2(T2_COL1);

-------------------------------------------------------------------------------

** 2 일반적인 조인

SELECT /*+ LEADING(T1) NLJ_PREFETCH(T2) */  T1.*, T2.*
FROM T1, T2
WHERE T1.T1_COL1=1
AND T1.T1_COL2 = T2.T2_COL1
ORDER BY T1.T1_COL1, T1.T1_COL2;

 

-------------------------------------------------------------------------------

** 3 후행테이블 의도적 BATCH I/O 발생

SELECT /*+ LEADING(T1) NLJ_PREFETCH(T2) BATCH_TABLE_ACCESS_BY_ROWID(T2) */  T1.*, T2.*
FROM T1, T2
WHERE T1.T1_COL1=1
AND T1.T1_COL2 = T2.T2_COL1
ORDER BY T1.T1_COL1, T1.T1_COL2;

 

NL JOIN을 유도하면서 선행 테이블은 BATCH I/O가 발생을 막았는데

SORT가 발생하는 이유를 잘 모르겠습니다.

 

by 마농 [2022.11.14 09:19:08]

프리패치는 읽어올 가능성이 있는 테이블 블럭을 미리 메모리에 올리는 것입니다.
그다음 읽어야 할 블럭이 미리 올려둔 것이라면 그대로 읽으면 되고
그렇지 않다면 다시 메모리에 올려서 읽게 됩니다.
즉 메모리에 미리 올려둘 뿐 인덱스 스캔 방식은 동일합니다. -> 정렬 유지

배치테이블 엑세스는
위에서 언급한 실패(미리 올려둔 블럭이 지금 읽어야 할 블럭이 아닌 경우)한 경우에
이를 곧바로 메모리에 올리는게 아니고 쌓아 두었다가 나중에 한번에(배치) 올리는 방식입니다.
따라서 NLJ_PREFETCH 까지는 정렬 유지 기능이지만
BATCH_TABLE_ACCESS_BY_ROWID 가 추가되면 정렬 유지 안됩니다.
 


by 양양 [2022.11.14 09:55:28]

헉.. 마농님 또 답글을 감사합니다!!

order by절은 드라이빙 테이블(t1)의 컬럼을 가리키고 batch_table_access_by_rowid는 드라이븐(t2)을 가리키고 있는데

드라이빙 테이블의 인덱스를 잘 타도 정렬이 발생하는 것이 이해가 안됩니다..


by 마농 [2022.11.14 10:27:12]

결과를 리턴하기 위해서는 일정 사이즈를 채워야 합니다. (패치사이즈? 어레이사이즈?)
배치가 동작하면 조인에 성공한 것부터 운반단위 메모리에 쌓고
성공하지 못한 것은 모아두었다가 나중에 다시 조인을 시도하게 됩니다.
먼저 채워진것이 먼저 반환이 되니 정렬이 유지되지 않는 것입니다.


by 양양 [2022.11.14 16:29:37]

배치 I/O는 드라이븐(T2) 테이블만 발생하는데, 인덱스를 순수하게 타는(=NO배치I/O) 드라이빙(T1)의 순서도 틀어지는걸까요.... 정렬은 드라이빙(T1) 테이블을 기준으로 하고있습니다


by 마농 [2022.11.14 16:56:06]

T1 을 읽어오는 순서가 틀어진게 아닙니다.
결과셋의 순서가 틀어지는 것이죠.
읽어오는 순서대로 조인하여 결과를 리턴하면 그대로 출력이 되는데
조인에 실패한 행들은 나중에 한꺼번에 다시 조인을 시도하게 되어서 출력 순서가 달라지는 것이죠.
예를 들어 T1 에서 1,2,3,4,5 읽어온 뒤
t2 를 조인하게 되면 1번을 찾으면서 인접 블럭들을 미리 메모리에 올리구요. (프리패치)
이때 올라온 메모리에 1,2,4,5 만 올라와 있다고 가정하면?
1, 2 는 성공하여 결과셋에 추가가 되고
3은 메모리에 올라온게 없어서 테이블 읽기를 일단 뒤로 미룹니다. (배치)
이 상태에서 4, 5 를 먼저 확인하는데 메모리에 올라와 있어서 결과셋에 추가가 되면
나중에 3을 메모리에 올려서 결과셋에 추가하게 되는 방식입니다.
출력 순서는 1,2,4,5,3 이 되겠지요.


by 양양 [2022.11.15 09:34:49]

5번 정독했습니다. 감사합니다....

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입