운영중인 DB가 느려진 것 같아서 인덱스 리빌드를 결정했다.

대상 선정을 위한 쿼리를 만들어 보았다.

SELECT
    PSUI.schemaname
    , PSUI.relname AS table_name
    , PSUI.indexrelname AS index_name
    , PSUI.idx_scan /* 인덱스가 사용된 횟수 */
    , PSUI.idx_tup_read /* 인덱스 튜플 수 */
    , PSUI.idx_tup_fetch /* 인덱스에서 실제 검색된 튜플 수 */
    , pg_size_pretty(pg_relation_size(PSAI.indexrelid)) AS index_size /* 인덱스의 크기 */
    , 'REINDEX INDEX CONCURRENTLY ' || PSUI.schemaname || '.' || PSUI.indexrelname || ';'
FROM pg_stat_user_indexes PSUI
    LEFT OUTER JOIN pg_stat_all_indexes PSAI
        ON PSAI.relname = PSUI.relname
        AND PSAI.indexrelname = PSUI.indexrelname
ORDER BY PSUI.idx_tup_read DESC, PSUI.idx_scan DESC, pg_relation_size(PSAI.indexrelid) DESC
;
------------------------------------------------------------------------------------------------------------------------
-- 거의 사용되니 않는 인덱스 -> 삭제하는 게 나을 수 있겠다
SELECT
    PSUI.schemaname
    , PSUI.relname AS table_name
    , PSUI.indexrelname AS index_name
    , PSUI.idx_scan /* 인덱스가 사용된 횟수 */
    , PSUI.idx_tup_read /* 인덱스 튜플 수 */
    , PSUI.idx_tup_fetch /* 인덱스에서 실제 검색된 튜플 수 */
    , pg_size_pretty(pg_relation_size(PSAI.indexrelid)) AS index_size /* 인덱스의 크기 */
    , 'REINDEX INDEX CONCURRENTLY ' || PSUI.schemaname || '.' || PSUI.indexrelname || ';'
FROM pg_stat_user_indexes PSUI
    LEFT OUTER JOIN pg_stat_all_indexes PSAI
        ON PSAI.relname = PSUI.relname
        AND PSAI.indexrelname = PSUI.indexrelname
WHERE PSUI.idx_scan < 100
ORDER BY PSUI.idx_scan DESC
;
------------------------------------------------------------------------------------------------------------------------
-- 크기가 너무 큰 인덱스
SELECT
    PSUI.schemaname
    , PSUI.relname AS table_name
    , PSUI.indexrelname AS index_name
    , PSUI.idx_scan /* 인덱스가 사용된 횟수 */
    , PSUI.idx_tup_read /* 인덱스 튜플 수 */
    , PSUI.idx_tup_fetch /* 인덱스에서 실제 검색된 튜플 수 */
    , pg_size_pretty(pg_relation_size(PSAI.indexrelid)) AS index_size /* 인덱스의 크기 */
    , 'REINDEX INDEX CONCURRENTLY ' || PSUI.schemaname || '.' || PSUI.indexrelname || ';'
FROM pg_stat_user_indexes PSUI
    LEFT OUTER JOIN pg_stat_all_indexes PSAI
        ON PSAI.relname = PSUI.relname
        AND PSAI.indexrelname = PSUI.indexrelname
ORDER BY pg_relation_size(PSAI.indexrelid) DESC
LIMIT 50
;
------------------------------------------------------------------------------------------------------------------------
-- 테이블 싸이즈에 비해 크기가 너무 큰 인덱스
SELECT
    PSUI.schemaname
    , PSUI.relname AS table_name
    , PSUI.indexrelname AS index_name
    , PSUI.idx_scan /* 인덱스가 사용된 횟수 */
    , PSUI.idx_tup_read /* 인덱스 튜플 수 */
    , PSUI.idx_tup_fetch /* 인덱스에서 실제 검색된 튜플 수 */
    , pg_size_pretty(pg_relation_size(PSAI.indexrelid)) AS index_size /* 인덱스의 크기 */
    , pg_size_pretty(pg_relation_size(T.oid)) AS table_size /* 테이블의 크기 */
    , ROUND(pg_relation_size(PSAI.indexrelid)::numeric / pg_relation_size(T.oid) * 100, 2) AS INDEX_RATIO
    , 'REINDEX INDEX CONCURRENTLY ' || PSUI.schemaname || '.' || PSUI.indexrelname || ';'
FROM pg_stat_user_indexes PSUI
    INNER JOIN pg_class T
        ON PSUI.relname = T.relname
    LEFT OUTER JOIN pg_stat_all_indexes PSAI
        ON PSAI.relname = PSUI.relname
        AND PSAI.indexrelname = PSUI.indexrelname
WHERE pg_relation_size(T.oid) > 0
AND pg_relation_size(PSAI.indexrelid) > 0
AND PSUI.idx_scan > 0
AND ROUND(pg_relation_size(PSAI.indexrelid)::numeric / pg_relation_size(T.oid) * 100, 2) > 100
ORDER BY INDEX_RATIO DESC
LIMIT 50
;
------------------------------------------------------------------------------------------------------------------------
-- 오래된 인덱스
SELECT
    PSUI.schemaname
    , PSUI.relname AS table_name
    , PSUI.indexrelname AS index_name
    , PSUI.idx_scan /* 인덱스가 사용된 횟수 */
    , PSUI.idx_tup_read /* 인덱스 튜플 수 */
    , PSUI.idx_tup_fetch /* 인덱스에서 실제 검색된 튜플 수 */
    , pg_size_pretty(pg_relation_size(PSAI.indexrelid)) AS index_size /* 인덱스의 크기 */
    , pg_stat_get_last_vacuum_time(PSAI.indexrelid) AS last_vacumm
    , 'REINDEX INDEX CONCURRENTLY ' || PSUI.schemaname || '.' || PSUI.indexrelname || ';'
FROM pg_stat_user_indexes PSUI
    LEFT OUTER JOIN pg_stat_all_indexes PSAI
        ON PSAI.relname = PSUI.relname
        AND PSAI.indexrelname = PSUI.indexrelname
WHERE PSUI.idx_scan = 0
OR PSAI.idx_scan = 0
ORDER BY last_vacumm ASC NULLS FIRST
;
728x90
반응형

2025년 SQLD 자격증 시험 일정과 준비 방법

SQLD (SQL Developer) 자격증은 데이터베이스 개발 및 관리에 필요한 SQL과 데이터베이스 관련 기술을 평가하는 자격증으로, IT 분야에서 데이터베이스 관련 업무를 담당하는 데 중요한 역할을 합니다. 2025년 SQLD 자격증 시험 일정과 함께, 효과적인 준비 방법에 대해 안내드리겠습니다.

2025년 SQLD 자격증 시험 일정

SQLD 자격증은 주기적으로 실시되며, 2025년 시험 일정은 다음과 같습니다:

회차 원서 접수 기간 수험표 발급 기간 시험일 사전 점수 공개 및 재검토 접수 기간 합격(예정)자 발표
제56회 2.3 ~ 2.7 2.21 3.8 (토) 3.28 ~ 4.1 4.4
제57회 4.28 ~ 5.2 5.16 5.31 (토) 6.20 ~ 6.24 6.27
제58회 7.21 ~ 7.25 8.8 8.23 (토) 9.12 ~ 9.16 9.19
제59회 10.13 ~ 10.17 10.31 11.16 (일) 12.5 ~ 12.9 12.12
  • 시험 일정은 대체로 매 분기마다 실시되며, 응시 등록은 해당 접수 기간 내에만 가능합니다.
  • 시험 방식은 객관식으로 진행되며, 온라인 또는 오프라인 시험을 선택할 수 있습니다.

SQLD 자격증 준비 방법

SQLD 자격증 시험은 데이터베이스와 SQL에 대한 기초적인 지식과 실무 경험을 평가합니다. 시험 준비를 위해서는 이론적인 학습과 실습을 병행하는 것이 중요합니다. 아래는 각 항목별로 준비 방법을 제시합니다.

(1) SQLD 시험 준비 개요

SQLD 시험은 데이터베이스의 기본적인 이해, SQL 사용법, 관계형 데이터베이스 설계, 성능 최적화 등 다양한 영역을 다룹니다. 시험 준비는 기본 이론과 실제 SQL 활용 능력을 키우는 데 집중해야 합니다.

(2) 주요 시험 과목

  • SQL 기본 문법: SELECT, INSERT, UPDATE, DELETE와 같은 기본적인 SQL 명령어에 대한 이해.
  • 데이터베이스 설계: ERD(Entity-Relationship Diagram) 설계, 정규화(Normalization)와 역정규화(Denormalization), 데이터 모델링.
  • SQL 성능 최적화: 인덱스, 조인, 서브쿼리 등의 성능 최적화 기법.
  • 트랜잭션 관리: ACID 속성, 트랜잭션 처리 및 관리.
  • 데이터베이스 관리 시스템(DBMS): DBMS의 기본 개념, 종류, 사용법.

(3) 준비 방법

  1. 기본적인 SQL 문법 학습

    • SQL의 기본적인 문법을 철저히 이해하고 연습해야 합니다. 실습을 통해 각 SQL 명령어를 활용할 수 있는 능력을 기르는 것이 중요합니다. SELECT 문을 이용해 데이터 조회, JOIN을 이용한 다중 테이블 연산 등을 충분히 연습하세요.
  2. 관계형 데이터베이스 이해

    • ERD 설계: 데이터베이스를 설계할 때 중요한 엔터티, 속성, 관계를 이해해야 합니다. 기본적인 정규화와 관계형 모델링을 학습하세요.
    • 정규화: 1NF, 2NF, 3NF에 대해 이해하고 실제로 이를 적용하는 연습을 해보세요.
  3. 실습을 통한 SQL 활용 능력 강화

    • SQL을 이론만으로 학습하지 말고, 실제로 MySQL, PostgreSQL 또는 Oracle 등 DBMS에서 SQL을 실행하며 실습을 진행하세요. 다양한 데이터베이스와 상호작용하면서 문제 해결 능력을 키울 수 있습니다.
  4. 성능 최적화 학습

    • SQL 쿼리의 성능을 최적화하는 방법을 공부하세요. 인덱스의 사용, 서브쿼리 최적화, 조인 방식에 따른 성능 차이 등을 이해하고, 실제 환경에서 이를 적용하는 방법을 학습하세요.
  5. 이론과 실습 병행

    • 이론 공부와 실습을 병행하면서 문제 해결 능력을 키워야 합니다. SQLD 시험에서는 이론적인 부분뿐만 아니라 실무에서 겪을 수 있는 다양한 시나리오를 다루기 때문에, 기본 문제 풀이와 함께 실전 연습을 충분히 해야 합니다.

공부 방법과 팁

  1. 공식 교재와 참고서 활용

    • SQLD 자격증을 준비할 때는 공식 교재를 활용하는 것이 좋습니다. 교재에는 시험에 나오는 기본적인 내용들이 포함되어 있으며, 실제 기출 문제를 통해 시험의 스타일을 익힐 수 있습니다.
    • SQLD 관련 서적이나 온라인 강의도 활용하면 도움이 됩니다.
  2. 문제 풀이 및 모의 시험

    • 기출 문제나 모의 시험을 풀어보세요. 실제 시험에 나오는 문제 유형을 파악하고, 시간 관리 능력을 키울 수 있습니다.
    • SQL 문제는 실습을 통해 연습하는 것이 중요하므로, DBMS에 접속하여 쿼리 문제를 풀어보며 실력을 점검하세요.
  3. 온라인 커뮤니티와 포럼 활용

    • SQLD 자격증 준비를 하면서 온라인 커뮤니티나 포럼을 활용하여 다른 사람들과 정보 교류를 하는 것도 유익합니다. 실무에서 겪은 다양한 SQL 관련 문제를 해결하고 서로 질문하고 답변하는 과정이 큰 도움이 됩니다.
  4. SQL 실습 환경 구축

    • 시험 준비를 할 때는 반드시 DBMS 환경을 구축하여 실습해보세요. MySQL, PostgreSQL, Oracle 등 다양한 DBMS에서 SQL을 실행해보며 각 시스템의 차이점을 이해하고 SQL 실력을 높일 수 있습니다.

결론

SQLD 자격증은 데이터베이스에 대한 기본적인 이해와 SQL 활용 능력을 증명할 수 있는 중요한 자격증입니다. 2025년 SQLD 시험 일정에 맞춰 체계적으로 준비하면 좋은 결과를 얻을 수 있을 것입니다. 기본적인 이론을 탄탄히 하고 실습을 충분히 하며, 문제 해결 능력을 키워 시험에 임하세요. 좋은 결과가 있기를 바랍니다!

728x90
반응형

특정 기간 중, CPU 사용율이 높은 쿼리를 조회한다.
CPU 점유율이 높은 쿼리를 찾아서 튜닝하기 위해서 사용한다. 기본적으로 oracle에서 제공하는 view를 활용한다.

사용 테이블

  • DBA_HIST_SQLSTAT : SQL Historical Statixtics Information
    DB에서 실행된 SQL에 대한 성능 통계치 view
  • DBA_HIST_SNAPSHOT : SnapShot Information
    워크로드 저장소의 스냅샷에 대한 정보 view
  • DBA_HIST_SQLTEXT : SQL Text
    워크로드 저장소에 캡쳐된 공유 SQL 커서에 속한 SQL 문의 텍스트 표시.
    이 view는 주로 V$SQL view와 함께 사용됨.

최종 쿼리

  WITH REF_DATE AS (
      /* 대상 기간 지정 */
      SELECT
          TO_DATE('20220401' || ' 000000', 'YYYYMMDD HH24MISS') AS BGN_DE
          , TO_DATE('20230420' || ' 235959', 'YYYYMMDD HH24MISS') AS END_DE
      FROM DUAL
  )
  SELECT
      X.SQL_ID
      , X.CPU_TIME
      , X.EXECUTIONS_DELTA
      , X.CPU_TIME_PER_EXECUTIONS
      , DBMS_LOB.SUBSTR(SUBSTR(D.SQL_TEXT, 1, 200)) AS SQL_TEXT
      , D.SQL_TEXT AS SQL_FULLTEXT
  FROM (
          SELECT
              SQL.DBID
              , SQL.SQL_ID
              , SUM(SQL.CPU_TIME_DELTA) / 1000000 AS CPU_TIME
              , SUM(SQL.EXECUTIONS_DELTA) AS EXECUTIONS_DELTA
              , ROUND((SUM(SQL.CPU_TIME_DELTA) / 1000000) / DECODE(SUM(SQL.EXECUTIONS_DELTA), 0, 1, SUM(SQL.EXECUTIONS_DELTA)) / DECODE(SQL.PX_SERVERS_EXECS_DELTA, 0, 1, SQL.PX_SERVERS_EXECS_DELTA)) AS CPU_TIME_PER_EXECUTIONS
          FROM DBA_HIST_SQLSTAT SQL
              , (
                  SELECT
                      MIN(SNAP_ID) AS START_SNAP_ID
                      , MAX(SNAP_ID) AS END_SNAP_ID
                      , MIN(BEGIN_INTERVAL_TIME) AS BEGIN_INTERVAL_TIME
                      , MAX(END_INTERVAL_TIME) AS END_INTERVAL_TIME
                  FROM DBA_HIST_SNAPSHOT, REF_DATE
                  WHERE BEGIN_INTERVAL_TIME BETWEEN REF_DATE.BGN_DE
                                              AND REF_DATE.END_DE
              ) SNAP
          WHERE SQL.SNAP_ID BETWEEN SNAP.START_SNAP_ID AND SNAP.END_SNAP_ID
          GROUP BY SQL.DBID, SQL.SQL_ID, SQL.PX_SERVERS_EXECS_DELTA
          HAVING SUM(SQL.EXECUTIONS_DELTA) >= 0
          ORDER BY CPU_TIME_PER_EXECUTIONS DESC
  ) X
  INNER JOIN DBA_HIST_SQLTEXT D
      ON D.SQL_ID = X.SQL_ID
      AND D.DBID = X.DBID
  WHERE ROWNUM <= 40
  ;

분리

  SELECT
      SQL.DBID
      , SUM(SQL.CPU_TIME_DELTA) / 1000000 AS CPU_TIME
      , SUM(SQL.EXECUTIONS_DELTA) AS EXECUTIONS_DELTA
      , ROUND((SUM(SQL.CPU_TIME_DELTA) / 1000000) / DECODE(SUM(SQL.EXECUTIONS_DELTA), 0, 1, SUM(SQL.EXECUTIONS_DELTA)) / DECODE(SQL.PX_SERVERS_EXECS_DELTA, 0, 1, SQL.PX_SERVERS_EXECS_DELTA)) AS CPU_TIME_PER_EXECUTIONS
  FROM DBA_HIST_SQLSTAT SQL
      , (
          SELECT
              MIN(SNAP_ID) AS START_SNAP_ID
              , MAX(SNAP_ID) AS END_SNAP_ID
              , MIN(BEGIN_INTERVAL_TIME) AS BEGIN_INTERVAL_TIME
              , MAX(END_INTERVAL_TIME) AS END_INTERVAL_TIME
          FROM DBA_HIST_SNAPSHOT
          WHERE BEGIN_INTERVAL_TIME BETWEEN TO_DATE('20230401' || ' 000000', 'YYYYMMDD HH24MISS')
                                      AND TO_DATE('20230419' || ' 235959', 'YYYYMMDD HH24MISS')
      ) SNAP
  WHERE SQL.SNAP_ID BETWEEN SNAP.START_SNAP_ID AND SNAP.END_SNAP_ID
  GROUP BY SQL.DBID, SQL.SQL_ID, SQL.PX_SERVERS_EXECS_DELTA
  HAVING SUM(SQL.EXECUTIONS_DELTA) >= 0
  ORDER BY CPU_TIME_PER_EXECUTIONS
  ;
  SELECT
      MIN(SNAP_ID) AS START_SNAP_ID
      , MAX(SNAP_ID) AS END_SNAP_ID
      , MIN(BEGIN_INTERVAL_TIME) AS BEGIN_INTERVAL_TIME
      , MAX(END_INTERVAL_TIME) AS END_INTERVAL_TIME
  FROM DBA_HIST_SNAPSHOT
  WHERE BEGIN_INTERVAL_TIME BETWEEN TO_DATE('20230401' || ' 000000', 'YYYYMMDD HH24MISS')
                              AND TO_DATE('20230419' || ' 235959', 'YYYYMMDD HH24MISS')
  ;
728x90
반응형

SELECT 시에는 꼭 필요한 column 만 불러오기

많은 필드를 불러 올수록 DB는 더 많은 로드를 부담하게 되기 때문에 꼭 필요한 열만 물러오도록 한다.

  -- WORST
  SELECT * FROM TABLE;
  -- BETTER
  SELECT COLUMN1, COLUMN2, COLUMN4, COLUMN8 FROM TABLE;

WHERE절에서 연산을 걸지 않는다.

연산이 들어가게 되면 TABLE FULL SCAN을 하면서 모든 값을 탐색, 계산 한 뒤 조건 충족 여부를 판단하기 때문에 좋지 않다.

  -- WORST
  SELECT COLUMN1, COLUMN4
  FROM TABLE
  WHERE FLOOR(COLUMN4) = 2;
  -- BETTER
  SELECT COLUMN1, COLUMN4
  FROM TABLE
  WHERE COLUMN4 BETWEEN 4 AND 5;

LIKE 조회시 와일드카드 % 는 가급적 뒤에만 붙이자

COLUMN6 LIKE %DF 는 TABLE FULL SCAN을 유발한다.
COLUMN5 IN ('ASDF', 'ERDF'), COLUMN5 = 'ASDF' OR COLUMN5 = 'ERDF' 같은 형태가 낫다.

SELECT DISTINCT, UNION ALL 과 같이 중복을 제거하는 연산은 자제한다

중복을 제거하는 연산은 시간이 많이 걸린다. 불가피하게 사용해야 할 경우 EXISTS, GROUP BY를 활용하는게 낫다.
DISTINCT는 원하는 컬럼에 대해서 중복을 제거하는 것이 아니라 SELECT 해온 모든 ROW에서 중복을 제거하므로 속도가 느려진다.

같은 내용의 조건이라면 GROUP BY 연산의 HAVING 보다는 WHERE 절을 사용하는 것이 좋다

쿼리 실행 순서에서 WHERE 절이 HAVING 절 보다 먼저 실행된다. 따라서 WHERE 절로 미리 데이터를 작게 만들면 GROUP BY 절에서 다뤄야 하는 데이터 크기가 작기 때문에 효율적인 연산이 가능하다.

VIEW VS MVIEW (MATERIALIZED VIEW)

뷰는 질의 할때마다 해당 쿼리를 재 실행하는 것과 같음. 속도가 느림. 다만 데이터는 LIVE 함.
MVIEW는 세팅을 어떻게 하느냐에 따라 질의 할 쿼리를 재사용하여 가져옴. 스냅샷 처럼 이전에 만들어 놓은 엠뷰 테이블에서 데이터를 가져옴.
비용이 많이 들어가고 데이터가 고정적인 경우 엠뷰를 만들어서 사용하는게 좋음. 인덱스도 생성 가능.
리프레시 타임이 많이 드는 경우 데이터가 LIVE하지 않은 문제가 있음.

CHAR VS VARCHAR

4byte 이하는 CHAR, 그 이상은 VARCHAR가 나음.

  • CHAR : 고정 길이 문자열
  • VARCHAR : 가변 길이 문자열

BLOB VS TEXT

많은 양의 데이터 저장, 디폴트 값 지정 안됨, 문자열 뒷부분 공백 제거 안되는 공통점이 있음.
차이점으로 BLOB은 대소문자를 구분, TEXT는 구분 안함.

PRIMARY KEY, UNIQUE KEY

PK와 Unique Key는 자동으로 인덱스가 생성됨.

쿼리 실행 순서

SUB-QUERY -> MAIN-QUERY

INNER JOIN시 테이블 배치 순서

3개 이상의 테이블을 INNER JOIN을 할 때는 크기가 가장 큰 테이블을 FROM 절에 배치하고 INNER JOIN 절에 남은 테이블을 작은 순서대로 배치하는 것이 좋다.
테이블 한두개차이는 상관 없지만 많은 테이블을 JOIN 할 경우 JOIN의 경우의 수가 생기고 OPTIMIZER가 PLANNING을 하면서 비용이 증가된다.

실행 계획 type이 index라면 한 번 더 살펴보기

EXPLAIN으로 실행 계획을 확인 했을 때 type이 index인 부분이 있다. where 절 조건문에서 사용하는 테이블의 컬럼에 인덱스가 제대로 걸려있지 않기 때문에 TABLE FULL SCAN을 한다.
해당 테이블에 index를 걸고 다시 실행 계획을 INDEX RANGE SCAN으로 변경되었고 실제 실행 속도가 1/4로 줄었다. 아래는 type의 종류로 성능이 낮은 것 부터 높은 순으로 정렬했다.

  • ALL : 테이블을 처음부터 끝까지 탐색하여 데이터를 찾음 (TABLE FULL SCAN)
  • INDEX : 인덱스를 처음부터 끝까지 탐색하여 데이터를 찾는 방식 (INDEX FULL SCAN)
  • RANGE : 특정 범위 내에서 인덱스를 사용하여 원하는 데이터를 추출, 데이터가 방대하지 않다면 준수함. (INDEX RANGE SCAN)
  • REF : 조인 할 때 Primary Key 혹은 Unique Key 가 아닌 Key로 매칭 한 경우
  • EQ_REF : 조인 할 때 Primary Key로 매칭
728x90
반응형
-- 락 걸린 테이블 확인
SELECT
    DO.OBJECT_NAME
  , DO.OWNER
  , DO.OBJECT_TYPE
  , DO.OWNER
  , VO.XIDUSN
  , VO.SESSION_ID
  , VO.LOCKED_MODE
FROM
    V$LOCKED_OBJECT VO
  , DBA_OBJECTS DO
WHERE VO.OBJECT_ID = DO.OBJECT_ID
;


-- 해당 테이블에 락이 걸렸는지 확인
SELECT
  A.SID
  , A.SERIAL#
  , B.TYPE
  , C.OBJECT_NAME
FROM
    V$SESSION A
  , V$LOCK B
  , DBA_OBJECTS C
WHERE A.SID = B.SID
  AND B.ID1 = C.OBJECT_ID
  AND B.TYPE='TM'
  AND C.OBJECT_NAME IN (${위 쿼리에서 가져온 OBJECT_NAME});


-- 락 발생 사용자, SQL, OBJECT 조회
SELECT
  DISTINCT X.SESSION_ID
  , A.SERIAL#
  , D.OBJECT_NAME
  , A.MACHINE
  , A.TERMINAL
  , A.PROGRAM
  , B.ADDRESS
  , B.PIECE
  , B.SQL_TEXT
FROM
    V$LOCKED_OBJECT X
  , V$SESSION A
  , V$SQLTEXT B
  , DBA_OBJECTS D
WHERE X.SESSION_ID = A.SID
  AND X.OBJECT_ID = D.OBJECT_ID
  AND A.SQL_ADDRESS = B.ADDRESS 
ORDER BY B.ADDRESS, B.PIECE;


-- 현재 접속자의 SQL 확인 
SELECT
    DISTINCT A.SID
  , A.SERIAL#
  , A.MACHINE
  , A.TERMINAL
  , A.PROGRAM
  , B.ADDRESS
  , B.PIECE
  , B.SQL_TEXT
FROM
    V$SESSION A
  , V$SQLTEXT B
WHERE A.SQL_ADDRESS = B.ADDRESS
ORDER BY A.SID, A.SERIAL#, B.ADDRESS, B.PIECE;


-- 락 세션 죽이기위한 sid 와 serial
SELECT
    A.SID
  , A.SERIAL#
  , A.SID || ', ' || A.SERIAL#
FROM
    V$SESSION A
  , V$LOCK B
  , DBA_OBJECTS C
WHERE A.SID = B.SID
  AND B.ID1 = C.OBJECT_ID
  AND B.TYPE = 'TM'
-- AND C.OBJECT_NAME IN ('${락 걸린 테이블 명}');


-- 해당 세선 kill
SELECT
    DISTINCT X.SESSION_ID
  , A.SERIAL#
  , D.OBJECT_NAME
  , A.MACHINE
  , A.TERMINAL
  , A.PROGRAM
  , A.LOGON_TIME
  , 'ALTER SYSTEM KILL SESSION '''||A.SID||', '||A.SERIAL#||''';'
FROM
    GV$LOCKED_OBJECT X
  , GV$SESSION A
  , DBA_OBJECTS D
WHERE X.SESSION_ID = A.SID
  AND X.OBJECT_ID = D.OBJECT_ID
ORDER BY LOGON_TIME
;


-- 최근 실행된 쿼리 찾기
SELECT 
    SQL_FULLTEXT
  , SQL_ID
  , PARSING_SCHEMA_NAME
  , SERVICE
  , MODULE
  , FIRST_LOAD_TIME
  , LAST_LOAD_TIME
FROM V$SQL
WHERE 1 = 1
  AND PARSING_SCHEMA_NAME = '${스키마 명}'
  AND SERVICE = '${서비스 명}'
ORDER BY LAST_LOAD_TIME DESC
;


-- 최근 실행된 쿼리에 바인팅 변수 찾기
SELECT
    NAME
  , POSITION
  , DATATYPE_STRING
  , VALUE_STRING 
FROM V$SQL_BIND_CAPTURE
WHERE 1=1
  AND SQL_ID = '${위 쿼리에서 가져온 SQL_ID}'
;

SELECT * FROM V$SQL;

SELECT 
  last_active_time
  ,parsing_schema_name
  ,sql_text 
FROM v$sqlarea
WHERE 
  parsing_schema_name <> 'SYS'
  AND parsing_schema_name <> 'SYSMAN'
  AND parsing_schema_name <> 'DBSNMP'
  AND parsing_schema_name <> 'MDSYS'
  AND parsing_schema_name <> 'EXFSYS'
ORDER BY 
  last_active_time DESC;

 

 

안타깝게도 어떤 쿼리가 락을 걸었는지는 알기 쉽지 않다.

특히나 Oracle DB S/W update를 주기적으로 하지 않는다면 유지보수가 쉽지 않다.

728x90
반응형

인덱스 리빌드

DB의 쿼리 수행 속도 저하의 문제 중 하나는 쿼리 튜닝이 문제일 수도 있지만, 인덱스의 밸런스가 깨졌을 경우의 가능성도 있다.
인덱스 밸런스가 깨졌다는게 무슨 의미냐 하면,
DB는 ArrayList와 트리를 합쳐 놓은 구조와 비슷한 B+트리 구조인데, 트리 아래의 데이터들이 무작위로 수정되거나 삭제 되었을 경우 트리 구조가 불균형을 이루게 된다.

이런 경우 인덱스를 재구성 해주면 쿼리 수행 속도를 향상 시킬 수 있다.
(물론 튜닝이 잘 된 쿼리를 짜는게 중요하다.)

오라클의 인덱스 재설정 쿼리는 ALTER INDEX 인덱스명 REBUILD;이고,
인덱스 명을 조회하는 쿼리는 SELECT INDEX_NAME FROM USER_INDEXED;이다.
그리고 인덱스의 데이터 타입이 LOB이라면 인덱스 리빌드는 불가능 하다.

따라서 이 두 쿼리를 조합하고, 조건을 추가하면 리빌드 하는 쿼리는 다음과 같다.

SELECT 'ALTER INDEX ' || INDEX_NAME || ' REBUILD ;'
FROM USER_INDEXES
WHERE INDEX_TYPE != 'LOB'
;

경험상 CUBRID나 TIBERO 도 동일했던 것 같다.

참고 : https://docs.oracle.com/database/121/SPATL/alter-index-rebuild.htm#SPATL1017

 
 
728x90
반응형

DB : Database

데이터의 집합, 검색 수정 삭제 추가등 관리.

파일 시스템의 문제점 해결

  • 데이터의 종속
  • 데이터의 중복
    • 일관성 - 동일성을 유지하기 위해 데이터 중복을 피하기 위해
    • 보안성 - 동일한 수준에서 보안 유지
    • 경제성 - 저장되는 공간에 대한 비용 절감
    • 무결성 - 데이터의 정확성을 유지

DB의 정의

  • 통합된 데이터 (Integrated Data)
    • 원칙적으로 데이터 중복되어 있지 않게함
  • 저장된 데이터 (Stored Data)
    • 기억장치에 저장된 데이터
  • 운영 데이터 (Operational Data)
    • 존재 목적이 명확하고 유용성을 지니고 있음
  • 공용 데이터 (Shared Data)
    • 여러 사용자들이 서로 다른 목적으로 공유가 가능한.

DB의 특징

실시간 접근성, 지속적인 변화, 동시 공유, 내용에 대한 참조

데이터베이스 관리시스템 (DBMS : DataBase Management System)

효율적으로 관리하고 검색할 수 있는 환경을 제공, 체계적인 활용을 가능케함.
응용프로그램과 데이터베이스의 중계

관계형 데이터베이스 관리 시스템

일반적인 DB, 작성과 이용이 편함, 응용프로그램을 변경하지 않아도 참삭이 편함.
정보들을 Table형태로 저장함.
테이블은 2차원 형태의 표처럼 row(행), column(열)로 구성.

Table ; 표

Row \ Table Column Column Column
Number 1 2 3
Eng Char A B C
Kor Char

참고

SQL? (Structured Query Language)

사용자와 관계형 데이터베이스를 연결시켜주는 표준 검색언어.
쉽게 얘기해서 데이터베이스를 다루기위해 디자인된 언어임.
프로그래밍 언어는 아니지만 Java 등 다른 프로그래밍 언어보다 더 많이 사용될 수밖에 없음.

728x90
반응형

'Database' 카테고리의 다른 글

[SQL] 데이터를 가공하기 위한 DB 함수들  (0) 2019.12.26
[SQL] 조건절 WHERE  (0) 2019.12.24
[SQL] 데이터 조회 SELECT  (0) 2019.12.23
DB 설치 없이 SQL 실습하기  (0) 2019.12.21
nodejs mysql 연동 에러  (0) 2019.12.11

+ Recent posts