최적화 사례 4 - 잘못된 큰 시계 HASH + 병행 --- > 올 바른 Nested loop

큰 시계 와 큰 시계 간 의 연결 방식 에 대해 말하자면 항상 의식 적 으로 HASH JOIN + 를 선택 하고 병행 하 는 효율 이 높 습 니 다. 사실은 구체 적 인 상황 은 반드시 구체 적 인 문제 가 있어 야 합 니 다. 어떤 때 는 큰 시계 가 포 함 된 순환 의 효율 이 HASH JOIN 보다 좋 습 니 다. 다음은 제 가 전에 최적화 한 사례 로 설명 하 겠 습 니 다.
      한 친구 가 저 를 찾 아와 서 SQL 을 최적화 시 켰 어 요. 논리 적 으로 103 만 개, 물리 적 으로 103 만 개 를 읽 고 19 초 를 뛰 어야 완 주 할 수 있다.
     다음은 SQL 및 실행 계획 입 니 다.
     
SELECT "A1"."SERV_ID"
   ,"A1"."ATTR_ID"
   ,"A1"."ATTR_VAL"
   ,"A1"."EFF_DATE"
   ,NVL("A1"."EXP_DATE", TO_DATE(NULL, NULL))
   ,"A2"."OP_SEQ"
   ,"A2"."OP_TYPE"
FROM COMM."USER_INFO_OPLOG_MASTER2" "A2"
   ,COMM."SERV_ATTR" "A1"
WHERE "A2"."MEMOP_DATE" IS NULL
   AND "A2"."TABLE_NAME" = 'SERV_ATTR'
   AND "A1"."SERV_ID" = "A2"."TABLE_COLUMN_1"
   AND "A1"."AGREEMENT_ID" = "A2"."TABLE_COLUMN_2"
   AND "A1"."ATTR_ID" = "A2"."TABLE_COLUMN_3"
ORDER BY "A2"."OP_SEQ"

563 rows selected.

Elapsed: 00:00:19.50

Execution Plan
----------------------------------------------------------
Plan hash value: 669020553

---------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                        | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                             |   150K|    17M|       | 61528   (3)| 00:12:19 |        |      |            |
|   1 |  PX COORDINATOR                      |                             |       |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (ORDER)                 | :TQ10002                    |   150K|    17M|       | 61528   (3)| 00:12:19 |  Q1,02 | P->S | QC (ORDER) |
|   3 |    SORT ORDER BY                     |                             |   150K|    17M|    20M| 61528   (3)| 00:12:19 |  Q1,02 | PCWP |            |
|   4 |     PX RECEIVE                       |                             |   150K|    17M|       | 61526   (3)| 00:12:19 |  Q1,02 | PCWP |            |
|   5 |      PX SEND RANGE                   | :TQ10001                    |   150K|    17M|       | 61526   (3)| 00:12:19 |  Q1,01 | P->P | RANGE      |
|*  6 |       HASH JOIN                      |                             |   150K|    17M|       | 61526   (3)| 00:12:19 |  Q1,01 | PCWP |            |
|   7 |        BUFFER SORT                   |                             |       |       |       |            |          |  Q1,01 | PCWC |            |
|   8 |         PX RECEIVE                   |                             |   147K|    11M|       |  1069   (1)| 00:00:13 |  Q1,01 | PCWP |            |
|   9 |          PX SEND BROADCAST           | :TQ10000                    |   147K|    11M|       |  1069   (1)| 00:00:13 |        | S->P | BROADCAST  |
|  10 |           TABLE ACCESS BY INDEX ROWID| USER_INFO_OPLOG_MASTER2     |   147K|    11M|       |  1069   (1)| 00:00:13 |        |      |            |
|* 11 |            INDEX RANGE SCAN          | IDX_INFO_OPLOG_M2COMB_11502 |  6113 |       |       |    33   (0)| 00:00:01 |        |      |            |
|  12 |        PX BLOCK ITERATOR             |                             |   229M|  9427M|       | 60101   (2)| 00:12:02 |  Q1,01 | PCWC |            |
|* 13 |         TABLE ACCESS FULL            | SERV_ATTR                   |   229M|  9427M|       | 60101   (2)| 00:12:02 |  Q1,01 | PCWP |            |
---------------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("A1"."SERV_ID"="A2"."TABLE_COLUMN_1" AND "A1"."AGREEMENT_ID"="A2"."TABLE_COLUMN_2" AND "A1"."ATTR_ID"="A2"."TABLE_COLUMN_3")
  11 - access("A2"."MEMOP_DATE" IS NULL AND "A2"."TABLE_NAME"='SERV_ATTR')
       filter("A2"."TABLE_NAME"='SERV_ATTR')
  13 - filter(SYS_OP_BLOOM_FILTER(:BF0000,"A1"."SERV_ID","A1"."AGREEMENT_ID","A1"."ATTR_ID"))

Note
-----
   - dynamic sampling used for this statement (level=6)


Statistics
----------------------------------------------------------
         30  recursive calls
          0  db block gets
    1039308  consistent gets
    1003269  physical reads
        716  redo size
      31187  bytes sent via SQL*Net to client
        927  bytes received via SQL*Net from client
         39  SQL*Net roundtrips to/from client
         11  sorts (memory)
          0  sorts (disk)
        563  rows processed

    실행 계획 을 보면 대략 세 가지 문제 가 있다.
< 1 > 원래 SQL 은 hint paraller 알림 으로 병행 하지 않 았 지만 실제 실행 계획 을 보면 병행 을 했 습 니 다. 이 두 표 에 기본 병행 도 를 설정 한 것 같 습 니 다.일반적으로 데이터 창고 에서 이렇게 할 수 있 지만 이 친구 에 게 물 어 보 았 다. 그들의 데이터 베이스 시스템 은 OLTP 와 OLAP 혼합 시스템 이기 때문에 표 에 높 은 병행 도 를 설정 하 는 것 을 권장 하지 않 는 다. 그러면 CBO 는 병행 + 전체 표 스 캔 을 선택 하 는 경향 이 더욱 강 할 것 이다.
 <2 > ID = 13 의 술어 정 보 는 "(SYS OP BLOOM FILTER: BF 0000," A1 "," SERV ID "," A1 "," AGREEMENT ID "," A1 "," ATTR ID ")" 이 있 습 니 다. 10g R2 이후 CBO 유 틸 리 티 알고리즘 은 부 릉 필터 링 알고리즘 을 추 가 했 습 니 다. 보통 두 표 에서 HASH JOIN + 를 병행 할 때 HASH JOIN 의 피 구동 표 에 나타 나 지만 제 가 SQL 을 최적화 한 경험 을 보면이 새로운 기능 은 BUG 가 많 습 니 다. 특히 드라이버 의 데이터 양 이 매우 많 을 때 이 알고리즘 을 사용 하 는 것 이 더 큰 영향 을 미 칠 수 있 으 므 로 데이터 시스템 에서 이 매개 변 수 를 disable 로 해결 하 는 것 을 권장 합 니 다.
<3>  이 SQL 이 최종 적 으로 돌아 온 결 과 는 563 줄 에 불과 하 다 는 것 을 알 수 있 습 니 다. 이 를 통 해 Nested loop 내장 순환 을 가 는 것 이 HASH 가 있 는 것 보다 효율 적 일 것 으로 추 정 됩 니 다.
  
다음은 다음 SQL 을 통 해 제 판단 을 입증 하 겠 습 니 다.
A2 ------USER_INFO_OPLOG_MASTER2  이 표 의 총 데 이 터 량 은 67 만 개 이다.
A1-------SERV_ATTR            이 표 의 총 데 이 터 량 은 2 억 여 개 이다.
SQL 실행:
select count(*) from COMM.USER_INFO_OPLOG_MASTER2 where MEMOP_DATE is null and TABLE_NAME='SERV_ATTR';

결 과 는:   
COUNT(*) ----------      53677
A2 이 시 계 는 걸 러 낸 후 5 만 여 개 만 되 돌려 줍 니 다.
A1 표 의 색인 정 보 를 살 펴 보 겠 습 니 다.
****************************************************************************************
INDEX INFO
****************************************************************************************

TABLE           TABLE                               Index                                    COLUMN                     Col
OWNER           NAME                                Name                           Unique    NAME                       Pos DESC
--------------- ----------------------------------- ------------------------------ --------- ------------------------- ---- ----
COMM            SERV_ATTR                           IDX_SERV_ATTR_AGREEMENT_ID     NONUNIQUE AGREEMENT_ID                 1 ASC
                                                    IDX_SERV_ATTR_ATTR_ID          NONUNIQUE ATTR_ID                      1 ASC
                                                    IDX_SERV_ATTR_INTERNET         NONUNIQUE ATTR_VAL                     1 ASC
                                                                                             ATTR_ID                      2 ASC
                                                    IDX_SERV_ATTR_SERV_ID          NONUNIQUE SERV_ID                      1 ASC
                                                    IDX_SERV_ATTR_VAL8             NONUNIQUE ATTR_VAL                     1 ASC
                                                    PK_SERV_ATTR                   UNIQUE    SERV_ID                      1 ASC
                                                                                             AGREEMENT_ID                 2 ASC
                                                                                             ATTR_ID                      3 ASC


A1 표 에 연합 키 가 세 워 져 있 습 니 다: SERVID   AGREEMENT_ID    ATTR_ID  이 세 열 을 보면 SQL 이라는 세 열 이 바로 A1 과 A2 의 연결 열 입 니 다. 그러면 잘 되 겠 습 니 다. 저 는 A2 에 게 순환 하 는 구동 표를 만 들 라 고 했 습 니 다. A1 은 피 구동 표를 만 들 었 습 니 다. 그러면 A1 은 반드시 메 인 키 PK 를 통 해 가 야 합 니 다.SERV_ATTR 은 색인 을 유일 하 게 스 캔 한 후에 다시 표 시 를 하면 성능 이 그리 낮 지 않 을 것 이다.
다음 HINT 를 넣 고 set autotrace traceonly 로 가라 고 했 어 요. 실행 계획 과 논리 읽 기:
/*+ use_nl(A1,A2)  index(A1,PK_SERV_ATTR) leading(A2)  */
Elapsed: 00:00:05.45

Execution Plan
----------------------------------------------------------
Plan hash value: 4263321111

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                        | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                             |   142K|    16M|       |   286K  (1)| 00:57:13 |
|   1 |  SORT ORDER BY                 |                             |   142K|    16M|    19M|   286K  (1)| 00:57:13 |
|   2 |   NESTED LOOPS                 |                             |   142K|    16M|       |   282K  (1)| 00:56:26 |
|   3 |    NESTED LOOPS                |                             |   142K|    16M|       |   282K  (1)| 00:56:26 |
|   4 |     TABLE ACCESS BY INDEX ROWID| USER_INFO_OPLOG_MASTER2     |   140K|    10M|       |  1489   (1)| 00:00:18 |
|*  5 |      INDEX RANGE SCAN          | IDX_INFO_OPLOG_M2COMB_11502 |  9438 |       |       |    49   (0)| 00:00:01 |
|*  6 |     INDEX UNIQUE SCAN          | PK_SERV_ATTR                |     1 |       |       |     2   (0)| 00:00:01 |
|   7 |    TABLE ACCESS BY INDEX ROWID | SERV_ATTR                   |     1 |    43 |       |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("A2"."TABLE_NAME"='SERV_ATTR' AND "A2"."MEMOP_DATE" IS NULL)
   6 - access("A1"."SERV_ID"="A2"."TABLE_COLUMN_1" AND "A1"."AGREEMENT_ID"="A2"."TABLE_COLUMN_2" AND
              "A1"."ATTR_ID"="A2"."TABLE_COLUMN_3")

Note
-----
   - dynamic sampling used for this statement (level=6)


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
      60044  consistent gets
       5440  physical reads
       8824  redo size
      19160  bytes sent via SQL*Net to client
        762  bytes received via SQL*Net from client
         24  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        345  rows processed

결국 5 초 만 에 달 려 논리 독 서 는 종전 103 만 명 에서 6 만 명 으로 줄 었 다.

좋은 웹페이지 즐겨찾기