본문 바로가기

자격증/SQLP

sqlp 연습문제 모음

 

Oracle에서 no_merge 힌트를 사용하지 않고도 아래 SQL문에 뷰 머징(View Merging)이 발생하지 않게 하려고 한다. 다음 중 ㉠ 안에 들어갈 키워드로 가장 적절한 것은?.  


---------------------------------- 아   래 -------------------------------------------------

 

SELECT *
FROM (SELECT ㉠ , EMP_NAME, HIRE_DATE, SAL, DEPT_NO
      FROM EMP
      WHERE DEPTNO = 30) X
WHERE HIRE_DATE BETWEEN TO_DATE('20100101','YYYYMMDD') AND TO_DATE('20101231','YYYYMMDD')

 

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

 

① TO_DATE(SYSDATE,’YYYYMMDD’)
② ROWNUM
③ EMPNO
④ ROWID

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

* 정답 및 해설 *

 

정답 : ②

뷰(View) 안에 rownum을 사용하면 뷰 머징(View Merging)을 방지하는 효과가 나타난다.


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


다음 중각 SQL 실행 결과를 가장 올바르게 설명한 것을 2개 고르시오.

① SELECT COL1, COL2 FROM TAB1 WHERE 1 = 2 ;

    → 실행 시 에러가 발생한다.

② SELECT NVL(COL1,'X') FROM TAB1 WHERE 1 = 2 ;

    → 실행 결과로 'X'를 반환한다.

③ SELECT NVL(MIN(COL1), 'X') FROM TAB1 WHERE 1 = 2;

    → 실행 결과로 'X'를 반환한다.

④ SELECT COL1, COL2 FROM TAB1 WHERE 1 = 2 ;

    → 실행 결과가 없다.(공집합)

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

* 정답 및 해설 *

 

정답 : ③ , ④



조건절에 해당하는 결과집합이 없다고 에러가 발생하지는 않는다. 그리고 공집합에 NVL 함수를 사용한다고 값이 얻을 수 있는 것은 아니다.


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


다음 중 Syntax 오류가 있는 SQL문 2개를 고르시오.

 

① SELECT 부서번호
   FROM 직원HAVING COUNT(*) > 3;


② SELECT 직원이름
   FROM 직원 JOIN 부서
   ON (직원.부서번호 = 부서.부서번호)
   WHERE 부서명 = ‘인사과’


③ SELECT 전화번호
   FROM 직원
   WHERE 전화번호 = ‘777’
   GROUP BY 전화번호


④ SELECT 직원이름
   FROM 직원 JOIN 부서
   USING (부서.부서번호)
   WHERE 부서명 = ‘인사과’


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

* 정답 및 해설 *

 

정답 : ①, ④


 ① GROUP BY 절 없이 HAVING을 사용할 수 없다.
 ④ USING 조건절을 이용한 EQUI JOIN에서도 NATURAL JOIN과 마찬가지로 JOIN 칼럼에 대해서는 ALIAS나 테이블 이름과 같은 접두사를 붙일 수 없다.
    (부서.부서번호 → 부서번호)


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


총 건수가 1,000만 건인 연도별지역별상품매출 테이블에 [출시연도 + 크기],  [색상  + 출시연도] 순으로 구성된 두 개의 B*Tree인덱스가 있었다. 다음 중 이 두 인덱스를 제거하고 아래와 같이 세 개의 비트맵(Bitmap) 인덱스를 생성했을 때, 개별 쿼리의 블록 I/O 측면에서 개선 효과가 가장 미미한 것은? 
 

---------------------------- 아 래 ----------------------------------------

create bitmap index 연도별지역별상품매출_bx1 on 연도별지역별상품매출(크기);
create bitmap index 연도별지역별상품매출_bx2 on 연도별지역별상품매출(색상);
create bitmap index 연도별지역별상품매출_bx3 on 연도별지역별상품매출(출시연도);
 
■ Distinct Value
   크기 = { NULL, SMALL, MEDIUM, BIG }
   색상 = { NULL, RED, GREEN, BLUE, BLACK, WHITE }
   출시연도 = { NULL, 2001, 2002, 2003, 2004, 2005 2006, 2007, 2008, 2009, 2010 }
 
■ 데이터 분포는 모두 균일

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

 

① select count(*) from 연도별지역별상품매출 where 색상 is null;


② select count(*) from 연도별지역별상품매출

      where (크기 = ‘SMALL’ or 크기 is null)

      and   색상 = ‘GREEN’

      and    출시연도 = ‘2010’;


③ select 색상, count(*) from 연도별지역별상품매출 group by 색상;


④ select sum(판매량), sum(판매금액)

      from 연도별지역별상품매출

      where  색상 = ‘BLUE’;


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

* 정답 및 해설 *

 

정답 : ④


1번과 3번은 기존에 Full Table Scan으로 처리됐을 것이므로 비트맵 인덱스를 생성하고 나면 블록 I/O가 크게 감소한다. 3번의 경우 만약 ‘색상is not null’ 조건을 추가하면 인덱스만 읽고 처리할 수 있지만 그렇더라도 B*Tree 인덱스는 비트맵 인덱스에 비해 블록 I/O는 더 많이 발생한다.
2번은 Bitmap Conversion이 발생하지 않는 한, 기존에 두 B*Tree 인덱스 중 어느 하나만 사용되고, 나머지 필터 조건을 처리하기 위해 테이블 랜덤 액세스가 불가피하므로 성능이 매우 안 좋았을 것이다. 반면, 비트맵 인덱스를 생성하고 나면 두 개의 비트맵 인덱스를 동시에 사용할 수 있고, 테이블을 랜덤 액세스도 생략되므로 성능 개선 효과가 클 것이다.
4번은 색상 = ‘BLUE’에 해당하는 건수만큼 대량의 테이블 액세스가 불가피하다. 비트맵 인덱스를 생성하고 나면 인덱스 스캔 단계에서 다소 블록 I/O가 감소하겠지만 테이블 랜덤 I/O는 줄지 않으므로 성능 개선 효과가 미미하게 나타난다.

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


다음 중 아래 테이블 정의와 인덱스 현황을 참고하여, 인덱스를 효율적(또는 정상적)으로 액세스할 수 없는 검색조건을 2개 고르시오.

(단, Oracle의 Index Unique Scan, Index Range Scan 또는 SQL Server의 Index Seek 이외의 액세스 방식은 모두 비효율적이라고 가정한다.)

---------------------------- 아 래 ----------------------------------------

create table 주문 (
    주문번호    int            not null
  , 주문자명    varchar(20)     null
  , 주문금액    money         null
  , 주문일자    varchar(8)      null
)
 
create unique index 주문_pk on 주문 (주문번호)
create index 주문_x01 on 주문 (주문자명)
create index 주문_x02 on 주문 (주문일자 , 주문금액)

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

 

① where 주문번호 between 1 and 10  
② where 주문자명 like '%홍길동%'
③ where 주문일자 >= '20100901'
④ where 주문일자 = 20100901



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

* 정답 및 해설 *

 

정답 : ② , ④

2번은 LIKE 검색 문자열 앞뒤에 모두 ‘%’ 기호를 붙였으므로 정상적인 Index Range Scan이 불가능하다. 4번은 내부적 형변환이 발생하므로 Index Range Scan이 불가능하다.

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


아래 테이블은 어느 회사의 사원들과 이들이 부양하는 가족에 대한 것으로 밑줄 친 칼럼은 기본키(Primary Key)를 표시한 것이다. 다음 중 ‘현재 부양하는 가족들이 없는 사원들의 이름을 구하라’는 질의에 대해 아래 SQL 문장의 ㉠, ㉡ 에 들어 갈 내용으로 가장 적절한 것은?

---------------------------- 아 래 ----------------------------------------

[테이블]

사원 (사번, 이름, 나이)

가족 (이름, 나이, 부양사번)

※ 가족 테이블의 부양사번은 사원 테이블의 사번을 참조하는 외래키(Foreign Key)이다.

[SQL 문장]

SELECT 이름

FROM 사원

WHERE ㉠ (SELECT * FROM 가족 WHERE ㉡ )

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

 

① ㉠ : EXISTS        ㉡ : 사번 = 부양사번

② ㉠ : EXISTS        ㉡ : 사번 <> 부양사번

③ ㉠ : NOT EXISTS ㉡ : 사번 = 부양사번

④ ㉠ : NOT EXISTS ㉡ : 사번 <> 부양사번


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

* 정답 및 해설 *

 

정답 : ③

‘가족들이 없는’조건 : NOT EXISTS

‘현재 부양하는 가족들’조건 : 사번 = 부양사번

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


다음 중 아래 스키마를 보고 평점이 3.0 이상인 학생들의 이름을 보여주는 SQL을 표현한 것으로 가장 적절한 것은?


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

아 래
 
<스키마>

※ 밑줄친 속성은 기본키(Primary Key)이며 ENROLL의 학번은 STUDENT의 학번을 참조하는 외래키(Foreign Key)이고, ENROLL의 강좌번호는 CLASS의 강좌번호를 참조하는 외래키이다.


STUDENT(학번, 학과, 이름)

CLASS(강좌번호, 시간, 강좌이름)

ENROLL(학번, 강좌번호, 학점)

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


 

SELECT 학번, MIN(이름)

FROM STUDENT S, ENROLL E

GROUP BY E.학번

HAVING AVG(E.학점) >= 3.0

 

SELECT S.학번, MIN(이름)

FROM STUDENT S, ENROLL E

WHERE S.학번=E.학번

HAVING AVG(E.학??글>

 

SELECT S.학번, MIN(이름)

FROM STUDENT S, ENROLL E

WHERE S.학번=E.학번

GROUP BY S.학번

HAVING AVG(E.학점) >= 3.0

 

SELECT 학번, MIN(이름)

FROM STUDENT S, ENROLL E

WHERE S.학번=E.학번

GROUP BY S.학번

HAVING AVG(E.학점) > 3.0

 

-----------------------보기 수정되었습니다-------------------------


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

* 정답 및 해설 *

 

정답 ③

GROUP BY 절 이후에 조건을 적용하는 경우는 HAVING 절이 사용된 경우이다.

그룹핑된 값에 조건을 적용하는 경우 HAVING 절을 사용한다.

JOIN 절에 ALIAS를 사용한 경우, 2개 이상의 테이블에 공통적으로 사용되고 SELECT 절에 사용되는 칼럼에는 ALIAS 접두사를 붙여야 한다.

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


다음 중 아래 SQL과 트레이스 결과를 분석하고, 보기에서 제시한 튜닝 방안 중 가장 적절한 것은?

 

------------------------------------  아                  래--------------------------------

SQL> SELECT ...
  2  FROM  (SELECT DEII_DT, NEII_VAL, NACT_VAL, NSTD_VAL
  3              , NVL(ROUND(AVG(NACT_VAL/NSTD_VAL*100) OVER(), 2), 0.00) AVG_VAL
  4              , NVL(ROUND(STDDEV(NACT_VAL/NSTD_VAL*100) OVER(), 2), 0.00) STDDEV_VAL
  5              , ROWNUM RN
  6         FROM   EII_SUMMARY
  7         WHERE  TO_CHAR(DEII_DT, 'YYYYMMDDHH24MISS') BETWEEN :B3 AND :B4
  8         ORDER BY DEII_DT) MR 
  9         LEFT OUTER JOIN EII_TARGET ET 
 10         ON   ET.DEII_DT BETWEEN TRUNC(MR.DEII_DT, 'MM') 
 11                             AND TRUNC(LAST_DAY(MR.DEII_DT)+1)-1/60/24/24
 12         AND  ET.NCODE_NO IN ( :B1, :B2 )
 13  GROUP BY FLOOR((MR.RN-1)/:B5 ), MR.AVG_VAL, MR.STDDEV_VAL
 14  ORDER BY FLOOR((MR.RN-1)/:B5 ) ;
 
call        count       cpu    elapsed     disk    query    current     rows
-------  ------  -------  --------  ------  -------  --------  -------
Parse       446        0.00        0.00          0           0           0            0 
Execute   7578        0.03        0.12        22        564           2            8
Fetch     13522     128.03     129.16        22  6676902           0      10442
-------  ------  -------  --------  ------  -------  --------  -------

total       21546     128.06     129.30        44  6677466           2      10450
 
Rows   Row Source Operation
----  ---------------------------------------------------
   2   SORT GROUP BY (cr=7340 pr=7 pw=0 time=221191 us)
 240    NESTED LOOPS OUTER (cr=7340 pr=7 pw=0 time=221460 us)
 120     VIEW  (cr=20 pr=7 pw=0 time=90776 us)
 120      FILTER  (cr=20 pr=7 pw=0 time=90410 us)
 120       WINDOW SORT (cr=20 pr=7 pw=0 time=89447 us)
 120        COUNT  (cr=20 pr=7 pw=0 time=79490 us)
 120         TABLE ACCESS (FULL) OF 'EII_SUMMARY' (TABLE) (cr=20 pr=7 pw=0 time=79250 us)
 240     VIEW  (cr=7320 pr=0 pw=0 time=74760 us)
 240      TABLE ACCESS FULL EII_TARGET (cr=7320 pr=0 pw=0 time=74414 us)
 
[인덱스 구성]
EII_SUMMARY_X01 : DEII_DT
EII_TARGET_X01 : DEII_DT

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

① 7번 라인을 아래와 같이 수정한다. WHERE  DEII_DT BETWEEN TO_DATE(:B3, 'YYYYMMDDHH24MISS') 
                       AND TO_DATE(:B4, 'YYYYMMDDHH24MISS')
② 9번 라인의 'LEFT OUTER JOIN'을 'INNER JOIN'으로 변경함으로써 EII_TARGET 테이블이 먼저 드라이빙 될 수 있게 한다. Row Source를 분석해 보면, Outer 집합에서 Inner 집합으로 조인 시도한 건수만큼 모두 성공하므로 Outer Join은 불필요하다.
③ 10~12번 라인을 위해 EII_TARGET_X01 인덱스를 [NCODE_NO + DEII_DT] 순으로 구성한다.
④ 14번 라인의 ORDER BY는 불필요하므로 제거한다.

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

* 정답 및 해설 *

 

정답 :  ③

7번 라인에 대한 Row Source를 보면, 20개 블록을 읽어서 120개 로우를 반환하므로 굳이 인덱스를 사용하도록 튜닝하지 않아도 된다.
9번 라인에 대한 Row Source만 보고 Left Outer Join이 불필요하다고 판단할 수 없다. 
10~11번 라인 조인 칼럼에 인덱스가 있는데도 옵티마이저가 이를 사용하지 않고 Full Table Scan으로 처리한 이유는, NCODE_NO 필터링을 위해 다량의 테이블 랜덤 액세스가 발생하기 때문이다. 인덱스 뒤에 NCODE_NO만 추가해도 성능이 많이 개선되겠지만, 순서까지 바꿔 [NCODE_NO + DEII_DT] 순으로 구성하는 것이 최적이다. 
14번 라인의 ORDER BY를 제거하면 결과집합의 출력순서가 달라질 수 있다. 

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