Oracle/튜닝

B-Tree 인덱스 구조

pbj1102 2022. 2. 10. 16:15
반응형

B-Tree 인덱스 구조

 

루트 블록 : 브랜치 블록의 블록 주소, 인덱스 컬럼 값으로 구성

브렌치 블록 : 리프 블록의 블록 주소, 인덱스 컬럼 값으로 구성

리프 블록 : 인덱스 컬럼, 테이블 ROWID로 구성

                인덱스 컬럼으로 정렬되어 있으며, 컬럼 값이 같으면 ROWID 로 정렬

 

CREATE INDEX products_price_idx ON products(price);   --  products 테이블의 price 컬럼에 비고유 인덱스 생성

1. products 테이블 전체를 읽고, price로 오름차순 정렬한다.
2. 정렬된 price 값과 해당 값이 포함된 행의 ROWID를 첫 번째 리프 블록부터 채워 넣는다.
3. 리프 블록이 완성되면, 각 리프 블록의 첫 번째 price 값과 해당 리프 블록의 주소를 첫 번째 브랜치 블록부터 채워 넣는다.
4. 브랜치 블록이 완성되면, 각 브랜치 블록의 첫 번째 price 값과 해당 브랜치 블록의 주소를 루트 블록에 채워 넣는다.

 

 

products_price_idx B-Tree 인덱스 구조

 

 

실습)

SELECT *
FROM products
WHERE price = 3350;

1. 루트 블록의 첫 번째 price 값부터 차례로 3350과 비교한다.
2. 3350보다 작은 값들 중에 가장 큰 값(3100)을 찾고, 해당 블록 주소(90000)를 읽는다.
3. 90000번 블록을 읽는다.
4. 90000번 브랜치 블록의 첫 번째 price 값부터 차례로 3350과 비교한다.
5. 3350보다 작은 값들 중에 가장 큰 값(3300)을 찾고, 해당 블록 주소(30000)를 읽는다.
6. 30000번 블록을 읽는다.
7. 30000번 리프 블록의 첫 번째 price 값부터 차례로 3350을 검색한다.
8. price가 3350인 항목이 발견되면, ROWID를 읽는다.
9. ROWID를 이용하여 해당 행이 저장되어 있는 테이블 블록을 읽는다.

 

 

 

 

SELECT /*+ gather_plan_statistics */ *
FROM products
WHERE price = 3350;

 

 select * from table(dbms_xplan.display_cursor(null,null,'TYPICAL ALLSTATS LAST'));

 

[PLAN]

SQL_ID  7dqsdht7bwp3y, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics */ * FROM products WHERE price = 3350
 
Plan hash value: 1668926985
 
----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name               | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                    |      1 |        |       |     3 (100)|          |      2 |00:00:00.01 |       5 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| PRODUCTS           |      1 |      2 |    40 |     3   (0)| 00:00:01 |      2 |00:00:00.01 |       5 |
|*  2 |   INDEX RANGE SCAN                  | PRODUCTS_PRICE_IDX |      1 |      2 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       3 |
----------------------------------------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("PRICE"=3350)

 

설명, 

[ID = 2]  -->>  PRODUCTS_PRICE_IDX 인덱스에서 Buffers 3개의 블록을 읽음

[ID = 3]  -->>  테이블에서 2개의 블록을 읽음 (=5-3) 

 

 

옵티마이저의 판단은 INDEX RANGE SCAN 을 타도록 유도하고 있다.

 -> 결론적으로는 힌트를 지정할 필요 없이, 해당 SQL 의 구문의 경우 인덱스를 타게 된다. 

 -> 오라클에서는 힌트의 사용을 권장하지 않는다. 

     하지만, 바인드 변수를 사용하거나 통계정보가 오래된 경우에는 옵티마이저가 올바른 판단을 내리기 쉽지 않으므로 이와 같은 경우에는 올바른 힌트를 사용하는것을 추천한다. 

 

 

 

반응형

'Oracle > 튜닝' 카테고리의 다른 글

INDEX RANGE SCAN  (0) 2022.02.10
INDEX UNIQUE SCAN  (0) 2022.02.10
FULL TABLE SCAN  (0) 2022.02.10
실행계획 순서분석  (0) 2022.01.28
DISPLAY_CURSOR  (0) 2022.01.28