오라클 임포트시 인코딩 설정

오라클 임포트시 인코딩 설정

1. DB에서 얻어온 한글값 깨지는 현상 발생 (와스 설정은 이상없었음. JEUS7 force 적용. jsp 이상없음)

2. 설치된 오라클 인코딩이 AMERICAN 으로 되어 있었음

3. 사내 인코딩은 K016KSC5601 로 되어 있었음

4. 오라클 초기화시키고 다시 인코딩을 K016KSC5601 로 맞춤

5. 임포트 시킴

6. 정상적으로 한글 출력됨

임포트 명령어

imp system/system_sflow file=/data01/oracle/app/oracle/admin/XF2K/dpdump/ose37.dmp log=/data01/oracle/app/oracle/admin/XF2K/dpdump/ose37.log fromuser=ose36dev touser=xf ignore=y

문자셋 확인
SELECT name, value$
FROM sys.props$
WHERE name = ‘NLS_CHARACTERSET’;

SELECT name, value$
FROM sys.props$
WHERE name = ‘NLS_NCHAR_CHARACTERSET’;

언어셋 확인
SELECT name, value$
FROM sys.props$
WHERE name = ‘NLS_LANGUAGE’;
=========================================================================

SQL> select name, value$
  2  from sys.props$
  3  where name = ‘NLS_CHARACTERSET’;

NAME
——————————
VALUE$
——————————————————————————–
NLS_CHARACTERSET

SQL> SELECT name, value$
  2  from sys.props$
  3  where name = ‘NLS_LANGUAGE’;

NAME
——————————
VALUE$
——————————————————————————–
NLS_LANGUAGE
KOREAN_KOREA.UTF8

UTF8

SQL> SELECT NAME,VALUE$
  2  FROM sys.props$
  3  where name= ‘NLS_LANGUAGE’;

NAME
——————————
VALUE$
——————————————————————————–
NLS_LANGUAGE
KOREAN_KOREA.UTF8

=================================

문자셋 변경
UPDATE sys.props$
SET value$ = ‘KO16KSC5601’
WHERE name = ‘NLS_CHARACTERSET’;

UPDATE sys.props$
SET value$ = ‘KO16KSC5601’
WHERE name = ‘NLS_NCHAR_CHARACTERSET’;

언어셋 변경
UPDATE sys.props$
SET value$ = ‘AMERICAN_AMERICA.KO16KSC5601’
WHERE name = ‘NLS_LANGUAGE”;
=================================
SQL> UPDATE sys.props$
  2  set value$ =’KO16KSC5601′
  3  WHERE name = ‘NLS_CHARACTERSET’;

1 row updated.

SQL> UPDATE sys.props$
  2  set value$ = ‘KO16KSC5601’
  3  WHERE name = ‘NLS_NCHAR_CHARACTERSET’;

1 row updated.

SQL> UPDATE SYS.PROPS$
  2  SET VALUE$ = ‘AMERICAN_AMERICA.KO16KSC5601’
  3  WHERE NAME = ‘NLS_LANGUAGE’;

1 row updated.

SQL> commit;

Commit complete.

SQL>
—————————————————————-

JEUS7 JVM Option 참고

JEUS7  JVM Option 참고

0. 메뉴 : JEUS7 – WebAdmin – Servers – JVM Option

1. -Djeus.servlet.request.6CompatibleSetCharacterEncoding=true
JEUS 6는 request.setCharacterEncoding()의 적용 범위를 Body가 아니라 Query String 및 Cookie까지 확대 해석한 문제점을 가지고 있다. 그러나 Servlet 표준은 명백하게 해당 API 적용 범위를 HTTP Body로 한정하고 있다. JEUS 7에서는 이를 바로 잡았으나 만약 JEUS 6 동작을 유지해야 한다면 jeus.servlet.request.6CompatibleSetCharacterEncoding 프로퍼티를 false로 지정하기 바란다. 단, 해당 애플리케이션에 jeus-web-dd.xml 설정을 권장한다.

2. -Djeus.servlet.response.6CompatibleForcedEncoding=true
forced는 response.setCharacterEncoding(), setContentType(), setLocale()보다 우선순위가 높다. 단, JEUS 6 및 JEUS v7.0 Fix#1까지는 forced의 우선순위 적용 정책이 명확하지 않았다. 그로 인해서 구현이 잘못된 부분이 나타났는데 이러한 동작에 의존해서 작성한 애플리케이션을 유지하고자 한다면, jeus.servlet.response.6CompatibleForcedEncoding 프로퍼티를 true로 설정한다.

3. -Djeus.servlet.response.6CompatibleSetCharacterEncoding=true

JEUS 6까지는 forced를 설정했더라도 response.setCharacterEncoding()은 우선순위가 가장 높았다. 이러한 동작을 유지하고자 한다면 jeus.servlet.response.6CompatibleSetCharacterEncoding 프로퍼티를 true로 설정한다.

-> 다시 말하면, jeus.servlet.response.6CompatibleSetCharacterEncoding 이 true일 경우 forced 의 우선순위가 낮아진다.

forced는 설정하지 않기를 권장한다. 웹 애플리케이션 개발자의 경우 default를 사용해서 매번 문자 인코딩을 설정해야 하는 수고를 덜 수 있다. default 설정으로 커버가 안 될 경우에는 response API로 Response Encoding을 설정하는 것이 바람직하다.
 

결론은 세 가지 다 권장하지 않는 걸로.

출처 : https://technet.tmaxsoft.com/upload/download/online/jeus/pver-20140827-000001/web-engine/chapter_jeus_web_engine.html

ORACLE DB EXPORT/IMPORT

ORACLE DB EXPORT/IMPORT

□ ORACLE DB EXPORT

exp system/시스템패스워드 owner=오너아이디 file=aaaa.dmp log=bbbb.log

□ ORACLE DB IMPORT

imp system/시스템패스워드 file=/home/bldfkdfdfej/aaaa.dmp log=/home/bldfkdfdfej/bbbb.log fromuser=오너아이디 touser=받는아이디 ignore=y

자바스크립트 replaceAll / trim

자바스크립트 replaceAll / trim

String.prototype.replaceAll = function(org,dest) {
 return this.split(org).join(dest);
}

String.prototype.trim = function() {
    return this.replace(/(^\s*)|(\s*$)/g, “”);
}

public int getCount(String str, String strToFind)

public int getCount(String str, String strToFind) {
  if (str == null || str.length() == 0) {
   return 0;
  }
  
  if (str.indexOf(strToFind) < 0) {
   return 0;
  }
  
  int totalCount = 0;
  int axisIdx = 0;
  int newIdx = 0;
  
  while ((newIdx = str.indexOf(strToFind, axisIdx)) > -1) {
   totalCount++;
   axisIdx = newIdx + 1;
  }
  
  return totalCount;
 }

자바 ipAddress 얻기

자바 ipAddress 얻기

<%!
 // 모든 clientIp를 얻는다.
 public Vector getClientIpList(HttpServletRequest req) {
  Vector ipList = new Vector();
  
  try {
   Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
   if (en == null) {
    return null;
   }
   
   while (en.hasMoreElements()) {
    NetworkInterface ni = en.nextElement();
    if (ni == null || ni.isLoopback()) {
     continue;
    }
      
    Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
    if (inetAddresses == null) {
     continue;
    }
    
    String oneIpAddress = null;
    while (inetAddresses.hasMoreElements()) {
     InetAddress ia = inetAddresses.nextElement();
     if (ia == null) {
      continue;
     }
     
     if (ia.getHostAddress() != null && ia.getHostAddress().indexOf(“.”) > -1) {
      oneIpAddress = ia.getHostAddress();
      
      if (oneIpAddress != null && oneIpAddress.length() > 0) {
       ipList.add(oneIpAddress); 
      }
      break;
     } 
    }
   }
   
  } catch (Exception e) {
   // 무시
  }
  
  // X-Forwarded-For 에서 얻기
  String xffAddr = req.getHeader(“X-Forwarded-For”);
  if (xffAddr != null && xffAddr.length() > 0 && !xffAddr.equals(“unknown”)) {
   ipList.add(xffAddr);
  }
  
  // RemoteAddr 얻기
  String remoteAddr = req.getRemoteAddr();
  if (remoteAddr != null && remoteAddr.length() > 0) {
   ipList.add(remoteAddr);
  }
  
  return ipList;
 }
%>

(펌) 실력있는Oracle Tunner가 되는법

(펌) 실력있는Oracle Tunner가 되는법

질문자 채택

iwis****님 답변입니다.

채택답변수145
2003.12.19. 14:24

프로필 페이지 이동

먼저, 위에 분이 말씀해주신 ERD..아주 중요하죠.

말씀처럼 아무리 SQL문장 하나 튜닝한다고 해도 구조적인 모순을 어쩔 수 없는거죠.

애초에 디자인을 잘 하면 아주 유용하겠죠.

하지만 실제 현장에선 그렇지 않습니다.

튜닝을 디자인 할 당시부터 당연히 신경을 써야하지만, 대체로 99%이상은

일단 그냥 개발하고, 운용하다가 문제(속도라든지)가 생기면 그 때서야 튜닝이란 말이 나오기 마련이죠. 이때는 ERD..즉 아키텍쳐를 고치자는 말 하기 쉽지 않습니다.

멀쩡히(??) 돌아가고 있는 프로그램을 다 뜯어고치잔거는 쉽지가 않죠.

즉, 어플리케이션의 차원의 튜닝은

첫째, SQL 문장 튜닝을 잘해야합니다.

둘째, 처음부터 디자인을 잘 해야합니다.

그렇지만 두번째의 경우는 앞서 말씀드린것처럼 쉽지가 않습니다.

튜닝은 크게 두 가지로 나뉩니다.

시스템 튜닝과 SQL문장 튜닝이죠.

먼저 SQL튜닝은 말 그래도 SQL문을 적절히 바꿔주는겁니다.

실제로 저 같은 경우도(참고로 전 개발자는 아니고 DBA입니다), 어떤 프로그램이 엄청나게 오랫동안 돌아가는 경우가 있어서, 문제가 되는 SQL문장을 찾아서(tracing) 조건절에 조건을 하나 더 줬더니, 1시간이상 돌아야 결과가 나온더것이 단 1분만에 나온적도 있습니다.

SQL튜닝을 잘 하기 위해선 일단 개발 경험이 많은게 유리합니다.

그리고 그에 받침이 될 많나 이론들(전공이시죠?)을 공부 잘 해둘 필요 당연히 있습니다.

또한 오라클에서 일반적으로 말하는 튜닝 정책(?)에 따라서 할 필요가 있습니다.

예를 들면, 아우터 조인시에는 양쪽 테이블 모두에 +기호를 사용하고, 유니온을 할 경우가 생긴다면 반드시 union all을 써야 한다…이런 내용들이죠.

그리고 literal variable말고 binding variable을 써라..

(select * from emp where empno=:a 이런거죠)->이건 제 답변을 참고하세요..

360813 Database에서 한번 조회된 결과를 다시 조회하면 -> 요게 질문입니다.

이런거는 오라클 책을 무조건 많이 보는 수밖에 없습니다.

또한, 혹 오라클을 공식적으로 구입해서 사용하시는 고객이라면, 고객번호로 메타링크(http://metalink.oracle.com)같은 곳에서 엄청난 자료를 얻을 수 있습니다.

주로 트러블슈팅에 관련되어서 엄청나게 도움을 얻을 수 있는 곳이죠.

물론 여타 공식 문서들도 디게 많습니다. 오라클의 관한 모든 문제는 여기서 해결한다고 보셔도 어쩜 무방할 정도죠.

얘기가 옆으로 좀 셌습니다. –;;

시스템 튜닝은 다시 2가지 정도로 나뉠 수 있겠습니다. 물론 제 생각입니다.

첫번째는 오라클 RDBS에 대한 튜닝이고 두번째는 말 그래도 전체 시스템(OS 등)에 대한 튜닝이라고 할 수 있겠죠.

님께서 예로 드신 병렬시스템..이런건 사실 DB튜닝이랑은 큰 관계가 없을것 같습니다. 다만 오라클에서 말하는 parallel query라든지 standby db라던지 하는 어떤 방법론적인 부분이라면 얘긴 좀 틀려지겠죠.

물론 OS차원에서의 I/O처리라던지 하는 부분에서 DB자체의 속도에 도움을 줄 수 있다고 생각할 수 있습니다.

예를 들어, 시스템에 Disk controller가 2개가 있고, 각각의 컨트롤러에 internal 1, external 1개씩 붙어있다..이럴 경우, 컨티롤러(디스크)의 효과적인 사용을 위해서 한쪽에는 DB 엔진 즉 오라클 자체를 두고, 한쪽에 데이타 파일을 위치 시킨다..뭐 이런거도 될 수 있겠네요.

어쨌든 전체 시스템에 대한 이해…이것도 중요한 부분이지만, 이건 나중 문제죠.

다만 인스톨시부터 OS에 대한 patch라던지, 아님 kernel parameter를 조정해 줄 필요가 있을 때가 있습니다.

중요하건 아무래도 오라클 RDBMS에 대한 튜닝이죠.

이건 자료를 열심히 뒤적거리고 테스트 하는…공부를 해야합니다.

일단 제 생각에..님께서 오라클 정식 고객이라면 오라클 영업사원에게 책을 달라고 하세요. 오라클을 사면 다 줘야 하는겁니다.

그럼 한 30권쯤 되는 책을 갖다 줍니다. 다 영문인데요.

그거 다 보고 제대로 이해하면 정말 훌륭한 튜너가 되실것 같습니다..^^

거기에는 님께서 궁금해하시는..(궁금해하시는지 모르겠지만..)

예를 들어 어디서 뭐가 waiting이 걸렸나..이런거 볼 때..

v$sysstat에 나오는 각 내용들이 무엇을 의미하는지 알 수 있습니다.

또한 메타링크와 연계하면 그 값들을 어떻게 조정해줘야 하는지도 알 수 있게 됩니다.

만약 이런 사정이 안된다면(오라클 공식 고객이 아니라면)…

시중에 나와있는 책들을 봐야겠습니다.

그런데 시중에 나와있는 책..(사실 전 한권도 안 봤습니다..–;;;)

이화식씨의 대용량..이 책 거의 바이블처럼 존경(??)받습니다..만

이 책은 얼핏 봤는데..일단 쓰여진지가 너무 오래됐습니다.

아시겠지만 지금 9i를 넘어서 10G가 나왔습니다.

이화식씨의 책은(이화식씨는 현재는 엔코어라는 회사를 만드셨더군요..거긴 실기 시험도 본대요..ㅎㅎㅎ) 7버전대에서 많이 문제(?)가 되었던 RBO(Role Based Optimizer)에 관한 내용이 많던걸로 얼핏 봤습니다…

그러나 이 책은(분명히 말씀드리는데 전 이 책 그냥 얼핏 하면 쭉 넘기면서 본거 뿐이니 걍 참고하시길) 나름대로 어떤 원리, 오라클의 메카니즘에 대한 이해를 바탕으로 설명을 하는 듯한 느낌을 받았습니다. 그럼으로 오라클에 대한 전체적인 메카니즘 이해에는 꽤 좋을거란 생각도 듭니다.

에..이제 질문에 답합니다..^^;;

1. 님이 지금 어떤 일을 하고 계신지..학생인지 잘 모르겠습니다만..

일단은 개발을 해보시는게 좋겠습니다. 그것도 빡~세게요..ㅎㅎㅎ

원래 DBA라는게 개발을 욜심히 하다가 DB를 더 공부해서 DBA가 되는게 일반적인 코스라고들 합니다. 그 만큼 개발 base가 필요하단 얘기죠.

2. 이화식씨 책..보십시요. 봐서 해될거 없습니다.

3. admin..이거 중요합니다. 나중에 튜너(사실 이런 직업은 아직 우리나라엔 없다고 봅니다만)가 되기 위해선 아주아주 중요하다고 봅니다.

이거를 잘 하기 위해선 공부 많이 해야합니다.

가능하다면 오라클에서 제공하는 공식 서적들을 보시기 바랍니다. 어디서든 만든 회사에서 나온 매뉴얼(??)이 젤 좋기 마련입니다.

참고로 오라클의 자료들은 90%이상이 영어입니다. 안된 얘기지만 한글로 된것들은 별로 쓸모(??)도 없고, 그나마 거의 영어를 번역한 수준입니다. 그러니 영어공부도 좀 하셔야..–;;;;

4.어쩜 젤 중요한걸 수 있는데요..직접 해봐야 합니다.

오라클 initSID.ora의 파라미터 값을 하나 고쳐서 무엇이 바뀌는지 시스템 뷰들 다 뒤져서라도 찾아야 합니다. 확인해야 합니다. 그리고 관리(admin)하다보면 정말 예상치 못한 경우도 많이 생깁니다. 그러니 그 전에 직접 다 해봐야 합니다. 백업&리커버리.. 이런거 시나리오를 구하던지 스스로 만들던지..해서 다 해봐야 합니다.

그리고 또 중요한건..이렇게 하면서 노트를 작성하는겁니다. 한 번 해봤다고 그게 머리에 남겠습니까? 그 당시의 상황이랑 자신이 취한 조치를 순서대로 가능하면 꼼꼼히 써 두는거 도움 많이 됩니다. 나중에 도움 받기 위해서가 아니고 이것도 공부입니다.

5.오라클이 제공하는 제품이 참으로 다양합니다. DB만 떨렁 있는거 아닙니다. 엄청나게 많습니다..–;; 드리고 싶은 얘긴 뭐냐면…이들이 제공하는 정보들을 놓치지 않기 위해서 otn같은데 자주 들락거리고..오라클 매거진(1년에 4번 나오나??)같은거 공짜니깐 구독하시고..오라클과 관련된 많은 사이트들(database.sarang.net 뭐 이런것들)틈틈히 주시하시는 등의 노력을 병행해야합니다.

처음엔 지식이 단편적일 수 밖에 없습니다.

그걸 아..난 정말 이런게 아니고 전체적인 걸..크게 보는 그런걸 하고 싶은데..공부가..이게 아닌데..

아닌게 아니라..맞습니다. 단편이 모여서 장편(??) 됩니다.

뭐든지 외우고 익혀두세요. 나중에 퍼즐처럼 딱딱 맞춰져 갑니다.

뭐 생각나는대로 써 봤는데..일부러 답변기간을 길게 두셨다니..저도 생각나면 와서 다시 추가하죠..

공부 열심히 하세요..^^

쇼모달 일괄제거 일지

쇼모달 일괄제거 일지

초기에 만들었던 쇼모달 제거 버전은, 오프너(패어런트)에 이어 바로 오픈대상(차일드)를 작업하는데, 문제가 있어서 폐기한다.

오프너(페어런트)들을 모두 다 처리하고, 오픈대상(차일드)는 목록에 넣어놨다가, 오픈대상(차일드)를 일괄 작업해야 문제가 생기지 않는다.

왜냐면 오프너(페어런트) 겸 오픈대상(차일드)일 경우, 둘 중 나중에 수행되는 것으로 엎어쳐지는(overwrite) 문제 때문이다.
이에 따라 새로운 버전은 오프너들을 모두 처리하고, 오픈대상을 일괄처리하는 방식으로 바꿨다.

덧붙여, 파일을 로드하는 규칙도 조금 바꿨다.

실제 파일의 위치가 operation 폴더에 있고, 결과 파일이 result 폴더에 떨어진다고 하면, 이미 바뀐 파일을 다시 바꾸는 로직을 혹시 제거하지 못했을 경우, operation 폴더의 파일을 가져오므로 앞선 작업분을 분실하는 위험이 있다.

따라서 파일을 불러올 때 목적지(result 폴더)를 일단 뒤지고, 파일이 있으면 그것을 쓰고, 없으면 아직 작업이 되지 않았으므로 operation 폴더의 파일을 가져오는게 안전하다.

이를 구현하기 위해 처음에는 파일 목록을 넣어놓는 hashMap을 썼지만, 실제 파일시스템 상에서 result 폴더를 뒤져보는게 더 확실하다고 판단하여 방식을 변경했다.

쇼모달 대체코드

쇼모달 대체코드

내가 짜고도 지렸다.

var g_shareObj = {};
var g_shareName = [];
var g_shareWin = [];

function openShareDialog(_url, _input, _features, _func) {
 g_shareObj = {};
 
 var fileName = _url;
 if (_url != null && _url.lastIndexOf(“/”) > -1) {
  var lastSlash = _url.lastIndexOf(“/”);
  fileName = _url.substring(lastSlash);
 }
 
 var newIdx = g_shareWin.length;
 
 closeShareDialogByName(fileName);
 
 g_shareName[newIdx] = fileName;
 g_shareWin[newIdx] = window.open(_url, “”, _features);
 
 g_shareWin[newIdx].dialogArguments = _input;
 g_shareWin[newIdx].callbackFunc = _func;
}

function closeShareDialog() {
 if (g_shareWin != null && g_shareWin.length > 0) {
  
  var winCount = g_shareWin.length;
  for (var i=0; i<winCount; i++) {
   if (g_shareWin[i] == null) {
    continue;
   }
   
   if (typeof(g_shareWin[i])!=”undefined” && !g_shareWin[i].closed) {
    // 열려있을시 닫기
    g_shareWin[i].close();
   }
  }
 }
}

function closeShareDialogByName(_fileName) {
 if (g_shareWin == null) {
  return false;
 }

 var winCount = g_shareWin.length;
 if (winCount < 1) {
  return false;
 }

 for (var i=0; i<winCount; i++) {
  if (g_shareWin[i] == null) {
   continue;
  }
  
  if (g_shareName[i] == _fileName) {
   if (typeof(g_shareWin[i])!=”undefined” && !g_shareWin[i].closed) {
    // 열려있을시 닫기
    g_shareWin[i].close();
   }
  }
 }
}

리눅스 특정 프로세스 종료시키는(kill) 쉘 스크립트(shell script)

리눅스 특정 프로세스 종료시키는(kill) 쉘 스크립트(shell script)

반복해서 프로세스를 종료시키는 과정이 번거로워서 쉘 스크립트를 짜보았다. 아직 서툴러서 검색을 많이 활용하여 원하는 결과를 얻을 수 있었다.

# ps -ef을 이용해서 원하는 프로세스 정보를 얻는다.
var1=$(ps -ef | grep ‘run_loop\.sh$’)
var2=$(ps -ef | grep ‘JenkinsHelper\.jar’)

#echo process info : ${var1}
#echo process info : ${var2}

# pid를 얻는다. (공백으로 잘라서, 두번째 argument)
second1=$(echo ${var1} | cut -d ” ” -f2)
second2=$(echo ${var2} | cut -d ” ” -f2)

#echo pid : ${second1} / length : ${#second1}
#echo pid : ${second2} / length : ${#second1}

# pid가 존재할 경우 프로세스를 kill 한다.

# -n 스트링은, 문자열 길이가 0 이 아닐 경우 true를 리턴한다.
if [ -n “${second1}” ]
then
        result1=$(kill -9 ${second1})
        echo process is killed.
else
        echo running process not found.
fi

if [ -n “${second2}” ]
then
        result2=$(kill -9 ${second2})
        echo process is killed.
else
        echo running process not found.
fi

[리눅스] 파일 찾기(ls), 파일 내부 문자열 찾기(grep)

[리눅스] 파일 찾기(ls), 파일 내부 문자열 찾기(grep)

자꾸 까먹어서 정리해봅니다.

1. 파일 찾기(ls)

개인적으로 파일 찾기는 find보다 ls가 편하다고 봅니다. 확장자가 xml인 파일을 모두 찾겠습니다. 아래와 같이 씁니다.

ls -al | grep ‘.*[.]xml’

또는

ls -al | grep ‘.*\.xml’

만약 하위 모든 폴더를 대상으로 찾고 싶다면 옵션에 대문자 R를 추가합니다. Recursive의 약자입니다.

ls -alR | grep ‘.*[.]xml’

또는

ls -alR | grep ‘.*\.xml’

만약 하위 폴더 중에 ‘log’폴더를 찾고 싶다면, 문자열 log로 끝나는(정규식의 $) 파일 리스트를 출력해보면 되겠습니다.

ls -alR | grep ‘log$’

2. 파일 내부 문자열 찾기(grep)

파일 내부의 문자열을 검색합니다. 내부에 encoding이라는 문자열이 포함된 xml 파일을 모두 찾겠습니다. 아래와 같이 씁니다. (grep 찾는내용 찾을위치)

grep ‘encoding’ ./*.xml 

만약 하위 모든 폴더를 대상으로 찾고 싶다면 옵션에 소문자 r을 부여합니다.

grep -r ‘encoding’ ./*.xml

아래와 같이 쓰면 하위 모든 디렉토리의 모든 파일들 대상으로 특정 문자열을 찾습니다.

grep -r ‘찾는문자열‘ ./*

Connection 누수 체크, Transaction 점검

Connection 누수 체크, Transaction 점검

파일 개수가 많아서 파서기를 개발하여 진행하였다. 사람의 눈과 손에는 한계가 있다.

1. (한 메서드 블록 내에서) try 블록 내부에 commit이나 rollback 존재하는데, catch 블록에 rollback이 존재하지 않는 경우 =>

rollback 만들어줘야 함.

2. (한 메서드 블록 내에서) try 블록 내부에 commit이나 rollback 존재하는데, (1) finally 블록 없거나 (2) finally 블록 내에 close

없는 경우 => finally 블록과 close 만들어줘야 함.

3. (한 메서드 블록 내에서) conn이 파라미터로 넘어오는데(트랜잭션으로 간주), 메서드 내부(catch와 finally 포함)에서 close나 rollback

이나 commit하는 경우 맞는지 내용 눈으로 확인해야 함.

4. (한 메서드 블록 내에서) rollback 을 갖고 있는 catch 블록이 존재하는데, rollback 을 갖고 있지 않은 catch 블록도 존재하는 경우 =>

rollback 하도록 통일

5. (한 메서드 블록 내에서) finally 내부에 commit 하는 경우 => 일반 close로 변경

6. (한 메서드 블록 내에서) finally 내부에 rollback 하는 경우 => 일반 close로 변경
 

javascript split

javascript split

어쩌다보니 내용이 split이 되어서 임시로 올림.

// 텍스트 딜리미터(|, &)로 잘라 얻기
function getArray(originText) {

    // 예 : originText = “대상텍스트&1&222&333&44|55|66”;

    if (originText == null || originText.length == 0) {
        return null;
    }
 
    if (originText.indexOf(“|”) > -1) {
        // 구분자 통일
        originText = originText.replace(“|”, “&”);
    }
 
    var delimiterIdx = originText.indexOf(“&”);
 
    if (delimiterIdx < 0) {
        // 구분자 없을시 그대로 리턴
        var resArray = [];
        resArray[0] = originText;
        return resArray;
    }
 
    var resArray = [];
    var count = 0;
    var idx = 0;
    var oneText = null;
 
    while (delimiterIdx > -1) {
        oneText = originText.substring(idx, delimiterIdx);
        if (oneText == null || oneText.length == 0) {
            break;
        }
  
        resArray[count] = oneText;
        idx = delimiterIdx + 1;
        delimiterIdx = originText.indexOf(“&”, idx);
        count++;
    }
 
     // last element
    oneText = originText.substring(idx);
    if (oneText != null && oneText.length > 0) {
        resArray[count] = oneText;
    }

    return resArray;
}

파워포인트VBA : 원하는 pptx 파일을 복수의 이미지 파일로 변환

파워포인트VBA : 원하는 pptx 파일을 복수의 이미지 파일로 변환

‘Imports Microsoft.Office.Interop.PowerPoint

Dim staticResult

Public Sub doTest()

    Dim filePath

    On Error Resume Next

    Const xlDoNotSaveChanges = 0
    Const wdFormatPDF = 32
    Const ppSaveAsJPG = 17
    Const xlHtml = 14
    Const wiFileTypeJPG = 6
    Const wdRevisionsViewFinal = 0
   
    Dim fso, objWord, objDoc
   
    Set fso = CreateObject(“Scripting.FileSystemObject”)
    Set objPowerPoint = CreateObject(“PowerPoint.Application”)
   
    ‘filePath = WScript.Arguments.Item(A)
   
    filePath = “C:\원하는파일이있는경로\test.pptx”
   
    objPowerPoint.Visible = True
   
    ‘sPdfFile = fso.GetParentFolderName(filePath) + “\” + fso.GetBaseName(filePath) + “.pdf”
    sPdfFile = fso.GetParentFolderName(filePath) + “\” + fso.GetBaseName(filePath) + “11”
   
    ‘If WScript.Arguments.Count = 0 Then
        ‘WScript.Quit
    ‘Else
        ‘For A = 0 To (WScript.Arguments.Count – 1)
            If fso.FileExists(filePath) Then

                ‘convert_slide filePath, sPdfFile, 1
               
                Save_PowerPoint_Slide_as_Images (filePath)

                ‘Set objDoc = objPowerPoint.Presentations.Open(filePath, , , FALSE)
                ‘Set wview = wdoc.ActiveWindow.View
                ‘wview.ShowRevisionsAndComments = False
                ‘wview.RevisionsView = wdRevisionsViewFinal
                ‘objDoc.SaveAs sPdfFile, wdFormatPDF, TRUE
                ‘objDoc.SaveAs sPdfFile, 17, TRUE
                ‘objDoc.Close
            Else
                MsgBox (“파일이 없습니다.”)
            End If
        ‘Next
    ‘End If
   
    ‘objPowerPoint.Quit
    Set fso = Nothing
    Set objPowerPoint = Nothing

    If Err.Number <> 0 Then
        Dim erroMsg, oShell, commadMsg
        erroMsg = “ppt_print.vbs Error: ” & filePath
   
        Set oShell = WScript.CreateObject(“WSCript.shell”)
        commadMsg = “EVENTCREATE /T WARNING /ID ” & Err.Number & ” /L APPLICATION /D ” & Chr(34) & erroMsg & Chr(34)
   
        oShell.Run commadMsg
        Set oShell = Nothing
       
        Err.Clear
    End If
End Sub

Sub Save_PowerPoint_Slide_as_Images(path As String)

    Dim pptapplication As New PowerPoint.Application
    Dim prsPres As PowerPoint.Presentation

    Set prsPres = pptapplication.Presentations.Open(path, True, False, False)
   
   
    Dim sImagePath As String
    Dim sImageName As String
    Dim sPrefix As String
    Dim oSlide As Slide ‘* Slide Object
    Dim lScaleWidth As Long ‘* Scale Width
    Dim lScaleHeight As Long ‘* Scale Height
    On Error GoTo Err_ImageSave

    Dim prePath
    prePath = Replace(path, “.pptx”, “”)
   
    Dim cnt
    cnt = 0
   
    ‘For Each oSlide In ActivePresentation.Slides ‘현재 프레젠테이션
   
    For Each oSlide In prsPres.Slides
        cnt = cnt + 1
        sImageName = prePath & “-” & cnt & “.jpg”
        oSlide.Export sImageName, “JPG”
    Next oSlide

Err_ImageSave:
    If Err <> 0 Then
        MsgBox Err.Description
    End If
End Sub
 

VBA : A열의 내용이 B열 안에 포함되어 있는지 확인

VBA : A열의 내용이 B열 안에 포함되어 있는지 확인

A열 라인 바이 라인으로 B열 안에 포함되어(included) 있는지 확인하여,

결과를 C열에 표시한다.

Sub Macro1()

‘ Macro1 Macro

‘ 바로 가기 키: Ctrl+k

Dim llist(1000)
Dim lcnt As Integer
Dim rlist(1000)
Dim rcnt As Integer

Dim oneStr As String

‘A열 선택
[A1].Select
lcnt = 0

‘리스트에 저장
Do
    oneStr = ActiveCell.Offset(0, 0).Value

    If oneStr = “” Then
        Exit Do
    End If
   
    llist(lcnt) = oneStr
    lcnt = lcnt + 1
   
    If lcnt > 999 Then
        MsgBox (“llist 배열의 크기를 늘려주세요”)
        Exit Sub
    End If

    ActiveCell.Offset(1, 0).Select
Loop

‘B열 선택
[B1].Select
rcnt = 0

‘리스트에 저장
Do
    oneStr = ActiveCell.Offset(0, 0).Value

    If oneStr = “” Then
        Exit Do
    End If
   
    rlist(rcnt) = oneStr
    rcnt = rcnt + 1
   
    If rcnt > 999 Then
        MsgBox (“rlist 배열의 크기를 늘려주세요”)
        Exit Sub
    End If

    ActiveCell.Offset(1, 0).Select
Loop

‘라인 포함여부 확인

Dim hasLine As Boolean

For i = 0 To lcnt
    hasLine = False
   
    For j = 0 To rcnt
        ‘A열의 라인이 B열 라인 안에 포함되어 있을 경우(Instr)
        If InStr(1, rlist(j), llist(i), False) > 0 Then
            hasLine = True
            Exit For
        End If
    Next j
   

    ‘C열에 표시
    [C1].Select
    ActiveCell.Offset(i, 0).Select
       
    If hasLine = True Then
        ActiveCell.Offset(0, 0).Value = “포함”
    Else
        ActiveCell.Offset(0, 0).Value = “미포함”
    End If
Next i

End Sub
 

파일패스의 확장자를 얻는 매크로 코드

파일패스의 확장자를 얻는 매크로 코드

A열에 파일패스를 쓰고, B열에서 ctrl+k키 눌러서 실행한다.

Sub Macro1()

‘ Macro1 Macro

‘ 바로 가기 키: Ctrl+k

Dim str
Dim dotPos

str = ActiveCell.Offset(0, -1).Value
dotPos = InStr(1, str, “.”)
‘MsgBox (dotPos)

If dotPos > 0 Then
    ActiveCell.Offset(0, 0).Value = Right(str, Len(str) – dotPos + 1)
Else
    ActiveCell.Offset(0, 0).Value = “없음”
End If

ActiveCell.Offset(1, 0).Select

End Sub
 

리눅스 : exe 제외하고 tar 파일 묶기

리눅스 : exe 제외하고 tar 파일 묶기

tar -cvf 결과파일명.tar –exclude *.exe 대상폴더명

clientWidth, clientHeight, offsetWidth, offsetHeight

clientWidth, clientHeight, offsetWidth, offsetHeight

javascript에서는 현재 화면의 크기를 구할 때 아래와 같이 구한다.

var clientWidth = document.documentElement.clientWidth;
var clientHeight = document.documentElement.clientHeight;

그런데 이 때 clientWidth, clientHeight 는 스크롤바의 영역을 제외한 크기이다.

다시 말해 스크롤바가 생기느냐 생기지 않느냐에 따라 크기가 달라진다.

만약 윈도우 리사이즈 함수를 구현할 때 (window.onresize = function(){})

clientWidth, clientHeight 를 잘못 쓰면 window.onresize 무한 루프에 걸릴 수 있다.

따라서 offsetWidth, offsetHeight 를 활용하자.

var offWidth = document.documentElement.offsetWidth;
var offHeight = document.documentElement.offsetHeight;

offsetWidth, offsetHeight 는 스크롤바 영역을 포함한 크기이므로 값의 변화가 없다.

자바 정규식 : js스크립트(script), js오브젝트(object) 제거

자바 정규식 : js스크립트(script), js오브젝트(object) 제거

      String targetStr = “타겟이 되는 스트링 내용”;

      String removedContent = targetStr;

      Matcher m = null;
     
      Pattern scriptPattern = Pattern.compile( “<script([^’\”]|\”[^\”]*\”|'[^’]*’)*?</script>”, Pattern.DOTALL );
      Pattern objectPattern = Pattern.compile( “<object([^’\”]|\”[^\”]*\”|'[^’]*’)*?</object>”, Pattern.DOTALL );

      m = scriptPattern.matcher(removedContent);
      removedContent = m.replaceAll(“”);
      m = objectPattern.matcher(removedContent);
      removedContent = m.replaceAll(“”);

ico 만들 수 있는 페이지(ex : favicon.ico)

ico 만들 수 있는 페이지(ex : favicon.ico)

http://convertico.com/

일반 그림파일을 ico 파일로 변환할 수 있는 사이트.​ 참고로 favicon.ico는 웹 브라우저 탭 안에 표시되는 작은 아이콘을 말한다. 웹사이트마다 다른 그림이 보이는 이유는 이 favicon.ico 파일 때문이다.

cf) 제보에 의하면 도트 프로그램 “그래픽스게일”이라는 프로그램이 있다고 한다. 찾아보니 모든 종류의 도트 작업에 있어서 최고라고. 정교한 ico 작업이 필요한 사람은 그래픽스게일을 구해보시길.

자바 부모 폴더 만들기 메서드

자바 부모 폴더 만들기 메서드

/**
  * 특정 파일패스의 부모 폴더가 없을 경우 만든다.
  *
  * @param filePath
  * @return
  */
 public static boolean makeParentDir(String filePath) {
  
  if (filePath == null || filePath.trim().length() == 0) {
   System.err.println(“makeParentDir : filePath == null || filePath.length() == 0”);
   return false;
   
  } else {
   filePath = filePath.trim();
  }
  
  if (filePath.indexOf(“/”) > -1) {
   filePath = filePath.replace(“/”, “\\”);
  }
  
  while (filePath.indexOf(“\\\\“) > -1) {
   filePath = filePath.replace(“\\\\“, “\\”);
  }
  
  // 필요한 디렉토리 만들기
  int lastSlashPos = filePath.lastIndexOf(“\\”);
  
  if (lastSlashPos > -1) {
   File d = new File(filePath.substring(0, lastSlashPos));
   if (!d.exists()) {
    d.mkdirs();
   }
   
  } else {
   System.err.println(“makeParentDir : lastSlashPos not exists”);
   return false;
  }
  
  return true;
 }

jstl-1.2, standard-1.1.2

jstl-1.2, standard-1.1.2

첨부파일은 태그 라이브러리를 사용하기 위한 jstl-1.2.jar, standard-1.1.2.jar 파일이다.

참고로 Class Path를 고치기 위해서는 일반적으로 홈에 위치한 .bash_profile 을 고치면 된다.

톰캣에서 ClassPath를 고치기 위해서는 tomcat/bin 에서 setclasspath.sh 을 수정하면 된다.

자바 클래스 비교하는 법, 파일 비교하는 법

자바 클래스 비교하는 법, 파일 비교하는 법

클래스가 아닌 파일(txt, jsp, js, java 등)은 (1) 용량, (2) 길이, (3) 내용. 3가지를 비교하면 된다.
그런데 클래스 파일은 비교가 쉽지 않다.

똑같이, 용량, 길이, 내용(바이너리 값)을 검사해본다. 그런데 2개의 클래스가 3가지 측면에서 모두 달라도, 역컴파일을 해보면 결국 내용이 동일하게 나오는 경우가 있다.

바이너리 값이 다소 달라도, 알고 보면 해당 바이너리 값은 기타 정보에 해당하는 가비지 값이었던 것.

나의 추측으로는, 동일한 파일도 컴파일러가 다르면 서로 다른 바이너리 파일(class)로 떨어질 수 있는 것 같다. 컴파일러 버전 정보라던가, 여러가지가 있겠지.

따라서 클래스와 클래스가 아닌 파일은 비교 방법이 달라야 한다.

1. 클래스가 아닌 파일 : 용량, 길이, 내용 3가지 중 하나라도 다르면 다른 파일이다.
 

2. 클래스 :
    (2-1) 용량, 길이, 내용 3가지가 같으면, 같은 파일이다. 역공학/디컴파일 불필요.
    (2-2) 용량, 길이, 내용 3가지가 다르면, 역공학을 해서 내용을 비교한다. 이것도 다르면 진짜 다른거.

주의할 점은 또한 디컴파일시 디컴파일러에 따라 지역 변수명이 랜덤하게 바뀌는 등 예외가 있으니 100% 라고 신뢰해서는 안된다.

지금으로서는 위의 방법이 최선.

더 좋은 방법을 아시겠는 분은 댓글로 부탁드립니다.

JTree : 트리에 노드추가

JTree : 트리에 노드추가

1. 새 JTree 생성

먼저 JTree 생성이다.

// JFrame 상속한 클래스에서 아래 코드를 작성한다.

// 먼저 JFrame의 ContentPane 을 가져온다.

Container container = getContentPane();

container.setLayout(null);

Font font = new Font(“굴림”, 13, 13);

// JTree 선언

// 트리에 넣을 기본값을 세팅한다.

DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(“Root”);
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode(“Node1”);
rootNode.add(node1);

JTree obj = new JTree(rootNode);

obj.setBackground(Color.white);
obj.setBounds(left, top, width, height);
obj.setFont(font);
  

// 스크롤판(JScrollPane) 에 Jtree 를 추가하고,

// ContentPane 에 스크롤판(JScrollPane)을 추가하는 방식으로 한다.

JScrollPane scrollPane = new JScrollPane(obj);  //스크롤판 추가
scrollPane.setBounds(left, top, width, height);
container.add(scrollPane); //화면에는 스크롤판 추가

2. 기존 JTree 에 Node추가

나중에 트리에 노드를 추가로 add해야 한다면 아래와 같이 코딩한다.

// 트리에 노드추가

DefaultTreeModel model = (DefaultTreeModel)fileTree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
root.add(new DefaultMutableTreeNode(“another_child”));
model.reload(root);

Apache 웹서버에 Http Authentication 적용하기

Apache 웹서버에 Http Authentication 적용하기

작성시 참고한 자료 : How To Set Up Password Authentication with Apache on Ubuntu 14.04

https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-apache-on-ubuntu-14-04

일단 Http Authentication 개념을 알아보자.

0. 개념

HTTP 기본 인증 (HTTP basic authentication)
웹 클라이언트로부터 취득한 사용자 이름과 패스워드를 사용하여 웹 서버가 사용자를 인증하는 HTTP 기반의 인증 방법. 이 방법은 이름과 패스워드가 인터넷상에서 암호화되지 않은 텍스트로 전송되기 때문에 보안성이 없다.

출처 : 네이버 지식백과 (HTTP 기본 인증 (IT용어사전, 한국정보통신기술협회))

쉽게 설명하면, Http Authentication를 적용한 후 웹사이트에 접속하면 ID랑 PASSWORD 입력하라고 창이 뜬다.

1. 우분투에 apache2 랑 apache2-utils 를 설치한다.

$sudo apt-get update
$sudo apt-get install apache2 apache2-utils

2. 유저 패스워드 파일을 만든다.
아래와 같이 쓰면 .htpasswd 파일에 id와 password가 등록된다.
$sudo htpasswd -c /etc/apache2/.htpasswd testuser1

참고로 유저를 추가하려면 아래와 같이 쓰면 된다. (.htpasswd 파일에 로우 추가됨)

$sudo htpasswd /etc/apache2/.htpasswd testuser2

파일 읽었을 때 ($cat /etc/apache2/.htpasswd) 내용이 아래와 같이 나오면 된다.

testuser1:$apr1$lzxsIfXG$tmCvCfb49vpPFwKGVsuYz.
testuser2:$apr1$p1E9MeAf$kiAhneUwr.MhAE2kKGYHK.

3. 아파치 설정 세팅
sites-enabled 설정을 수정한다.

$sudo vi /etc/apache2/sites-enabled/000-default.conf

기존 내용이 아래와 같다면,

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

아래와 같이 수정하면 된다.

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory “/var/www/html”>
        AuthType Basic
        AuthName “Restricted Content”
        AuthUserFile /etc/apache2/.htpasswd
        Require valid-user
    </Directory>
</VirtualHost>

4. 접근 설정 세팅

4-1. /etc/apache2/apache2.conf 를 아래와 같이 수정한다.

(AllowOverride 뒤의 단어를 “All”로 고치는게 포인트다.)

$sudo vi /etc/apache2/apache2.conf

(전략)
<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>
(후략)

4-2. /var/www/html/.htaccess 를 아래와 같이 수정한다.

기존 내용이 있다면 아래 쪽에 붙여넣자.

$sudo vi /var/www/html/.htaccess

AuthType Basic
AuthName “Restricted Content”
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

5. 다 됐으면 아파치 재기동(리부팅)한다.
$sudo service apache2 restart

웹사이트 재접속하면 적용되어 있을 것이다.

Mysql Update시 AutoCommint 여부 변경

Mysql Update시 AutoCommint 여부 변경

Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
 To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect. 0.000 sec

Mysql Update 시 위와 같이 1175 오류가 나면, 안전 업데이트 값을 변경해줘야 한다.

SET SQL_SAFE_UPDATES = 0; 하면 업데이트가 된다.

그런데 이 때, 만약 autocommit 이 true라면, 실수할 가능성이 있다.

따라서 SET SQL_SAFE_UPDATES = 0; 에 이어 set autocommit = 0; 을 써줘야 한다. (오토커밋 해제)

오토커밋 조회

SELECT @@AUTOCOMMIT; 

오토커밋 적용
set autocommit = 1;
set autocommit = TRUE;

오토커밋 해제
set autocommit = 0;

set autocommit = FALSE;

Rich Client Platform(RCP)

Rich Client Platform(RCP)

책을 읽다보면 RCP라는 용어가 자주 나오는데, 이미 알고 있다는 전제로 사용해서 난감하다. 해당 개념은 영문 페이지에는 꽤 잘 설명되어 있다. 한글로 된 페이지에는 제대로 나와있는 곳이 없어 직접 쓴다.

Rich Client : Thin Client와 Fat Client 사이에 해당. Thin Client는 네트워크 의존성이 매우 큰 프로그램이고, Fat Client는 로컬에 필요한 파일이 거의 존재하는 프로그램이다. 즉, Rich Client란 네트워크 의존성이 제법 있는(==Rich한) 프로그램을 뜻함.

Rich Client Application : Rich Client와 같은 뜻.

Rich Client Platform(RCP) : Rich Client Application을 사용할 수 있게 지원하는 플랫폼. 이클립스같은 경우 전형적인 RCP이다. 플러그인 방식으로 RCA를 사용할 수 있게 지원하기 때문.

오라클 에러코드

오라클 에러코드

첨부파일 참조

권순용의 실전 SQL Tuning 8강 SORT와 IN/OR 실행 계획을 이해하자

권순용의 실전 SQL Tuning 8강 SORT와 IN/OR 실행 계획을 이해하자

03:12 2017-01-17 화

SQL 8차시 SORT와 IN/OR 실행 계획을 이해하자

1/24

9i까지 group by 에 의해 정렬 수행
10g부터는 order by 로 정렬 수행.

in절에 포함된 컬럼에 정렬이 있다면, order by 를 하지 않고도 정렬이 된다.
in/or를 이용하면 된다.
그런데 그걸 모르는 경우, 이중 정렬을 하여 성능 저하가 일어난다.

2/24
SORT 관련 실행 계획
IN/OR 관련 실행 계획

3/24
SORT 관련 실행 계획 : SORT를 발생시키는 실행 계획. ORDER BY, GROUP BY, DISTINCT 등에 의해 발생함.

IN/OR 관련 실행 계획 : IN절 또는 OR절을 사용하면 CONCETENATION 실행계획 및 INLIST ITERATOR 실행 계획이 생성될 수 있다. 해당 실행 계획을 IN/OR 관련 실행 계획이라 한다.

4/24

SORT 관련 실행 계획

정렬(SORT) => 엄청난 성능 저하
정렬 양이 많다면 디스크 정렬을 수행하기 때문임.

5/24
정렬의 실행계획

(1) SORT(AGGREATE) : 집합 함수에 대한 실행 계획
(2) SORT(UNIQUE) : UNIQUE 정렬에 대한 실행 계획
(3) SORT(GROUP BY) : GROUP BY 에 대한 실행 계획
(4) SORT(ORDER BY) : ORDER BY 에 대한 실행 계획

6/24

(1) SORT(AGGREATE)

SELECT MAX(거래금액)
FROM 거래내역
WHERE 거래일자 = ‘20080801’;

–> 실행계획
SELECT STATEMENT
SORT(AGGREATE)
TABLE ACCESS (FULL) OF ‘거래내역’

ㅁ집합 함수에 따른 수행의 차이
MAX : 실제 정렬은 발생하지 않음. 하나씩 엑세스하며 큰 값 하나만 남기고 나머지 제거
MAIN : 실제 정렬은 발생하지 않음. 하나씩 엑세스하며 작은 값 하나만 남기고 나머지 제거
AVG : 모든 데이터 엑세스하여 평균 추출
SUM : 실제 정렬은 발생하지 않음. 데이터를 엑세스하여 값을 더함
COUNT : 데이터를 한 건 한 건 엑세스하여 COUNT를 누적

7/24

(2) SORT(UNIEUQ)

SELECT 사원번호, 급여
FROM 급여_이력
WHERE 사원번호 IN (SELECT 사원번호 FROM 사원 WHERE 입사일자 LIKE ‘2008%’);

8/24

(2-2) SORT(UNIQUE)

SELECT DISTINCT 사원번호, 급여
FROM 급여
WHERE 부서번호 = ’10’;

정렬에 의한 성능 저하 가능함

9/24

(3) SORT(GROUP BY)

SELECT 고객번호, SUM(거래금액) 총거래금액
FROM 거래내역
GROUP BY 고객번호;

SELECT STATEMENT
    SORT(GROUP BY)
    TABLE ACCESS (FULL) OF ‘거래내역’

GROUP BY – NO SORT
(실제 정렬은 발생하지 않아도 정렬된 그루핑 데이터를 추출할 수 있다!)
SELECT 고객번호, SUM(거래금액) 총거래금액
FROM 거래내역
GROUP BY 고객번호;

–> 실행계획

SELECT STATEMENT
    SORT(GROUP BY NO SORT)
        TALBE ACCESS (BY INDEX ROWID) OF ‘거래내역’
            INDEX (REANGE SCAN) OF ‘고객번호_IDX’

10/24
(4) SORT(ORDER BY)

실제 정렬이 발생함.

SELECT 거래일자, 고객번호, 거래금액, 상태 FROM 거래내역 ORDER BY 거래일자;

실행 계획1
SELECT STATEMENT SORT(ORDER BY) TABLE ACCESS (FULL) OF ‘거래내역’; => 정렬 발생

실행 계획2
SELECT STATEMENT SORT(NO SORT) TABLE ACCESS (BY INDEX ROWID) OF ‘거래내역’
INDEX (FULL SCAN) OF ‘거래일자_IDX’; => 정렬 발생 안함

11/24

IN/OR 관련 실행 계획

(1) CONCATENATION
(2) INLIST ITERATOR
(3) FULL SCAN

12/24
CONCATENATION 실행계획

두 가지에 관하여 합집합

SELECT 부서번호, 사원번호, 이름 FROM 사원 WHERE 지역 IN(‘서울’, ‘부산’);

최종적으로 UNION ALL 연산자로 바뀌어 출력됨

IN (‘서울’, ‘부산’) 일 경우 부산부터 추출되고, 서울이 뒤에 추출된다.
이를 이용한다면 IN절 SQL에서 ORDER BY에 의한 정렬 감소시킬 수 있음

13/24

INLIST ITERATOR

SELECT 거래일자, 고객번호, 거래금액, 상태
FROM 거래내역
WHERE 거래내역 IN (‘서울’, ‘부산’, ‘대구’);

14/24

CONCATENATION 실행계획 과 INLIST ITERATOR 의 차이

정렬 순서

INLIST ITERATOR 실행계획 : IN절의 앞에서부터 데이터 추출
CONCATENATION 실행계획 : IN절의 뒤에서부터 데이터 추출

생성 조건
INLIST ITERATOR : IN 서브 쿼리를 하는 경우
CONCATENATION : IN 절에 상수를 사용하는 경우

15/25

IN : 선분 조건을 점 조건으로 변경시 사용
      추출 순서 지정 가능
(SQL  최적화시 선분 조건을 점 조건으로 변경하고자 할 때 IN 연산자 많이 사용)

OR : OR 연산자는 추가될 때마다 처리 범위 증가
(OR는 UNION ALL로 변환됨)

OR 연산자를 사용한 SQL이 내부적으로 UNION ALL 연산자로 실행된다면
실행 계획에는 CONCATENATION 실행 계획이 생성

SORT(GROUP BY) : GROUP BY 절에 사용한 컬럼에 의해 정렬된 값 출력
HASH(GROUP BY) : 정렬값 추출되지 않음

소트 그룹바이보다는 해쉬 그룹바이가 더 빠름.

문제. SET AUTOT TRACEONLY EXP
SELECT DEPARTMENT_ID
FROM EMPLOYEES
WHERE DEPARTIMENT_ID IN (’10’, ’20’, ’30’, ’50’);

-> 답 : 실행계획에 INLIST ITERATOR 포함됨

문제. SORT는 성능 저하를 발생시킵니다.
그렇다면 어떻게하면 SORT를 감소시킬 수 있을까요?

=> ORDER BY 등을 사용하지 않고 정렬된 데이터를 추출하이 위해서는
어딘가에 정렬된 데이터가 존재해야 한다.
(SORT를 제거하고 SQL 결과를 추출하고 싶다면 인덱스 추천

MIN, MAX, AVERAGE –> SORT(AGGREATE)
GROUP BY –> SORT(GROUP BY)
ORDER BY –> SORT[ORDER BY]

최신 버전일수록 해쉬로 전환중
해쉬가 쏘트보다 빠르기 때문임.

생성 조건
INLIST ITERATOR : IN 서브 쿼리를 하는 경우 (IN절의 앞에서부터 데이터 추출)
CONCATENATION : IN 절에 상수를 사용하는 경우 (IN절의 뒤에서부터 데이터 추출)

SORT 실행 계획이 아닌 것은?
1) SORT(UNIQUE)
2) SORT(DISTINCT)
3) SORT(ORDER BY)
4) SORT(GROUP BY)

답 : 2번

IN 에서 발생할 수 없는 실행 계획은?

1) CONCATENATION 실행 계획
2) INLIST ITERAROT 실행 계획
3) FULL SCAN 실행 계획
4) SAMPLE 실행 계획

답 : 4

OR  절에서 발생할 수 있는 실행 계획은?

1) SKIP SCAN 시행 계획
2) CONCATENATION 실행 계획
3) SORT(UNIQUE) 실행 계획
4) STOPKEY 실행 계획

답 : 2번
(OR연산자는 테이블 FULL SCAN 실행 계획 또는 CONCATENATION 실행계획으로
실행 계획이 생성될 수 있습니다.)

권순용의 실전 SQL Tuning 7강 테이블과 인덱스 관련 실행 계획은 기본이다

01:22 2017-01-17 화

권순용의 실전 SQL Tuning

7차시 테이블과 인덱스 관련 실행 계획은 기본이다

1/45
– FULL SCAN 이 인덱스보다 빠를 수도 있다.

2/45

대표적인 실행 계획은 아래와 같다.

– 테이블 관련 실행 계획
– 인덱스 관련 실행 계획

3/45

TABLE FULL SCAN : 테이블을 엑세스하는 방법 중 테이블을 처음부터 끝까지 모두 엑세스하는 실행 계획

INDEX RANGE SCAN : 인덱스를 엑세스하는 경우 인덱스 범위 스캔은 일정 범위를 엑세스 하는 것을 의미함.
    보통의 경우 BETWEEN, LIKE 등 부등호 연산자를 사용할 경우 생성되는 실행 계획이다.

Parallel Processing : 이 아키텍처는 테이블을 Full Scan하거나 또는 인덱스를 Full Scan하는 경우에 여러 개의 프로세스를 가동시켜 엑세스하는 아키텍처이다.

4/45

1. 실행 계획의 종류

테이블 관련, 인덱스 관련, 정렬 관련, IN/OR 관련,
집합 연산자 관련
뷰 관련, STOPKEY 관련, 파티션 관련, 조인 관련.

5/45

테이블 엑세스 방법은 여러 개.
인덱스 이용 방법도 여러 개. -> 선택에 따라 많은 성능 차이 발생됨.

6/45

2. 테이블 관련 실행 계획
(1) 종류
(2) FULL SCAN
(3) ROWID SCAN
(4) SAMPLE

(1) 종류
테이블을 엑세스 하는 방법 == 결국, 테이블 관련 실행 계획이 됨.

(1-1) BY INDEX ROWID : 인덱스 스캔을 통한 테이블 엑세스
(1-2) FULL SCAN : 테이블 처음부터 끝까지 엑세스
(1-3) BY USER ROWID : SQL 에 설정된 ROWID에 의한 테이블 엑세스 (ROWID==데이터베이스의 주소임)
(1-4) SAMPLE : 표본 데이터 추출

ㅁ 테이블을 Full Scan하는 경우
– WHERE 조건이 없는 경우
– WHERE 조건이 있지만 INDEX가 없는 경우
– WHERE 조건이 있고 조건에 INDEX가 있지만 옵티마이저에 의해 FULL SCAN 선택
– 힌트에 의해 FULL SCAN 선택

ㅁ FULL SCAN : 테이블의 첫 번째 블록부터 마지막 블록까지 모든 데이터 블록을 엑세스. 그러므로 성능을 고려하여 다중 블록 I/O가 발생됨. 반면, 인덱스를 이용하면 단일 블록 I/O를 수행하게 됨.

ㅁ FULL SCAN
실행계획 : SELECT STATEMENT TABLE ACCESS (FULL) OF ‘TAB1’

특징 1. 일반적으로 테이블은 1개의 프로세스에 의해 엑세스 됨. 이걸 개선하기 위해 Parallel Processing 아키텍처가 고안됨. 여러 개의 프로세스를 기동시켜 엑세스하는 아키텍처. 자원을 최대한 이용, 대용량 테이블을 빠르게 엑세스할 수 있게 됨.

특징 2. 다중 블록 I/O : 한 번에 여러 개의 데이터 블록을 엑세스.(한 번에 엑세스하는 블록 개수는 DB_FILE_MULTI_BLOCK_READ_COUNT 파라미터에 의해 결정됨. 해당 값이 16이면 한 번에 16개의 데이터 블록을 다중 엑세스.)

특징 3. FULL SCAN이 인덱스 사용보다 유리할 수 있음 : 랜덤 엑세스(인덱스 엑세스 후 테이블을 엑세스)하면, 단일 블록 I/O가 수행됨. 테이블에서 많은 데이터를 엑세스하는 경우 FULL SCAN이 성능에 유리함 (대용량 테이블에서3~5% 이상)

9/45

ㅁROWID SCAN
– ROWID는 유니크하다.
– ROWID는 주소값이라고 생각하면 된다.
– 인덱스로 테이블 엑세스 : 인덱스를 통해 ROWID를 획득하고, ROWID로 테이블을 엑세스한다.

ㅁROWID 실행계획
SELECT STATEMENT TABLE ACCESS (BY INDEX ROWID) OF 부서
INDEX (RANGE SCAN) OF 지역_IDX

10/45

ㅁSQL에서 ROWID 제공시
SELECT 고객번호, 고객이름, 입금액
FROM 계좌 A
WHERE ROWID IN (SELECT SUBSTR(최대거래금액11, 16) RID
FROM (SELECT MAX(거래금액||ROWID)
           FROM 거래내역
           GROUP BY 고객번호)
                            );

–> SQL 에서 명시적으로 ROWID를 사용할 수 있으며, 실행계획에서는 BY ROWID로 바뀐다.

SELECT STATEMENT
    NESTED LOOP
        VIEW
            SORT (GROUP BY)
                INDEX (RANGE SCAN) OF ‘고객번호_IDX’
        TABLE ACCESS (BY ROWID) OF ‘계좌’

11/45

ㅁ내부적 ROWID 제공시
SELECT LEVEL, A.EMPNO FROM EMP
CONNECT BY PRIOR EMPNO = MGRNO
START WITH EMPNO = ‘1111’;

SELECT STATEMENT
    CONNECT BY (WITHOUT FILTERING)
        NESTED LOOPS
            INDEX (UNIQUE SCAN) OF ‘EMPNO_IDX’
            TABLE ACCESS (BY USER ROWID) OF ‘EMP’
        NESTED LOOPS
            BUFFER (SORT)
                CONNECT BY PUMP
            TABLE ACCESS (BY INDEX ROWID) OF ‘EMPNO’
                INDEX (RANGE SCAN) OF ‘MGRNO_IDX’

12/45
SAMPLE
SAMPLE 실행 계획은 SQL에 SAMPLE 옵션을 설정했을 경우에 생성됨

SQL> SELECT 거래일자, 고객명, 거래금액
         FROM 거래내역 SAMPLE(10);

SELECT STATEMENT
    TABLE ACCESS (SAMPLE) OF ‘거래내역’

13/45

3. 인덱스 관련 실행 계획

(1) 종류
(2) 인덱스 유일 스캔 : UNIQUE SCAN
(3) 인덱스 범위 스캔 : INDEX RANGE SCAN
(4) 인덱스 앤드-이퀄 스캔 : INDEX AND-EQUALS SCAN
(5) 인덱스 전체 스캔 : INDEX FULL SCAN
(6) 빠른 인덱스 전체 스캔 : INDEX FAST FULL SCAN
(7) 인덱스 병렬 스캔 : INDEX PARELLEL SCAN
(8) 생략 스캔 : INDEX SKIP SCAN
(9) 인덱스 민/맥스 스캔 : INDEX MIN/MAN SCAN
(10) 인덱스 조인 : INDEX JOIN

(2) 인덱스 유일 스캔 : UNIQUE SCAN
인덱스와 테이블 모두에서 무조건 1건의 데이터만을 엑세스함

UNIQUE SCAN : 한 건의 인덱스 값만 엑세스(점 조건 : =, IN)
RANGE SCAN : 여러 건의 인덱스 값을 엑세스

ㅁUNIQUE SCAN 특징

(1) 인덱스 값 : 인덱스 스캔을 통한 테이블 엑세스
(2) 높은 우선순위 : 실행 계획을 생성하는 옵티마이저에 의해 높은 우선 순위
(3) 정렬 제거 : IN 절에서 발생하는 정렬 제거 기능
 – IN 절에서 제공하는 상수 값에 대해 정렬이 발생.
 – IN 절은 내부적으로 유니크 정렬하게 됨. (변경 전 SQL이 ‘1’, ‘1’, ‘2’ 라면 ‘1’, ‘2’로 변경됨)
 – ※ UNIQUE 인덱스를 효과적으로 이용할 수 있다면, UNIQUE한 값을 생성하기 위해 수행하는
    IN 절의 UNIQUE 정렬을 제거할 수 있다.

18/45

ㅁ INDEX의 RANGE SCAN 특징
– 인덱스의 RANGE SCAN :  인덱스 관련 실행계획 중 가장 많이 사용되고 생성됨
– 인덱스 컬럼을 WHERE 조건에서 LIKE, BETWEEN, <, > 사용
– UNIQUE 인덱스를 이용하면서 선분 조건을 사용한 경우

19/45

SELECT 배송일자, 고객번호, 상품, 주소
FROM 배송내역
WHERE 배송일자 LIKE ‘200803%’;

–> 실행계획

SELECT STATEMENT
    TABLE ACCESS (BY INDEX ROWID) OF ‘배송내역’
        INDEX (RANGE SCAN) OF ‘배송일자_IDX’

위 실행 계획에는 RANGE SCAN와 BY INDEX ROWID 가 같이 등장한다.
여기서 BY INDEX ROWID는 RANGE SCAN 이 발생한 이후에 랜덤 엑세스가 발생했다는 뜻이다.

– RANGE SCAN의 단점 == 랜덤 엑세스의 단점
단점 해결법 1 : 단점을 극복하려면 선분 조건 -> 점 조건으로 변경

22/45
단점 해결법 2 : 선분 조건(BETWEEN, LIKE) -> 점 조건을 위하여 아예 날짜 테이블을 생성하여 활용.

SELECT  사용일자, 대상
FROM 이벤트
WEHRE 사용일자 IN (SELECT 사용일자
                               FROM CALENDAR
                               WHERE 사용일자
                               BETWEEN ‘20080301’ AND ‘20080430’ )
             AND 대상 = ‘A’

위의 SQL을 실행하고자 할 때, BETWEEN을 쓰지 말고 아예 날짜 테이블을 셀렉트해서 점 조건으로 만들기.

INSERT INTO CALENDAR
SELECT TO_CHAR(TO_DATE(‘20010101’, ‘YYYYMMDD’) + ROWNUM, ‘YYYYMMDD’) 사용일자
FROM TAB1
WHERE ROWNUM <=3650;

23/45

ㅁ풀 스캔
인덱스의 풀 스캔과 테이블의 풀 스캔의 차이?

– 보통의 경우 인덱스 FULL SCAN 실행 계획이 생성된다면 SQL 최적화 대상이 된다.

– (1) (인덱스 첫 번째 칼럼을 이용하여) 정렬 제거를 할 경우
– (2) 엑세스 하고자 하는 컬럼이 인덱스에 모두 존재할 경우
– 인덱스 FULL SCAN이 일어나게 된다.
– 인덱스의 FULL SCAN은 정렬을 제거하기 위해 사용 가능하지만, 랜덤 엑세스를 발생시킨다면
성능 저하를 발생시키기 때문에 최적화 대상이 됨.

ㅁ인덱스 풀스캔 실행계획
SELECT STATEMENT
    INDEX (FULL SCAN) OF ‘EMPNO_IDX’;

25/45
– 인덱스의 FULL SCAN 실행 계획은 엑세스하는 첫 번째 컬럼에 의해 정렬된 데이터가 자동 추출됨
– 첫 번째 컬럼이 동일한 값이라면 두 번째 컬럼에 의해 정렬된 데이터가 추출됨
– 잘 이용하면 ORDER BY 없이 정렬됨 (정렬 제거)

26/45

FAST FULL SCAN
인덱스의 FULL SCAN 계획에서 단일 블록 I/O 부분만 다중 블록 I/O로 변경된 실행 계획

SELECT EMPNO, SAL FROM EMPLOYEES WHERE DEPTNO = ’10’;

–>

SELECT STATEMENT
    INDEX (FAST FULL SCAN) OF ‘EMPNO_IDX’;

27/45

FAST FULL SCAN

(1) PARALLEL PROCESSING 사용 가능
(2) 다중 블록 I/O 수행
(3) 정렬 수행 불가

– 정렬 필요없는 상황에서, 인덱스 엑세스만으로 원하는 모든 값을 추출할 수 있을 경우

28/45

테이블의 총 건수를 추출할 경우 매우 유용.

SELECT /*+ PARALLEL_INDEX(TB,TB_PK,4) */ COUNT(*) FROM 거래내역 TB;

(정렬이 필요없으므로 다중 블록 I/O를 쓰면 빠르다.)

29/45

AND-EQUALS 조건

SELECT 거래일자, 고객번호, 거래금액, 상태
FROM 거래내역 A
WHERE  거래일자 = ‘20080425’
AND 가맹점_번호 = ‘1’;

두 컬럼 다 EQUAL(=)로 비교되고, 두 컬럼이 각각 인덱스가 걸려있을 경우, 머지 작업 수행.

30/45

실행계획
SELECT STATEMENT
    TABLE ACCESS (BY INDEX ROWID) OF ‘거래내역’
    AND EQUALS
        INDEX (RANGE SCAN) OF ‘거래일자_IDX’
        INDEX (RANGE SCAN) OF ‘가맹점_번호_IDX’

31/45

AND-EQUALS 특징
(1) 성능 저하 예상 – 옵티마이저가 잘 선택하지 않는 계획
(2) 결합 인덱스가 더 효과적

33/45

SKIP SCAN
유용하게 사용 가능한 계획.

SELECT 거래일자, 고객번호, 거래금액, 상태
FROM 거래내역
WHERE 거래일자 = ‘20080801’

인덱스가 가맹점_번호+거래일자 인덱스일 경우 인덱스 타지 않을 것임 (오라클 9i 이전)

이럴 경우는
SELECT 거래일자, 고객번호, 거래금액, 상태
FROM 거래내역
WHERE 거래일자 = ‘20080801’
AND 가맹점_번호 IN (SELECT 가맹점 FROM 가맹점_마스터 WHERE 1=1);

(더미 조건 == 인덱스를 동작시키기 위해 포함시키는 조건)

실행 계획
SELECT STATEMENT
    TABLE ACCESS (BY INDEX ROWID) OF ‘거래내역’
        INDEX (SKIP_SCAN) OF ‘가맹정_번호_거래일자_IDX’
    TABLE ACCESS (BY

35/45

MAX 최적화 전
SELECT MAX(거래금액) 최대금액
FROM 거래내역
WHERE 거래일자 = ‘20080801’;

MAX 최적화 후

SELECT /*+ INDEX_DESC(A,거래일자_거래금액_IDX) */
    MAX(거래금액) 최대금액
FROM 거래내역
WHERE 거래일자 = ‘20080801’
AND ROWNUM <= 1;

37/45

INDEX JOIN

SELECT 거래일자, 고객번호, 거래금액, 상태
FROM 거래내역
WHERE 가맹점_번호 = ‘1’
AND 거래일자 > ‘20080801’;

가맹점_번호 + 고객번호 인덱스
거래일자 + 거래금액 인덱스

ㅁINDEX JOIN과 INDEX AND-EQUALS 실행 계획의 차이
– AND-EQUALS : = 연산자로 사용해야 가능, 테이블 엑세스 가능
– JOIN : 부등호 및 연산자 가능, 테이블 엑세스하지 않음

=> 결합 인덱스로 성능 최적화 가능

1. EMPLOYEES에서는 인덱스가 존재하지 않는다. 알맞은 실행 계획은?
(1) FULL
(2) SAMPLE
(3) BY INDEX ROWID
(4) BY ROWID

답 : 1

2. 인덱스 생성 – CREATE UNIQUE INDEX EMPLOYEES_PK ON EMPLOYEES(EMPLOYEE_ID);
(1) RANGE SCAN
(2) UNIQUE SCAN
(3) SKIP SCAN
(4) FULL SCAN

답 : 2

해설 : 실행 계획
SELECT STATEMENT
    TALBE ACCESS BY INDEX ROWID
        INDEX UNIQUE SCAN

3.  인덱스를 이용하는 방법에 어떤게 존재할까요?

인덱스 유일 스캔 : UNIQUE SCAN
인덱스 범위 스캔 : INDEX RANGE SCAN
인덱스 앤드-이퀄 스캔 : INDEX AND-EQUALS SCAN
인덱스 전체 스캔 : INDEX FULL SCAN
빠른 인덱스 전체 스캔 : INDEX FAST FULL SCAN
인덱스 병렬 스캔 : INDEX PARELLEL SCAN
생략 스캔 : INDEX SKIP SCAN
인덱스 민/맥스 스캔 : INDEX MIN/MAN SCAN
인덱스 조인 : INDEX JOIN

ㅁ요약

1. 테이블을 엑세스 하는 방법 == 테이블 관련 실행 계획

(1) BY INDEX ROWID : 인덱스 스캔을 통한 테이블 엑세스
(2) FULL SCAN : 테이블 처음부터 끝까지 엑세스
(3) BY USER ROWID : SQL 에 설정된 ROWID에 의한 테이블 엑세스 (ROWID==데이터베이스의 주소임)
(4) SAMPLE : 표본 데이터 추출 : 10 이라고 적으면 10% 에 해당하는 표본 추출

2. 인덱스 관련 실행 계획

(1) 인덱스 유일 스캔 : UNIQUE SCAN. 실제 유니크(또는 PK) 속성으로 인덱스 줘야 하고, =(이퀄) 조건을 써야 함.
(2) 인덱스 범위 스캔 : INDEX RANGE SCAN
(3) 인덱스 앤드-이퀄 스캔 : INDEX AND-EQUALS SCAN. 싱글 컬럼 인덱스 2개를 EQUAL로 조인한다. 결합으로 바꿔주는게 효과적. 옵티마이저는 랜덤 엑세스를 줄이기 위해 인덱스 조인(인덱스 앤드-이퀄 스캔)을 감행함.
(4) 인덱스 전체 스캔 : INDEX FULL SCAN. 단일 블록 I/O. 정렬 제거에 쓰임
(5) 빠른 인덱스 전체 스캔 : INDEX FAST FULL SCAN. 다중 블록 I/O. 정렬 안됨. 카운트 셀 때 좋다.
(6) 인덱스 병렬 스캔 : INDEX PARELLEL SCAN
(7) 생략 스캔 : INDEX SKIP SCAN. 인덱스의 첫 번째 컬럼이 WHERE 절에 존재하지 않더라도 이용할 수 있게 하는 실행 계획.
(8) 인덱스 민/맥스 스캔 : INDEX MIN/MAN SCAN
인덱스 조인 : INDEX JOIN

문제

1. 테이블 관련 실행 계획으로 틀린 것은?
(1) BY INDEX ROWNID 실행 계획
(2) FULL 실행 계획
(3) BITMAP CONVERSION 실행 계획
(4) SAMPLE 실행 계획

 답 : 3

2. 인덱스 관련 실행 계획으로 틀린 것은?
(1) RANGE SCAN 실행 계획
(2) FULL SCAN 실행 계획
(3) SKIP SCAN 실행 계획
(4) JUMP SCAN 실행 계획

답 : 4

3. SKIP SCAN 실행 계획의 설명으로 올바른 것은?
(1) 인덱스의 첫 번째 컬럼이 WHERE 절에 없어도 인덱스 이용 가능
(2) MIN/MAX 값을 추출하는 실행 계획
(3) 인덱스들을 조인하는 실행 계획
(4) 인덱스들을 머지하는 실행 계획

우분투에서 tomcat8로 자바 프로젝트 띄우기 2/2 : 자바 프로젝트를 띄워보자

우분투에서 tomcat8로 자바 프로젝트 띄우기 2/2 : 자바 프로젝트를 띄워보자

지난 시간에 리눅스(우분투) 환경에서 톰캣까지 띄워봤다.

1강을 보고 톰캣까지 띄운 후 이 글을 읽어야 한다.

(우분투에서 tomcat8로 자바 프로젝트 띄우기 1/2 : 톰캣을 띄워보자 == http://blog.naver.com/bb_/220907952848)

이제 자바 프로젝트를 제대로 띄워볼 차례다.

0. 설치한 우분투 기동한다.

나의 환경 : Ubuntu 12.04.5 LTS (Release: 12.04)

우분투에서 버전 알아내는 명령어.

lsb_release -a

1. JDK 깔기

프로젝트가 어떤 JDK를 필요로 하느냐에 따라 맞는 버전을 깐다.

1-1. JDK 6 깔기

sudo apt-get install openjdk-6-jdk
sudo apt-get install openjdk-6-jre

1-2. JDK 7 깔기

sudo apt-get install openjdk-7-jdk
sudo apt-get install openjdk-7-jre

자바 설치 순서가 꼬였다면 아래 명령어로 자바를 버전을 직접 지정한다.

자바 버전을 지정하는 명령어.

update-alternatives –config java

1-3. JDK 8 깔기

Java SE Development Kit 8 Downloads 페이지.

(http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)

위 페이지에서 Linux x64 JDK8을 tar.gz 파일로 다운로드한다.(173.04 MB, jdk-8u111-linux-x64.tar.gz)

다운로드한 파일을 리눅스에 갖다 놓는다.(FTP, USB 등)

압축을 푼다.

tar -xvf  jdk-8u111-linux-x64.tar.gz

폴더를 /usr/bin/java 안쪽으로 이동시킨다.

mv ./jdk-8u111-linux-x64 /usr/bin/java/jdk1.8.0_111

모든 세팅을 JDK 8로 바꾼다.

sudo update-alternatives –install “/usr/bin/java” “java” “/usr/local/java/jdk1.8.0_111/bin/java” 1
sudo update-alternatives –install “/usr/bin/javac” “javac” “/usr/local/java/jdk1.8.0_111/bin/javac” 1
sudo update-alternatives –install “/usr/bin/javaws” “javaws” “/usr/local/java/jdk1.8.0_111/bin/javaws” 1

sudo update-alternatives –set java /usr/local/java/jdk1.8.0_111/bin/java
sudo update-alternatives –set javac /usr/local/java/jdk1.8.0_111/bin/javac
sudo update-alternatives –set javaws /usr/local/java/jdk1.8.0_111/bin/javaws

2. 프로파일 세팅.

vi /etc/profile

가장 상단에 아래와 같이 적는다.

JAVA_HOME=/usr
CATALINA_HOME=/usr/tomcat8
CLASSPATH=$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib/jsp-api.jar:$CATALINA_HOME/lib/servlet-api.jar
PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
export JAVA_HOME  CLASSPATH PATH CATALINA_HOME

명령어로 쉘에 적용시킨다.

source /etc/profile

3. 환경파일 세팅

vi /etc/environment

가장 상단에 아래와 같이 적는다.

JAVA_HOME=”/usr”

명령어로 쉘에 적용시킨다.

source /etc/environment

4. 톰캣 설정 변경

cd /usr/tomcat8

cd /conf

vi server.xml

   <Connector port=”8080″ protocol=”HTTP/1.1″
               connectionTimeout=”20000″
               redirectPort=”8443″ />

   <Connector URIEncoding=”UTF-8″ port=”80″ protocol=”HTTP/1.1″
               connectionTimeout=”20000″
               redirectPort=”8443″ />

으로 고친다.

이렇게 되면 뒤에 포트번호를 붙이지 않아도 (브라우저 기본 포트가 80 임) 접속이 된다.

그리고 원래는 Context 태그를 추가해서 폴더를 매핑해줘야 한다.

가장 쉬운 방법은 Host 태그의 appBase 부분을 변경하는 것이다.

4-1. Server.xml을 변경하지 않는 방법. (가장 쉬운 톰캣 세팅법)

<Host name=”localhost”  appBase=”webapps” unpackWARs=”true” autoDeploy=”true”>

위 설정을 손대지 말고 그대로 둔다.

대신 webapps 폴더 안의 내용을 싹 비우고, 안에 ROOT 폴더를 만든다.

톰캣이  /usr/tomcat8 에 있다고 했을 때,

실제 파일은 /usr/tomcat8/webapps/ROOT에 들어간다.

index.jsp 또는 index.htm 를 /usr/tomcat8/webapps/ROOT 위치에 넣으면 아이피 주소를 넣어서 접속했을시 해당 페이지가 뜬다.

4-1. Server.xml을 살짝 변경하는 방법. (두 번째로 쉬운 톰캣 세팅법)

<Host name=”localhost”  appBase=”webapps” unpackWARs=”true” autoDeploy=”true”>

에서 webapps 끝의 “s”만 지운다.

아래처럼 말이다.

<Host name=”localhost”  appBase=”webapp” unpackWARs=”true” autoDeploy=”true”>

으로 바꾼다. 그 다음에 /usr/tomcat8/webapp 폴더를 만들고, 안에 ROOT 폴더를 만들고, 안에 index.jsp 를 넣으면 된다.

webapp이 아니라, 프로젝트 명으로 해도 좋다.

클래스는 /usr/tomcat8/webapp/WEB-INF/classes 에 넣으면 알아서 돌아간다.

정리하자면 다음과 같다.

톰캣의 위치 : /usr/tomcat8

server.xml 의 내용 : <Host name=”localhost”  appBase=”프로젝트명” unpackWARs=”true” autoDeploy=”true”>

index.jsp(시작 페이지)의 위치 : /usr/tomcat8/프로젝트명/ROOT/index.jsp

필요한 라이브러리(jar파일들)의 위치 : /usr/tomcat8/프로젝트명/ROOT/WEB-INF/lib

클래스들의 위치 : /usr/tomcat8/프로젝트명/ROOT/WEB-INF/classes

5-2. 요약

요약하면 jdk 버전에 맞게 깔고 환경 변수 잡는다.

톰캣 적당한 위치에 풀고, server.xml의 appBase 값을 프로젝트명으로 바꾼다.

그 다음 톰캣 폴더 내에 프로젝트명 으로 폴더 만들고, 그 안에 ROOT 폴더 만들고 index.jsp 집어 넣는다. (톰캣경로/ROOT/index.jsp)

한 마디로 이클립스에서 jsp 작업하던 것들 몽땅 톰캣경로/ROOT/ 안에 넣으면된다.

이클립스에서 java 작업하던 것들은, 저장함과 동시에 calss 파일로 컴파일 되어서 class 형태로 존재할 것이다.

클래스 파일들 싹 다 잡아서 몽땅 톰캣경로/ROOT/WEB-INF/classes 안에 넣으면 된다.

우분투에서 tomcat8로 자바 프로젝트 띄우기 1/2 : 톰캣을 띄워보자

우분투에서 tomcat8로 자바 프로젝트 띄우기 1/2 : 톰캣을 띄워보자

1. 리눅스(우분투)를 준비한다.

우분투를 설치한다. 설치는 USB 구워서 다음(Next) 신공을 구사하면 된다.

아니면 웹호스팅 업체에서 리눅스 가상서버 호스팅을 구입한 후, putty로 붙어도 된다.

개인적으로 후자를 이용하였음.

나의 환경 : Ubuntu 12.04.5 LTS (Release: 12.04)

우분투에서 버전 알아내는 명령어.

lsb_release -a

2. 자바 JDK를 설치한다.

필요한 버전을 설치하면 된다.

자바를 설치하는 명령어.

sudo apt-get install openjdk-7-jdk
sudo apt-get install openjdk-6-jdk
sudo apt-get install openjdk-7-jre
sudo apt-get install openjdk-6-jre

아래 명령어들은 인터넷에서 찾았는데 동작하지 않는다.
(sudo apt-get install oracle-java8-installer

sudo apt-get install oracle-java7-installer
sudo apt-get install oracle-java6-installer)

자바 설치 순서가 꼬였다면 아래 명령어로 자바를 버전을 직접 지정한다.

자바 버전을 지정하는 명령어.

update-alternatives –config java

3. 톰캣8을 웹사이트에서 다운 받아와서 우분투 안에 넣는다.

웹호스팅 업체를 이용 중이라면 FTP로 올리면 된다.

적당한 위치에서 (ex: /usr) 압축을 푼다.

폴더 이동.

cd /usr

압축 풀기.

tar -xvf apache-tomcat-8.5.9.tar.gz

이름 변경.

mv apache-tomcat-8.5.9 tomcat8

4. 톰캣을 심볼릭 링크 지정해준다.

편하려고 권장하는 사항이므로, 꼭 하지 않아도 된다.

ln -s 원본링크 타겟링크

ex) ln -s /usr/tomcat8 /tomcat

5. 환경 변수 지정.

프로파일 세팅을 잡아야 한다.

vi /etc/profile

가장 상단에 아래와 같이 입력한다.

자바 홈 경로나, 톰캣 경로(카탈리나)는 당신이 어디에 자바와 톰캣을 설치했느냐에 따라 달라질 수 있다.

(5-1 항목 참고)

JAVA_HOME=/usr
CATALINA_HOME=/usr/tomcat8
CLASSPATH=$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib/jsp-api.jar:$CATALINA_HOME/lib/servlet-api.jar
PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
export JAVA_HOME CATALINA_HOME CLASSPATH PATH

5-1. 자바 위치를 모른다면 알아내서 JAVA_HOME 에 알맞게 쓴다. 

자바 위치 알아내기.

which java

위 방법 외에, 최상위 경로에서 하위를 모두 찾는 명령어가 있다.

find -name java

6. 프로파일을 현재 쉘에 적용시킨다.

source /etc/profile

7. 톰캣을 기동한다.

cd /usr/tomcat8/bin

./startup.sh

기동하는 쉘은 startup.sh 이다.

참고로, 종료하는 명령어.

cd /usr/tomcat8/bin

./shutdown.sh

7-1. 톰캣을 실행하기 전에 터미널을 하나 더 띄워서, 미리 로그에 tail을 걸어두자.

cd /usr/tomcat/logs

tail -f catalina.out

8. 아이피 주소로 접속 (톰캣 확인)

톰캣 서비스는 기본적으로 8080 포트를 사용한다.

정상적으로 기동되었다면,

http://ip주소:8080 을 입력했을 때, 아래와 같이 톰캣이 떠야 한다.

톰캣이 뜨지 않는다면 우선 tail 걸어놓은 catalina.out 을 보자.

거기에 왜 기동이 되지 않았는지 에러 로그가 떨어진다. 읽고 대응하도록 하자. 모르겠으면 구글링.

만약 톰캣이 떴는데도 아이피로 접속이 안된다면 아래와 같은 이유다.

1. 아이피가 틀렸다. (내가 이 경우였다. 한 자리 틀려서 20분 헤맸음.)

2. 포트가 틀렸다. server.xml 을 따로 수정하지 않았다면 8080 포트가 맞다.

3. 방화벽을 확인한다. (구글에 우분투 iptables 검색)

참고로 iptables는 우분투에서 자체 제공하는 방화벽 프로그램이다. 정책을 잘 넣어두면 디도스 같은걸 막을 수 있다.

참고. iptables

방화벽 현재 리스트 보기.

sudo iptables -L

정책 추가(APPEND) 명령어 형식.

iptables -A INPUT -s [근원지] –sport [근원지 포트] -d [목적지] –dport [목적지 포트] -j [정책]

방화벽에 허용 주소 추가하기 (8080 포트)

sudo iptables -A INPUT -m state –state NEW -m tcp -p tcp –dport 8080 -j ACCEPT

방화벽에 포트 허용하기 (8080 포트)

sudo iptables -A INPUT -m state –state NEW -m tcp -p tcp –dport 8080 -j ACCEPT

방화벽에 포트 허용하기 (80 포트)

sudo iptables -A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT

디도스 공격 차단 : 1초동안 80포트에 똑같은 IP가 10번 이상의 SYN가 들어오면 드랍하는 정책.

sudo iptables -A INPUT -p tcp –dport 80 -m recent –update –seconds 1 –hitcount 10 –name HTTP -j DROP

TCP FLAG 중 전체를 보고 그 중 SYN 과 FIN이 있을 경우 차단하는 정책

sudo iptables -A INPUT -p tcp –tcp-flags ALL SYN,FIN -j DROP

TCP FLAG 중 전체를 보고 그 중 PSH 과 FIN이 있을 경우 차단하는 정책
sudo iptables -A INPUT -p tcp –tcp-flags ALL PSH,FIN -j DROP

아이피 x.x.x.x 차단

sudo iptables -A INPUT -s x.x.x.x -j DROP

아이피 대역 d클래스 전체 차단
sudo iptables -A INPUT -s x.x.x/24 -j DROP

포트25 차단
sudo iptables -A INPUT -p tcp –dport 25 -j DROP

포트587 차단
sudo iptables -A INPUT -p tcp –dport 587 -j DROP

국가별 차단 : 80포트로 접속국가가 KR이 아닐경우 모두 DROP

iptables -A FORWARD -p tcp –dport 80 -m geoip ! –src-cc KR -j DROP

———-

1강 우분투에서 tomcat8로 자바 프로젝트 띄우기 1/2 : 톰캣을 띄워보자 끝.

2강 우분투에서 tomcat8로 자바 프로젝트 띄우기 2/2 : 자바 프로젝트를 띄워보자 == http://blog.naver.com/bb_/220908002929

checkCount 함수 (indexOf 로 갯수 세기)

checkCount 함수 (indexOf 로 갯수 세기)

<textarea rows=”6″ style=”width: 99%; overflow: hidden;” id=”req_content” onkeyup=”expandArea()” name=”req_content”><c:out 

     <script type=”text/javascript”>
       function expandArea(){
        
        var returnCount = checkCount(“#req_content”, “\n”);
        
        if (returnCount < 6) {
         $(“#req_content”).attr(“rows”, “6”);
        } else {
         $(“#req_content”).attr(“rows”, returnCount + 1); 
        }
       }
       
       function checkCount(_selector, _findChar) {
        var val = $(_selector).val();
        
        if (val == null || val.length == 0) {
         return 0;
        }
        
        var totalCount = 0;
        
        var axisPos = -2;
        var loopCnt = 0;
        while (true) {
         
         axisPos = val.indexOf(_findChar, axisPos + 1);
         if (axisPos < 0) {
          break;
         }
         
         totalCount ++;
         loopCnt++;
         if (loopCnt > 1000) {
          break;
         }
        }
        return totalCount;
       } 

권순용의 실전 SQL Tuning 6강

00:49 2017-01-10 화

권순용의 실전 SQL Tuning 6강

실행계획과 옵티마이저에 대해 배워보자.

실행계획
– 개념
– 생성법
– 해석하기

3/22
<실행계획>
실행계획은 sql이 어떻게 수행되었는지에 대한 경로를 보여준다.
실행 계획에 따라 SQL은 인덱스를 이용할 수도 있고 이용하지 않을 수도 있다.
이처럼 실행 계획을 통해 해당 SQL의 성능을 예측할 수 있다.

5/22

<실행계획>
SQL의 시작부터 종료까지의 실행 경로를 계획하는 것

원하는 데이터를 추출하는 경로를 보여주기 때문에, SQL의 튜닝은 실행 계획의 분석부터 시작.

6/22

Explain
AUTOTRACE
 TKPROF Trace
10046

<Explain 명령어>
실행계획을 추출하는 명령어. 이게 실행계획 분석의 시작이다.

1. Plan Table 생성
(유저에게 플랜 테이블에 존재해야 한다.)
@$ORACLE_HOME/rdbms/admin/utxplan.sql (Unix)
@$ORACLE_HOME\rdbms\admin\utxplan.sql (NT)

2. 실행계획 확인 방법

EXPLAIN PLAN FOR
SELECT * FORM EMPLOYEES;

이렇게 쓰면 실행계획을 추출한다.

<AUTOTRACE 명령어>

1. Plan Table 생성
(유저에게 플랜 테이블에 존재해야 한다.)
@$ORACLE_HOME/rdbms/admin/utxplan.sql (Unix)
@$ORACLE_HOME\rdbms\admin\utxplan.sql (NT)

2. PLUSTRACE 권한 생성 및 부여 (DBA 권한을 가진 유저로 수행해야 함)

옵션
TRACEONLY – 실행 수행 후 계획 추출
TRACEONLY EXPLAIN – 실행 제외 계획 추출

3. AUTOTRACE 옵션
SET AUTOT TRACEONLY EXP
SELECT * FROM XMP;

8/22
<TKPROF Trace>
1. Plan Table 생성.
2. SQL_TRACE Parameter를 True로 설정.
(30% 정도의 부하가 증가될 수 있다. 실전에서는 실행 계획 검토하려는 세션에만 적용해야.)

3. SQL 실행
Trace를 추출하고자 하는 SQL 수행

4. TKPROF 실행
# tkprof tracefile outputfile sys=no explain=username/password

많은 시간이 소요되는 SQL은 TKPROF Trace보다는
AUTOTRACE 명령어로 실행 계획 최적화 후, TKPROF Trace 방식 사용이 유리하다.

* 세션별 Trace를 수행하는 방법
 exec sys.dbms_system.set_sql_trace_in_session(SID, SERIAL#, TRUE);
 SID와 SERIAL#은 해당 세션의 고유 번호이며 해당 값은 V$SESSION 에서 확인 가능

* 실행계 성능 데이터에서 CPU시간과 ELAPSED 시간의 차이가 많다면?
악성 SQL에서 자주 발생. CPU시간과 Query 시간과의 많은 차이는 과다한 데이터 블록 엑세스에 의해 발생함.
대개의 경우 악성 SQL인 경우가 대부분임.

<실행 성능 데이터>
Count : 총 건수
Query : (메모리에서 엑세스하는) 데이터 블록 개수
CPU : cpu사용시간
Current : DML시 엑세스하는 데이터 블록 개수
Elapsed : 수행시간
Rows : 추출된 데이터의 건수
Disk : 디스크에서 엑세스하는 데이터 블록 개수

* 토드 툴의 경우 실행 성능 데이터는 Trace 탭에서 확인 가능하다.

4. 10046 Trace

사용법 : ALTER SESSION SET EVENTS ‘10046 trace name context forever, level 9’ ;

Trace 파일 위치 : USER_DUMP_DEST 파라미터에 정의된 위치에 저장

TKPROF보다 좀 더 자세한 내용을 확인할 수 있다.

(오렌지나 토드 툴에 경우 Execution Plan 또는 Explain 항목이 존재하여 실행계획 확인 가능.)

11/22
실행계획 해석
1) 도식화
2) 해석

Execution Plan
0    SELECT STATEMENT
1 0   TABLE ACCESS (BY INDEX ROWID) OF ‘EMPLOYEES’
2 1       INDEX (RANGE SCAN) of ’employees_IDX

(좌측부터)
키 값 : 실행계획 내의 유니크 값(0, 1, 2…)
부모키 값: 해당 실행계획에 대한 부모키 값 (0, 1…)
실행계획 : 각각의 실행단계

실행계획의 해석
1. 키값을 이용한 도식화 : 키값을 구준으로 부모 키값을 연결해서 해석
2, 레벨을 이용한 해석 : 실행계획의 들여쓰기 기준에 의해 해석

SELECT
  TABLE ACCESS
     INDEX SCAN

도식화된 실행계획 해석시 다음의 우선순위 준수해서 실행계획을 해석하면 됨.

아래에서 위로 – 아래 있는 실행계획부터 해석
좌측에서 우로 – 동일 높이일 경우 좌측 실행 계획부터 해석

LEVEL에 의한 실행계획 해석 (아래쪽이 레벨이 낮은것)
조인을 사용하는 경우, 조인 방식에 의해 해석해야만 정확한 해석이 가능하다.

– 익숙해지면 도식화를 위한 이해 -> LEVEL에 의한 이해 로 가는게 해석 속도가 빨라진다.

SELECT STATEMENT
    NESTED LOOPS
      TABLE ACCESS (FULL) OF ‘TABV1’
      TABLE ACCESS (FULL) OF ‘TABV2’

Level이 낮은 실행계획을 먼저 해석
동일 Level이라면 위치상 위에 있는 실행계획을 먼저 해석
조인방식 사용시 조인실행 방식에 의해 해석

15/22

악성 SQL 최적화 수행 순서

– TRACEONLY EXP : SQL 수행하지 않고 실행계획만 확인하여 실행 계획 최적화 수행

– TRACEONLY : 실행계획 최적화 후 SQL을 수행하여 세미한 최적화 수행함

SQL 최적화 시 위와 같이 1단계 수행후 2단계로 가게 됨. 경우에 따라서는 동시에 하기도 함.

16/22

AUTOTRACE 를 이용하여 실행계획만을 추출하고자 한다면 다음 중 어떤 옵션을 사용해야 할까요?
알맞은 옵션을 드래그 하여 넣어보세요.

on 옵션 : 결과도 추출
실행계획, 실행성능

– TRACEONLY EXP == 결과없이 실행계획만
– TRACEONLY ONLY == 결과없이 실행계획, 실행성능데이터
– OFF  == 트레이스 모드가 종료된다.

18/22

실행계획은 왜 분석이 필요할까요?

– SQL이 인덱스를 사용했는지 아닌지에 대한 분석, 인덱스를 이용했다면 어떤 인덱스를 썼는가,
어떻게 이용했는가를 이해해야만 해당 SQL을 최적화할 수 있게 된다.
그렇게 때문에 SQL 성능을 분석하고 최적화하기 위해서는 실행계획 분석이 필수적이다.

AUTOTRACE ON : 실행하고, 실행계획 얻음
AUTOTRACE TRACE ONLY : 해당 SQL수행하고, 실행계획 얻음. 결과는 추출되지만 실제 화면에 디스플레이 되진 않는다.
AUTOTRACE TRACE ONLY EXP : 수행없음. 단지 실행계획만 얻는다.

*** 가장 안쪽의 들여쓰기 실행계획부터 해석하면 되고,
동일한 들여쓰기라면 위의 실행계획부터 해석한다.

퀴즈 1. 실행계획의 설명으로 올바른 것은?
1) SQL이 수행되어 추출되는 결과를 의미
2) SQL이 실행되는 경로를 의미
3) SQL의 구문 분석을 의미
4) SQL의 응답속도를 의미

답 : 2

– sql이 인덱스를 탔는지 안탔는지에 대한 내용도 실행계획을 통해 볼 수 있음.
sql이 어떻게 수행되었는지에 대한 경로를 보여주게 됨.

퀴즈 2. 실행 계획을 추출할 수 있는 방법이 아닌 것은?

1) Explain Paln For
2) 10046 Trace
3) Dump
4) Autotrace

답 : 3

실행 계획을 추출할 수 있는 방법에는 Explain 명령어, AUTOTRACE 명령어, TKPROF Trace 명령어, 10046 Trace 등이 있습니다.

퀴즈 3. 실행 계획의 해석 방법으로 올바른 것은?

1) Level을 이용한 실행계획 해석
2) 위에서부터 아래로 해석하는 Top down 방식
3) 아래서부터 위로 해석하는 Bottom up 방식
4) Case By Case 를 이용한 해석 방식

답 : 1

01:37 2017-01-10 화

권순용의 실전 SQL Tuning 5강

권순용의 실전 SQL Tuning 5강

00:55 2017-01-06 금

SQL 5강 SQL은 옵티마이저에 의해 변경

ㅁ 학습목표
구문 분석 및 SQL의 실행 절차를 설명
Query Transformation
옵티마이저의 특징

(1) SQL 실행 절차
(2) 구문분석
(3) Query Transformation
(4) 옵티마이저

ㅁ 구문분석

SQL을 수행하기 위해 SQL의 문법, 권한 등을
확인하는 초기 단계를 의미한다.

ㅁ Query Transformation

SQL이 구문분석 과정을 마치고
실행이 되기 전에 수행한 SQL을 변형하는 단계임.

ㅁ 옵티마이저

데이터 베이스의 두뇌에 해당.
SQL의 결과를 추출하기 위해 어떻게 수행될지를 결정한다.

ㅁ 서브쿼리

Query Transformation 단계에서 발생하게 된다.
서브쿼리 Merging은 In절, Any 절, Not in 절, All 절을
NOT EXISTS 절로 변경하는 단계이다.

ㅁ 뷰 머징

Query Transformation   단계에서 가장 먼저 수행되는 단계는 “뷰 머징”단계이다.
인라인 뷰 또는 뷰를 사용한 SQL을 옵티마이저가 변경하여 뷰의 쿼리가
주 쿼리와 통합되어 뷰가 제거되거나
뷰에 조건이 삽입되는 경우를 말한다.

1. SQL 실행 절차

구문 분석 -> 쿼리 트랜스포메이션 -> Cost 계산 후 실행계획 생성

ㅁ SQL 실행절차

SQL 수행 -> 구문분석 (Query Transformation 포함) -> 옵티마이저 선택 -> 비용 계산 -> 실행 계획 생성

ㅁ Query Transformation
– SQL 을 변경 하는 단계. “구문분석”에 포함된다.
뷰 Merging, 서브 쿼리 Merging, Transitivity, OR Expansion 및 Query Rewrite 과정을 수행함.

– 해당 과정을 통해 SQL에 조건을 삽입하거나 생성하고
경우에 따라서는 쿼리 전체를 변경하여 최대한 처리 범위를 감소시킬 수 있는 형태의 SQL로 변경하게 됨

– DB 버전이 높을수록 Query Transformation 과정은 더욱 활발하게 발생함.
이 과정을 거치면서 우리가 수행한 SQL의 대부분은 변경이 됨.
처리 범위를 감소시켜 성능을 향상시키기 위한 목적임. SQL이 변경된 이후에도 변경 전과 동일한 데이터가 추출됨

– 결국 Query Transformation은 SQL의 성능을 향상시키기 위해 옵티마이저가 단독으로 수행하는 과정임.

ㅁ 옵티마이저 선택

– “비용 기반” 옵티마이저와 “규칙 기반” 옵티마이저 중 하나를 선택

– 대부분의 DB는 “비용 기반” 옵티마이저가 기본값

– 오라클도 기본값으로 “비용 기반” 옵티마이저를 선택

ㅁ 비용계산
– SQL 이 수행될 수 있는 모든 경우에 대해 추출하고자 하는 데이터의 비율을 계산하는 Selectivity를 추출한 후
Selectivity 에 전체 건수를 곱하여 추출하고자 하는 데이터의 전체 건수를 Cardinality 로 도출하여
도출된 Cardinality 와 다른 통계 정보를 통해 비용을 계산함.

– 비용 계산 결과 가장 적은 비용이 소요되는 형태의 SQL 수행 방식을 선택함.

ㅁ 실행 계획 생성
– 비용 계산 결과 가장 적은 비용이 소요되는 SQL의 수행 방법을 선택한 다음에는
해당 방법을 “실행 계획”으로 생성하게 됨.

– 실행 계획이 생성되면 해당 SQL은 실행 계획에 의해서 수행이 되므로,
이와 같은 실행 계획을 통해 “SQL 최적화”를 수행하게 됨.

2. 구문 분석
1) 구문 분석 절차

SQL의 수행 여부를 확인하는 과정이 구문 분석.
구문 분석 과정 중에 옵티마이저는 Query Transformation 을 수행하게 됨. => 가장 먼저 수행

구문 분석 절차는 6단계임
검색 -> 문법 확인 -> Semantic 확인 -> Query Transformation -> 권한 확인, TM(Table Management Lock)

———-

<구문분석의 과정>
검색 -> 신택스 -> 시멘틱 -> 권한 -> TM락

소프트 파싱 : “검색”을 수행해서, 메모리에 있으면 더 이상 진행하지 않고 아까의 실행계획 다시 수행

하드 파싱 : “검색”을 수행해서, 메모리에 없으면 아래 로직을 수행함.

1. 검색
2. 신택스 확인 (문법, 맞춤법)
3. 시멘틱 체크 (테이블, 컬럼 존재 체크)
4. 권한 확인
5. TM LOCK (테이블 매니지먼트 락==티엠 락.) : 다른 접근에 의한 변경을 막는 락이다.

구문 분석 내에 쿼리 트랜스포메이션이 있다.

쿼리 트랜스포메이션 : 뷰 머징, 서브쿼리 머징, 트랜시티비티, OR 익스팬션, 쿼리 리라이트

———-

13/27

<뷰 머징>

뷰 머징(주 쿼리의 조건이 인라인 뷰로 삽입되는 형태)이 발생한 것.

조건이 삽입되더라도 해당 조건을이용하여 처리 범위를 감소시키고자 한다면
그에 맞는 인덱스가 존재해야 함.
(- 인덱스가 존재하지 않는다면 조건이 삽입되더라도
처리 범위가 감소되지 않으므로
의도대로 성능 향상을 기대할 수 없음)

14/27

<서브쿼리 머징>

서브쿼리 머징도 쿼리 트랜스포메이션 단계에서 발생.

IN, ANY, NOT IN, ALL 을 -> EXISTS 또는 NOT EXISTS 로 변경한다.

존재유무 쿼리로 바꾸면, 반드시는 아니지만, 성능향상.

15/27

<트랜시티비티>
해당 SQL에 조인이 사용되는 경우,
논리적으로 추가할 수 있는 조건을 추가

논리적으로 가능한 조건을 추가 -> 처리 범위를 감소시킨다.
(사용자가 명시적으로 해주면 더 좋다고 함.)

17/27

쿼리 리라이트(Query Rewrite)

보통, Meterialized View를 이용하는 과정에 발생하는 경우 많음.

Meterialized view를 사용해서 성능이 향상된다면,
쿼리를 이걸로 대체해서 쓴다.
이 경우를 대비해, View에 인덱스를 넣어줘야 한다.

18/27

<OR Expansion>

SQL 의 IN 절과 OR 절은 많은 경우, UNION ALL 절로 변경된다.

참고로, WHERE 가맹점번호 IN (‘111’, ‘112’, ‘113’) 일 경우,
뒤에서부터 UNION ALL 을 한다.
(113 UNION ALLl 112 UNION ALL 111).
그러므로 이 순서로 정렬된다.

19/27

<옵티마이저>
1. 비용계산법
2. 옵티마이저 종류

옵티마이저는 비용 계산을 수행하여 가장 적은 비용의 실행 계획 선택.

셀렉티비티 (조건을 만족하는 데이터가 차지하는 비율. 0 ~ 1 사이)

카디널리티 : 셀렉티비티 * 전체 건수 = 카디널리티. (셀렉티비티는 비율이므로 대용량 테이블에서는 셀렉티비티가 낮아도 무의미)

비용 : 통계정보 + 디스크 아이오 + 메모리 + 시피유

20/27

옵티마이저
1. 규칙 기반 : SQL문, 인덱스를 참조하여 실행계획 생성
2. 비용 기반 : 통계를 바탕으로 실행계획 생성. 융통성 있음. (but, 일부 통계정보 이용시 종종 잘못될 수도 있음.)

21/27

보충 및 심화학습

옵티마이저에 영향을 주는 요소
– SQL 형태, 연산자, 인덱스/테이블 구조, 힌트사용, 옵티마이저 모드, DBMS 버전, 통계정보…
(주의깊게 관리해야 하는 요소들. 옵티마이저에 영향을 주기 때문임.)

실행계획이 변한다는 것 = SQL 의 성능이 달라진다는 것.

22/27

쿼리에 뷰가 있었는데,
인라인 뷰가 실행계획에 없다면?
“인머저블 인라인 뷰”가 아니라, “머저블 인라인 뷰”였던 것임.
“뷰”라는 실행계획이 생성되지 않았을 경우.

23/27

데이터베이스는 제가 수행한 SQL을 그대로 수행할까요?
아니다. 옵티마이저가 최적화함.

퀴즈 1. 쿼리 트랜스포메이션에 해당하지 않는 항목은?
1. 뷰 머징
2. 트랜시티비티
3. 인라인 뷰
4. OR 익스팬션

답 : 3번
해설 : Query Transformation에 해당하는 항목은 뷰 머징, 서브쿼리 머징, 트랜시비티비, 쿼리 리라이트, 오어 익스팬션입니다.

퀴즈2. 옵티마이저에 영향을 미치는 요소가 아닌 것은?
1. 인덱스
2. 테이블 구조
3. 데이터베이스 버전
4. Client Tool의 종류

답 : 4번
해설 : 옵티마이저에 영향을 미치는 요소로는 힌트 사용, 옵티마이저 Mode, DBMS버전, 통계정보, 연산자, SQL형태, 인덱스/테이블 구조 등이 있습니다.

퀴즈3. 구문 분석의 단계가 아닌 것은?

1. 신택스 확인
2. 시멘틱 확인
3. SQL수행
4. 기존 실행계획 검색

답 : 3번
해설 : 구문 분석 단계는 기존 실행 계획 검색, 신택스 확인, 시멘틱 확인, 권한 확인으로 구성됩니다.

00:48 2017-01-10 화

javascript 쿠키

javascript 쿠키

 

function setCookie(name, value, expireDays) {
 
 var today = new Date();
    today.setDate(today.getDate() + expireDays);

    // document.cookie = name + ‘=’ + escape(value) + ‘; path=/; expires=’ + today.toGMTString() + ‘;’
    document.cookie = name + ‘=’ + value + ‘; path=/; expires=’ + today.toGMTString() + ‘;’
}

function getCookie(name){
 
 var wcname = name + ‘=’;
 var wcstart, wcend, end;
 var i = 0;   

   while(i <= document.cookie.length) {           
    wcstart = i; 
  wcend   = (i + wcname.length);           
  if(document.cookie.substring(wcstart, wcend) == wcname) {                   
   if((end = document.cookie.indexOf(‘;’, wcend)) == -1)                          
    end = document.cookie.length;                   
   return document.cookie.substring(wcend, end);           
    }           

  i = document.cookie.indexOf(”, i) + 1;           
  
    if(i == 0)                   
   break;   
   }   
   return ”;
}

javascript n일 뒤의 날짜 구하기

javascript n일 뒤의 날짜 구하기

 

// n일 뒤의 날짜 구하기
 function getFutureDate(_intNum) {
  // 오늘 날짜 구하기
  var todayObj = new Date();
  var todayYear = todayObj.getFullYear();
  var todayMonth = (todayObj.getMonth() + 1);
  var todayDay = todayObj.getDate();
  
  // 새로운 날짜 구하기 (_intNum 일 뒤의 날짜)
  var newDateObj = new Date(todayYear, todayMonth-1, todayDay);
  newDateObj.setDate(newDateObj.getDate() + parseInt(_intNum, 10));
  
  var newYear = newDateObj.getFullYear();
  var newMonth = (newDateObj.getMonth() + 1);
  var newDay = newDateObj.getDate();
  
  var newFullDate = newYear + make2digit(newMonth) + make2digit(newDay);
  
  return newFullDate;
 }

 

// 숫자 2자리로 만들기
 function make2digit(_num) {
  if (_num == null) {
   return “00”;
   
  } else {
   _num = _num + “”; //toString
   _num = _num.trim();
   
   if (_num.length == 1) {
    return “0” + _num;
   } else if (_num.length == 2) {
    return _num;
   }
  }
  
  return _num.substring(0, 2);
 }

JQuery radio 버튼 선택

JQuery radio 버튼 선택

 

$(“.클래스명:input[value='” + 밸류 + “‘]”).attr(“checked”,”checked”);

자바스크립트 숫자인지 검사

자바스크립트 숫자인지 검사

 

인터넷에 흔히 돌아다니는 isNaN(parseInt(숫자)) 검증은 문제가 있어서 새로 짜보았음.

’11aa’ 와 같은 케이스 발견 불가능하므로 길이만큼 for문 돌아주는게 제일 속편함.

// 숫자만 얻기
 function getNum(_str) {
  
  try {
   if (_str == null || _str.trim().length == 0) {
    return false;
   }
   _str = _str.trim();
   
   // 1차 검증
   var num = parseInt(_str);
   if (num == null || isNaN(num)) {
    return false;
   }

 

   // 1차 검증시 : ’11aa’ 와 같은 케이스 발견 불가
   var len = _str.length;
   var oneChar = “”;
   for(var i=0; i<len; i++) {
    oneChar = _str.substring(i, i+1);
    if (oneChar == “0”) {
     continue;
    }
    
    if (isNaN(parseInt(oneChar))) {
     return false;
    }
   }
   
  } catch (e) {
   return false;
  }
  
  return num;
 }

권순용의 실전 SQL 튜닝 4강 : 인덱스는 결합 인덱스로 선정하자

권순용의 실전  SQL 튜닝 4강 : 인덱스는 결합 인덱스로 선정하자

00:03 2017-01-05 목

4강 인덱스는 결합 인덱스로 선정하자

ㅁ 인트로
Q. 분포도가 좋은 컬럼을 앞에, 분포도가 나쁜 컬럼을 뒤에 둬야 하지 않나요?

A. 매우 위험한 선정이다! 결합 컬럼은 “분포도”가 아닌, “연산자”가 우선이 되어야 한다.
점 조건이 먼저, 선분 조건이 나중에 되도록 순서를 조정해야 한다.

ㅁ 용어정리
단일 컬럼 인덱스
– 하나의 컬럼으로만 생성된 인덱스

결합 컬럼 인덱스
– 하나의 컬럼이 아닌 여러 개의 컬럼으로 생성된 인덱스

점 조건 (Point Condition)
– Where 조건에서 =, IN 연산자를 사용한 조건의 컬럼

선분 조건 (Line Condition)
– Where 조건에서 =, IN을 제외한 LIKE, BETWEEN 등의 연산자를 사용한 조건의 컬럼

ㅁ 결합 컬럼 인덱스의 개념
(1) 특징
(2) 성능차이

하나의 컬럼으로 인덱스를 선정하는건 유용하지 않음.

인덱스가 col1 인덱스일 경우 -> (1) 반드시 where에 col1이 있어야 함.
인덱스를 col1+col2인덱스로 설정한다면 -> (1) where 절에 col1만 있어도 적용, (2) col1과 col2 있어도 적용. (3) 최적화 잘하면 col2 조건만 존재해도 인덱스 적용

전제 조건 : 결합 컬럼의 첫 번째 컬럼이 where 절에 조건으로 존재해야만 적용됨.
(단, 오라클 10g 이상부터는 where절의 첫 번째 컬럼이 아니어도 인덱스 적용 == 인덱스 SKIP SCAN이라 부름)

*** 인덱스는 컬럼 순서에 의해 성능차이가 있음.

ㅁ 해당  SQL에 대한 최적의 결합 컬럼 인덱스는?
SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 계좌번호 LIKE ‘210%’
AND 연령 =20;

답 : 최적의 인덱스는 “계좌번호+연령”이 아니라, “연령+계좌번호” 인덱스이다.
전자는 처리범위 증가에 따라 성능 저하가 일어날 수 있다.

ㅁ 컬럼 순서에 의한 성능 차이(1)
SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 = ‘200803’
AND 연령 BETWEEN 20 AND 30;
일 경우,

==> 개설년월 + 연령 인덱스가 더 효과적이다.
연령 + 개선년월 인덱스는 성능이 떨어진다.
(점을 먼저 찾고, 선분을 나중에 찾는게 좋다)

ㅁ 컬럼 순서에 의한 성능 차이(2)
SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 BETWEEN ‘200802’ AND ‘200804’
AND 연령 = 20;

==> 연령 + 개설년월 인덱스가 더 효과적이다.
즉, 컬럼 순서에 의한 성능차이 (1), (2)를 종합해보았을 때,
연산자가 중요하다.

2. 결합 컬럼 인덱스의 선정
(1) 선분조건과 점 조건
(2) 결합 컬럼 인덱스 컬럼 순서 선정
(3) 점 조건으로 사용된 컬럼
(4) 랜덤 엑세스를 감소시키기 위핸 컬럼
(5) 정렬을 제거하기 위한 컬럼
(6) 분포도가 좋은 컬럼

ㅁ 선분 조건과 점 조건
선분조건 (Line Condition)
– Like
– Between
– <, >

점 조건 (Point Condition)
– =
– In

ㅁ 점 조건과 점 조건
SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 = ‘200803’
AND 연령 = 20;

인덱스의 형태 = 점 조건1 + 점 조건2 일때,
처리 범위를 감소시키는 조건 = 점 조건1, 점 조건2
(개설년월 + 연령 인덱스, 또는
연령 + 개설년월 인덱스 모두 동일한 처리 범위를 가지게 된다)

ㅁ 점 조건과 선분 조건의 비교

SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 = ‘200803’
AND 연령 BETWEEN 15 AND 28;

인덱스의 형태 = 점 조건 + 선분 조건
(개설년월 + 연령 인덱스 권장)

ㅁ 선분 조건과 점 조건의 비교

SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 BETWEEN ‘200802’ AND ‘200804’
AND 연령 = 25;

인덱스의 형태 = 선분 조건 + 점 조건 일 경우,
처리 범위를 감소시키는 조건 = 선분 조건만.

ㅁ 선분 조건과 선분 조건의 비교

SELECT 계좌번호, 입금자, 입금액
FROM 계좌
WHERE 개설년월 BETWEEN ‘200802’ AND ‘200804’
AND 연령 BETWEEN 15 AND 28;

인덱스의 형태 = 선분 조건1 + 선분 조건2
처리 범위를 감소시키는 조건 = 선분 조건1

ㅁ 인덱스의 형태 = 점 조건1 + 점 조건2 -> 처리 범위를 감소시키는 조건 = 점 조건1, 점 조건2 – A
인덱스의 형태 = 점 조건 + 선분 조건 -> 처리 범위를 감소시키는 조건 = 점 조건, 선분 조건 – B
인덱스의 형태 = 선분 조건 + 점 조건 -> 처리 범위를 감소시키는 조건 = 선분 조건 – C ===> *** C 는 B 로 변경하여야 한다.
인덱스의 형태 = 선분 조건1 + 선분 조건2 -> 처리 범위를 감소시키는 조건 = 선분 조건1 – D : 순서를 바꿔도 의미 없다.

※ 점 조건으로 조회되는 컬럼이 결합 컬럼 인덱스의 앞에 위치해야 함.

ㅁ 결합 컬럼 인덱스 컬럼 순서 선정

점 조건과 선분 조건
– 점 조건으로 사용된 컬럼이 결합 컬럼 인덱스에서 가장 앞에 위치해야 함
– 점 조건으로 사용되는 컬럼이 여러 개 존재한다면, 해당 조건들을 모두 앞으로 해야 함 (선분 조건은 뒤에 위치해야 함)
– 점 조건들에 의해 처리 범위가 감소함.
   그 다음 1개의 선분 조건에 의해서 처리 범위가 감소함. 나머지 선분 조건들은 랜덤 엑세스를 제거하는 역할 수행
– 결합 컬럼 인덱스의 핵심은 “처리 범위를 얼마나 많이 감소시키는가”임.

랜덤 엑세스
– 랜덤 엑세스는 인덱스 엑세스 후 테이블을 엑세스하는 과정에서 발생하는 현상.
– 랜덤 엑세스의 증가는 성능 저하로 이어지므로 랜덤 엑세스를 감소시킬 수 있는 결합 컬럼 인덱스를 생성해야 함.

정렬의 제거
– 대용량의 데이터에 대한 정렬은 해당 시스템에 많은 부하 가중
– 결합 컬럼 인덱스를 이용하여 정렬을 제거할 수 있다면 이것만으로도 많은 성능을 향상시킬 수 있음
– 결합 컬럼 인덱스의 컬럼을 선정하는 단계에서, 정렬 제거도 항상 고려해야 함.

단일 컬럼의 분포도
– 결합 컬럼 인덱스의 컬럼 순서와 분포도는 해당 SQL 성능과 무관함
– 결합 컬럼 인덱스의 핵심(가장 중요한 항목)은 처리범위를 최소화 시키는 것.
– 단일 컬럼 분포도에 의해 결합 컬럼 인덱스 생성은 다른 SQL를 고려한 것임.
(== 다른 SQL을 고려한다면 분포도가 좋은 컬럼을 인덱스의 앞에 위치시키는 것이 유리함.)

ㅁ 점 조건으로 사용된 컬럼
– where 조건에서 점 조건으로 사용된 컬럼이 결합 컬럼 인덱스의 가장 앞에 위치
– 점 조건으로 사용된 컬럼이 여러 개라면 어느 컬럼이 먼저 위치해도 성능에 무관

ㅁ 랜덤 엑세스를 감소시키기 위한 컬럼

ㅁ 확인 랜덤 엑세스
– 확인 랜덤 엑세스는 WHERE 조건의 컬럼이 인덱스에 존재하지 않아
테이블을 엑세스한 후 해당 컬럼의 값을 확인하여
조건을 만족하면 결과로 추출하고
만족하지 않으면 해당 데이터를 버리는 역할을 수행함

SELECT 계좌번호, 입금자, 입금액
FROM 입금_목록
WHERE 구분 = ‘A’ ===> 확인 랜덤 엑세스
AND 계좌번호 = ‘115’;

계좌번호에만 인덱스가 걸려 있다면,
구분 컬럼에 확인 랜덤 엑세스가 발생한다.

(해결책 1 : 구분 + 계좌번호 인덱스 생성
해결책 2 : 계좌번호 + 구분 인덱스 생성)

ㅁ 정렬 랜덤 엑세스
Order By 절의 컬럼이 인덱스에 존재하지 않아 테이블을 엑세스하여 Order By 절의 컬럼 값을
확인한 후 정렬을 수행하는 경우 발생하는 랜덤 엑세스

SELECT 계좌번호, 입금액
FROM 입금_목록
WHERE 계좌번호 = ‘115’
ORDER BY 구분; ===> 정렬 랜덤 엑세스 발생

계좌번호 인덱스 일경우, 계좌번호 + 구분 인덱스로 변경하면 됨.

– Order By 의 컬럼을 인덱스에 추가하면 정렬 랜덤 엑세스는 제거됨
– 정렬 랜덤 인덱스를 발생시키는 컬럼은 처리 범위를 감소시킬 수 없는 컬럼이므로
   인덱스에서의 위치는 중요하지 않음.
– 모든 정렬 랜덤 엑세스를 제거할 수는 없지만, 하나 또는 두 개의 컬럼을 인덱스에 추가함으로써
많은 정렬 랜덤 엑세스를 제거할 수 있다면 반드시 인덱스에 해당 컬럼을 추가하는 것을 고려해야 함.

ㅁ 추출 랜덤 엑세스
결과 데이터를 추출하기 위해 테이블을 엑세스하는 것. Select 절의 컬럼을 추출하기 위해
테이블을 엑세스하는 것을 의미함

SELECT 계좌번호, 입금액, 구분 FROM 입금_목록 WHERE 계좌번호 = ‘115’

셀렉트 절에 있는 모든 컬럼을 인덱스에 추가하면 되는데,
이렇게 되면 인덱스 관리에 어려움이 따를 수 있음.

*** 확인 랜덤 엑세스는 단일 블록 I/O에 대한 비효율 뿐만 아니라
추출되는 데이터를 감소시킬 수도 있으므로
비효율이 많이 발생함.
*** 확인 랜덤 엑세스를 제거하면 불필요한 랜덤 엑세스가 감소하여 성능이 향상됨

ㅁ 정렬을 제거하기 위한 컬럼

정렬 랜덤 엑세스 != 정렬의 제거 (전혀 다른 이야기)

정렬 랜덤 엑세스 : 정렬을 수행하는 컬럼이 인덱스에 존재하지 않기 때문에, 테이블을 엑세스하는 것을 의미한다.
정렬의 제거 : 정렬 랜덤 엑세스도 제거하지만, 실제 정렬이 수행되지 않게 하는 인덱스 선정.

SEELCT 입금자
FROM 입금_목록
WHERE 계좌번호 = ‘115’
ORDER BY 입금액;

ORDER BY 컬럼을 사용하지 않고, 인덱스 만으로 정렬을 해야 “정렬 제거” 된 것임.

SELECT 입금자
FROM 입금_목록
WHERE 계좌번호 = ‘115’;

해답 : 계좌번호+입금액 인덱스를 만들면 된다.
– 계좌번호 + 입금액 인덱스를 생성해보면, 동일한 계좌번호 컬럼의 값에 대해서는
입금액 컬럼의 값으로 정렬이 되어 있음.
– 위  SQL 에서 Order By 절을 생략하고 계좌번호 + 입금액 인덱스를 이용한다면
계좌번호 조건은 점 조건이므로 동일한 값만 엑세스하게 되며
추출되는 데이터는 입금액 컬럼의 값으로 자동 정렬되어 결과가 추출됨.

ㅁ 컬럼의 분포도 : 결합 인덱스를 선정하는 마지막 우선 순위임

SEELCT 계좌번호, 입금자, 입금액
FROM 임금_목록
WHERE 구분  ‘A’
AND 계좌번호 = ‘115’;

구분 컬럼 : 분포도 나쁨
계좌번호 컬럼 : 분포도 좋음 (해당 컬럼에 중복값이 적다는 의미임)

분포도가 좋은 컬럼을 앞에 위치시키는 것
– 점 조건들 사이의 우선순위임.
– 또는 선분 조건들 사이의 우선순위임.

ㅁ 해당 테이블을 엑세스하는 다른 유형의 SQL을 고려한다면,
분포도가 좋은 컬럼을 인덱스의 가장 앞에 위치시켜야 성능에 유리함..

ㅁ 보충 및 심화 학습

ㅁ 정렬 제거를 위한 인덱스

점 조건 + … + 점 조건 + Order By 절의 1번째 컬럼 + … + Order By 절의 n번째 컬럼 + … + 선분조건

Q. 다음 아래 SQL 에서 최적의 SQL은?

SEECT EMPLOYEE_ID
FROM EMPLOYEES
WHERE DEPARTMENT_ID  =’10’
AND SALARY > 200;

(1) DEPARTMEM_ID+SALARY
(2) SALARY_DEPARTMENT_ID
(3) SALARY
($) DEPARTMENT_ID

답 : (1)

Q. 결합 컬럼 인덱스와 단일 컬럼 인덱스의 유연성은 어떨까요?

A. 단일 컬럼 인덱스를 생성한다면 인덱스는 하나의 컬럼으로 생성되므로
해당 컬럼이 WHERE 절에 조건으로 사용된다면
해당 인덱스를 이용하게 되면 WHER 조건에 맞지 않는다면 해당 인덱스를 이용하지 않게 된다.

이처럼 단일 컬럼 인덱스는 유연성이 나쁘지만
결합 컬럼 인덱스를 만든다면 여러 가지 상황이 발생할 수 있다.

인덱스의 첫 번째 컬럼이 WHERE 절에 본재하지 않아도 해당 인덱스를 최적으로 이용할 수도 있다.
이처럼 결합 컬럼 인덱스를 이용한다면 인덱스의 유연성은 높아진다.

ㅁ 퀴즈

1. 결합 컬럼 인덱스 선정 시 가장 중요하지 않은 것은?

(1) 컬럼의 분포도
(2) 랜덤 엑세스
(3) 조건들에 사용된 연산자
(4) 정렬 제거

답 : 1번
(“결합 컬럼 인덱스에서의 분포도”는 해당 SQL의 성능과 무관하다.
결합 컬럼 인덱스의 선정 순서는 점 조건과 선분 조건의 위치, 랜덤 엑세스, 정렬 제거, “단일 컬럼 “순으로 고려한다.)

03:47 2017-01-05 목

 

SecureBoot가 제대로 구성되지 않았습니다.

SecureBoot가 제대로 구성되지 않았습니다.

 

Windows 8.1 – 업데이트 후 SecureBoot가 제대로 구성되지 않았다는 메시지가 표시되는 경우

이슈 해결을 위한 여러가지 방법이 있을 수 있습니다. 여기 두가지 접근법이 있습니다:
 
솔루션 1
 
Microsoft에서 이 이슈에 대한 KB 팁을 제공했습니다. 아래 링크에서 확인하십시오:
 
Update removes the “Windows 8.1 SecureBoot isn’t configured correctly” watermark in Windows 8.1 and …
(http://support.microsoft.com/kb/2902864)
 
솔루션 2
 1.시스템을 완전히 종료하십시오. – (shift + 종료)
2.시스템을 다시 시작하고 BIOS로 이동하십시오(F1). ※BIOS 로 접근하는 키는 컴퓨터마다 다릅니다.
3. Security(보안) > SecureBoot 로 이동하여 값을 enable(활성)으로 설정하십시오.
Note: 이렇게 하면 CSM이 해제되고 장치가 UEFI에서만 시작됩니다. 이는 SecureBoot가 작동하는데 필요합니다.

 

솔루션 3
 
커뮤니티 회원들이 다음 방법으로 성공했다고 말합니다:
 1. windows 버튼을 눌러 “startup(시작)”을 찾으십시오.
2. Change advanced startup options (고급 시작 옵션 변경)을 클릭하십시오.
3. “Advanced startup(고급 시작)”에서 Restart now (지금 다시 시작)을 클릭하십시오.
4. Troubleshoot (문제해결)을 클릭하십시오.
5. Advanced options (고급 옵션)을 클릭하십시오.
6. UEFI firmware settings (UEFI 펌웨어 설정)을 클릭하십시오.

이제 bios/uefi 구성 페이지가 보입니다:
 1. “security(보안)”으로 이동하고 “reset to setup mode (설정 모드로 재설정)”를 선택하십시오.
2. “exit(종료)”로 이동하고 “exit saving changes (변경사항 저장하고 종료)”을 선택하십시오.

windows로 돌아와서, 1 – 6 단계를 모두 반복하십시오. bios 화면에서:
 1.”security(보안)”으로 다시 이동하고 이번에는 “restore factory keys (공장 키 복원)”를 선택하십시오.
2. “exit(종료)”로 이동하고 “exit saving changes (변경사항 저장하고 종료)”를 선택하십시오.

권순용의 실전 SQL Tuning 3강

01:48 2017-01-04 수

권순용의 실전 SQL Tuning 3강

– 단일 컬럼 인덱스가 많으면 랜덤/?
– 유연성이 강한 결합 컬럼 인덱스를 생성해야 한다.

1. 인덱스의 개념

2. 랜덤 엑세스

– 인덱스의 구조
– 랜덤 엑세스란?
– 랜덤 엑세스의 영향은?

ㅁ 인덱스
데이터 베이스의 인덱스는 사전의 인덱스와 동일하다.
사전의 인덱스가 단어의 조회를 위해 존재하듯이
데이터베이스의 인덱스 또한 테이블에 저장되어 있는 데이터를 보다 빠르게
엑세스하기 위해 필요하다.

ㅁ 랜덤 엑세스
랜덤 액세스는 한 번 액세스시 한 번의 I/O를 발생시키게 된다.
이는 단일 블록 I/O 를 수행하기 때문이며 이와 같은 현상은 인덱스를
엑세스한 후 테이블을 엑세스하는 경우에 발생한다.

ㅁ 추출 랜덤 엑세스
select 절의 컬럼 값을 추출하기 위해 인덱스 엑세스 후
테이블을 엑세스하는 과정에서 발생하는 랜덤 엑세스이다.

ㅁ 확인 랜덤 엑세스
Where 절의 컬럼이 인덱스에 존재하지 않아
Where 절의 컬럼을 확인하기 위해 테이블을 엑세스하는 경우 발생하는 랜덤 엑세스이다.

1. 인덱스의 개념
ㅁ 인덱스의 장단점

장점 : 조회 속도 향상
단점 : 장점 외에는 거의 단점 밖에 없다. DML 성능 저하(Insert, Update, delete), 세그먼트 이므로 별도의 저장공간 차지 (디스크 공간 낭비)
          잘못된 인덱스 지정은 공간 낭비 + 조회 성능 저하

ㅁ B* 트리 인덱스 ]비 스타 트리 인덱스]

루트 블록 : 가장 위에 위치. 인덱스의 루트. 루트를 통해서만 모든 인덱스 엑세스 가능. 인덱스의 삽입/변경은 루트를 통해 수행됨.
                분기 값과 블록 주소 (DBA, Data Block Address)를 가지게 됨
브랜치 블록 : 중간에 위치. 루트 블록와 리프 블록을 연결함. 분기 값과 블록 주소 (DBA, Data Block Address)를 가지게 됨
리프 블록 : 가장 아래에 위치. 인덱스 키 값과 ROWID로 구성됨. (인덱스 키값 == 컬럼의 값,  ROWID == 데이터의 주소)
 – 더블 링크드리스트 : 리프 블록을 연결하는 포인터. 리프 블록끼리는 더블 링크드리스트로 통신하므로, 인덱스 범위(Range) 스캔 등에 이용하게 됨

ㅁ ROWID란?
데이터를 찾아가는 주소.
각 데이터는 서로 다른 ROWID 가짐 (유니크)

인덱스를 이용한다는 의미 == 인덱스를 엑세스하여 ROWID를 획득하고, 그것으로 테이블을 엑세스한다.

구성요소 : 오브젝트 번호(6자리, 32bit), 파일번호(3자리, 10bit), 블록번호(6자리, 22bit), 로우 번호(3자리, 16bit)
위 4개의 요소로 ROWID가 구성된다. (그러므로 유니크)
ex) AAAAAC AAB AAAAAX AAD

ㅁ 인덱스의 사용
인덱스를 사용하면 안되는 SQL도 매우 많으므로 주의 (엄청난 성능저하 발생)
SQL Tuning != 인덱스 사용 (동치가 아니다.)

– 적은 데이터 결과를 엑세스 하는 경우 반드시 인덱스 이용
– 많은 데이터 결과를 엑세스 하는 경우 FULL SCAN을 이용

ㅁ 인덱스 선정 절차
1. 테이블 아키텍처 선정 : 일반 테이블, 파티션 테이블 및 IOT(Index Organized table) 선정
2. 엑세스 Path 검토 : 해당 테이블을 엑세스하는 SQL 수집
3. 결합 컬럼 인덱스 고려 : 단일 컬럼 인덱스가 아닌 결합 컬럼 인덱스 고려
4. 인덱스 선정 : 엑세스 Path를 기준으로 여러 컬럼으로 구성된 결합 인덱스 선정
5. 선정된 인덱스 검증 : 인덱스에 대한 확인 및 테스트

2. 랜덤 엑세스
– 개념, 미발생/발생, 종류, 감소

ㅁ 랜덤엑세스의 개념

(1) 랜덤엑세스는 인덱스 스캔 후 테이블 엑세스하는 순간 랜덤 엑세스 발생
(2) 두 테이블 사이에 데이터 연결 단계에서 중첩 루프 조인을 사용할 경우 발생

Full Scan은 다중블록 I/O를 수행하지만,
인덱스는 랜덤 엑세스, 즉 단일블록 I/O를 수행하므로 많은 데이터를 엑세스하는 경우 FullScan이 더 빠르다.
데이터가 n건 연속으로 존재해도 인덱스는 ROWID로 찾아가기 때문에 그렇다.

– 인덱스 스캔 자체는 랜덤 엑세스를 발생시키지 않음.
– 인덱스 스캔 후 테이블 엑세스에서 랜덤 엑세스 발생.

ㅁ 랜덤엑세스 미발생
SELECT * FROM ~만 있고 WHERE가 없다면 Full Scan이므로 랜덤 엑세스 미발생.

ㅁ 랜덤엑세스 발생
WHERE 문에 특정 컬럼 조건을 넣었고, 특정 컬럼에 대한 인덱스가 존재할 경우.
단일 블록 I/O를 발생시키는 엑세스를 랜덤 엑세스라고 한다.

ㅁ 랜덤 엑세스 종류
(1) 추출 랜덤 엑세스 : 테이블 엑세스하는 과정에서 발생하는 랜덤 엑세스
SELECT col1, col2 FROM tab1 WHERE col3=’AAA’, col4=’BBB’
– col3+col4 인덱스를 사용시 : col1, col2때문에 인덱스 엑세스 후 테이블(tab1) 엑세스함. 이때 발생되는게 바로 추출 랜덤 엑세스.
– col3+col4+col1+col2 인덱스 생성시 추출 랜덤 엑세스 제거됨

(2) 확인 랜덤 엑세스 : WHERE 절의 컬럼이 인덱스에 존재하지 않아서 테이블을 엑세스하는 과정에서 발생
SELECT col3 FROM tab1 WHERE col3 = ‘AAA’ AND col4 = ‘BBB’ AND col5 like ‘AA%’
조건을 만족하지 않을 경우 랜덤엑세스 수행 결과를 버림 (버리는 과정이 동반되므로 다른 랜덤 엑세스 비해 더 많은 성능저하 발생될 수 있다.)
– col3+col5를 이용한다면 col4 를 확인하기 위해 테이블 엑세스를 함
– col4 확인 결과 조건에 안 맞으면 버리게 됨
– 예제에서는 col3+col4+col5 인덱스를 생성한다면 모두 존재하므로 확인 랜덤 엑세스가 모두 제거됨

(3) 정렬 랜덤 엑세스
SELECT a.col3 FROM tab1 WHERE col = ‘AAA’ and col4  = ‘bbb’ order by col5;

– Order By 절의 컬럼값을 확인하기 위해 인덱스 엑세스 후 테이블을 엑세스하는 과정에서 발생
– 추출랜덤 엑세스 처럼, 랜덤 엑세스 건수와 추출되는 데이터 건수가 동일함.
(오직 확인 랜덤 엑세스만이, 엑세스 건수에 비해 추출되는 데이터가 적을 수 있음)

– col3+col4 인덱스 이용시 col5 컬럼이 인덱스에 없으므로 col5 확인을 위해 랜덤 엑세스 발생 (정렬 랜덤 엑세스)
– 해당  SQL에 col3+col4+col5 인덱스 이용시 정렬 랜덤 엑세스 제거됨

ㅁ 랜덤 엑세스 감소 방법

(1) 클러스터 팩터 최적화 : 엑세스하고자 하는 데이터 모아서 저장 (랜덤 엑세스 발생 감소)
ex: 카드회사 솔루션이라면 카드번호 순으로 데이터를 쌓아두면 연속값이 존재해서 랜덤 엑세스 감소할 수 있음

(2)올바른 인덱스 선정 : 확인 랜덤, 추출 랜덤, 정렬 랜덤 엑세스의 감소

주로 (2)가 많이 사용되는 방법임
특히 확인랜덤 엑세스를 줄이는게 성능에 큰 도움이 됨.

ㅁ 랜덤 엑세스와 인덱스 스캔과의 관계
– 인덱스 스캔 자체는 랜덤 엑세스 발생시키지 않음 (인덱스 스캔으로 SQL 종료시 랜덤 엑세스 미발생)
– 스캔 후 테이블 엑세스할 때 랜덤 엑세스 발생됨

많은 데이터 결과를 추출하는 경우 : Full Scan이 유리

ㅁ 보충 및 심화학습
SEELCT col1, col2, col3, col4, col5
FROM test
WHERE dt BETWEEN ‘20080701’ AND ‘20080730’;

– dt는 인덱스에 존재해도, col1, col2, col3, col4, col5 컬럼이 인덱스에 존재하지 않을 경우 랜덤 엑세스 발생
– 테이블 전체가 2개월의 데이터만 존재하고 대용량 테이블일 경우
  위 쿼리는 전체의 50%를 조회하고 있음(1개월치를 조회). 풀스캔이 더 빠른 상황

employees 테이블에 emp_idx1 이름으로 SALARY 컬럼 인덱스를 생성해보세요.
CREATE INDEX EMP_IDX1 ON EMPLOYEES(SALARY);

CREATE INDEX 인덱스이름 ON 테이블명(컬럼명 [desc|asc]); => 비 스타트리 인덱스가 만들어진다.

ㅁ SQL의 실행 계획에서 랜덤 엑세스를 의미하는 부분은 다음 중 어디일까요?
(1) SELECT STATEMENT
(2)   TABLE ACESS BY INDEX ROWID | EMPLOYEES
(3)      INDEX RANGE SACN | EMPLOYEE_IDX4

답: (2)

해설 :
SET AUTOT TRACEONLY EXP select * from 테이블명
하면 실행계획을 볼 수 있다.
인덱스를 엑세스한 후 인덱스로부터 로우 아이디를 획득하여 테이블을 엑세스하는 단계를, 랜덤 엑세스라고 한다.

ㅁ 인덱스를 이용해야 하는 SQL 과 이용하지 말아야 하는 SQL의 기준은 무엇일까요?
엑세스하는 데이터의 양에 의해 좌우된다. 해당 테이블의 많은 데이터를 엑세스한다면 인덱스를 이용해서는 안된다.
왜냐하면 인덱스를 엑세스한 후 테이블을 엑세스하는 랜덤 엑세스가 발생하게 되며
랜덤 엑세스의 양이 많을수록 엄청난 성능 저하를 발생시키기 때문이다.

ㅁ마무리 정리
1. 인덱스의 구조는 인덱스 컬럼의 값과 ROWID로 구성된다.
2. ROWID는 인덱스에서 테이블의 데이터를 찾아가는 주소의 역할을 한다.
3. 랜덤 엑세스는 인덱스 엑세스 후 테이블을 엑세스 하는 경우 주로 발생하게 된다.
4. 종류에는 확인 랜덤 엑세스, 추출 랜덤 엑세스, 정렬 랜덤 엑세스가 있다.
* 확인 랜덤 엑세스는 엑세스 건수보다 추출 건수가 적을 수 있음 == 버리는 로직 발생.
5. 랜덤 엑세스는 성능 저하의 주범이며, 랜덤 엑세스를 최소화하기 위해서는 인덱스 선정이 매우 중요한다.

퀴즈
1. 데이터베이스에서 지원하는 인덱스 중 B*Tree 구조를 지원하지 않는 인덱스는?

(1) B*Tree 인덱스
(2) Function base 인덱스
(3) Bitmap 인덱스
(4) Reverse Key  인덱스

답: 3
B*Tree 구조를 사용하는 Index는 B*Tree 인덱스, Function Base 인덱스, Reverse Key  인덱스가 존재.
Bitmap 인덱스는 B*Tree 인덱스와 유사하지만, 비트맵을 이용하게 된다.

2. 인덱스의 단점이 아닌 것은?
(1) DML 성능저하
(2) 잘못된 인덱스는 저장공간 낭비
(3) 잘못된 인덱스는 성능 저하 발생
(4) 디스크 속도 저하 발생

답 : 4
참고로 장점은, 잘 만든 인덱스는 조회 성능 향상.

3. 랜덤 엑세스 중에 가장 성능 저하를 만힝 발생시키는 랜덤 엑세스는?
-> 확인 랜덤 엑세스.
(버리는 과정이 동반될 수 있기 때문임).

02:56 2017-01-04 수

Version 1.5.0_22 of the JVM is not suitable for this product. Version: 1.6 or greater is required.

Version 1.5.0_22 of the JVM is not suitable for this product. Version: 1.6 or greater is required.

 

이클립스에서 위와 같은 메시지가 뜰 때.

 

[원인]

(1) 해당 버전의 자바가 깔려있지 않은 경우

(2) 여러 버전의 자바가 깔려있는 경우 (1.4, 1.5, 1.6, 1.7 등이 깔려있는 경우)

 

[해결]

eclipse.ini 파일을 열어서,

 

Dosgi.requiredJavaVersion=1.6 를

Dosgi.requiredJavaVersion=1.4 로 수정한다.

 

[해결2]

-vmargs 위 부분에

 
-vm
C:\Java\jdk1.6.0_45\bin\javaw.exe
 
를 기입한다. (실제 javaw.exe가 위치한 곳이어야 한다.)

현재창 닫기

현재창 닫기

function DoWindowClose() {
 window.open(‘about:blank’, ‘_self’).close();
}

혹은

function DoWindowClose() {
 window.open(‘about:blank’, ‘_self’);

 window.close();
}

——————–

2017년 10월 12일 21:45 수정

try {
   window.open(“about:blank”, “_self”).close();
  } catch (e) {
   window.close();
  }

Tomcat8 css 파일 인식되지 않을 때 web.xml

Tomcat8 css 파일 인식되지 않을 때 web.xml

아래와 같이 수정하면 된다.

<!– The mapping for the default servlet –>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>

<!– The mappings for the JSP servlet –>
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>

권순용의 실전 SQL Tuning 2강

권순용의 실전 SQL Tuning 2강

00:28 2016-12-28 수

2강

DML (Data Manipulation Language)
SQL 에 포함되며 데이터베이스에 존재하는 데이터를 변경하는 언어이다.
DML은 INSERT, UPDATE, DELETE 만 존재하게 된다.

DCL (Data Control Language)

DCL 또한 SQL의 하나이며 권한을 부여하고 제거하는 역할을 수행하는 언어이다.
REVOKE와 GRANT 명령어만이 존재한다.

DDL (Data Definition Language)

데이터베이스에 존재하는 오브젝트에 대해 변경을 수행하는 SQL이며 ALTER 또는 CREATE 등을 이용하게 된다.

QUERY
테이블에 저장되어 있는 데이터를 추출하는 SQL 문이며 SELECT를 이용하게 된다.

TO_NUMBER(카드번호) = 1234 의 사용

– 해당 SQL 은 함수 기반 인덱스(Function Base Index)를 제외하면 인덱스를 이용할 수 없게 됨.

WHERE 절의 인덱스 컬럼은 절대 가공이 되어서는 안됨.
의도적으로 가공하여 인덱스를 이용하지 않게 할 수도 있음.

<INSERT>

대용량의 INSERT
– 직접(Direct) 로딩과 Nologging 으로 작업을 수행해야만 원하는 성능을 보장받을 수 있음.

Insert의 성능 저하 요인
– 인덱스가 많을수록 Insert가 느리다.
– DML 작업은 로그 기록이 발생. 로그 기록은 디스크 작업이므로 I/O증가됨.
– 내부적인 작업으로 인해 성능저하 (HWM Bump Up이라고 부름)
– UNDO 기록 : 롤백을 지원하기 위해 UNDO 저장. (UPDATE와 DELETE와 비교해서 적은 양이긴 함)
– INSERT 작업 자체 : 디스크 작업이므로 I/O증가됨.

1. INSERT INFO 테이블명 (컬럼명1, 2, …, n)
VALUES (값1, 2, …, n)

2. INSERT INFO 테이블명 (컬럼명 1, 2, …, n)
SELECT 컬럼명1, 2, …, n
FROM 테이블명
WHERE 조건절
기타;

(Nologging 와 직ㅇ접 로딩(Direct Loading) 은 2번, 인서트-셀렉트 SQL 만 가능)
(1번 INSERT-VALUES는 컨벤셔널 로딩만 된다. 다이렉트 로딩 불가.)

<UPDATE>

UPDATE는 최적화 방법이 따로 없으므로
INSERT 를 이용하여 최적화를 수행하는 경우가 있음.

UPDATE의 성능저하 요인
– 로그 기록 : 디스크 작업이므로 I/O발생
– 인덱스 변경 : 인덱스 작업이 느림
– UNDO 기록 : 롤백 지원을 위한 UNDO 저장. 디스크 작업 = I/O 발생
– Update 작업 자체 : 디스크 작업이므로 I/O발생

UPDATE 테이블명 SET 컬럼=값 WHERE 조건;

<DELETE>

UPDATE는 최적화 방법이 따로 없으므로
INSERT 를 이용하여 최적화를 수행하는 경우가 있음. (아니, DELETE를 어떻게 INSERT로 치환하지?)

DELETE의 성능저하 요인

– 로그 기록 : 디스크 작업이므로 I/O발생. UPDATE나 INSERT에 비해 많이 느림 (모든 컬럼에 대한 값 저장되기 때문)
– 인덱스 변경 : 인덱스 작업이 느림
– UNDO 기록 : 롤백 지원을 위한 UNDO 저장. 디스크 작업 = I/O 발생
– Update 작업 자체 : 디스크 작업이므로 I/O발생

*딜리트는 비포 이미지를 저장하는 작업의 양이 커서 매우 느리다.

DELETE FROM 테이블명 WHERE 조건;

Q. QUERY와 DML 중 어느 SQL이 시스템에 더 많은 성능저하를 발생시킬까?

같은 양의 데이터를 엑세스한다면 일반적으로 DML이다.
DML은 QUERY에 더하여 저장, 변경, 삭제 수행의 작업이 추가된다.
이와 같은 작업은 디스크 I/O를 발생시키므로 성능 저하를 더 발생시킨다.

<DDL (변경)>

컬럼 ADD
컬럼 DROP
컬럼 MODIFY

테이블 TRUNCATE
테이블 DROP

<DCL (데이터 제어어)>
GRANT(권한 할당), REVOKE(권한 제거)

성능과는 관계 없으나, 장애와 관련이 있다.
(권한이 없으면 장애 발생)

시스템 권한 : 데이터베이스에 대한 권한 + 테이블 생성 권한.
오브젝트 권한 : 테이블 내 데이터에 대한 권한. (삽입, 갱신, 삭제 권한)
오브젝트 : 객체. ex) 테이블, 인덱스, 함수, 프로시저.

INSERT를 직접 로딩하기 (직접 로딩Direct Loading 수행)

(1) ALTER TABLE TEST NOLOGGING;
(2) INSERT /*+APPEND*/ INTO TEST
  SELECT ~ ;
(3) ALTER TABLE TEST LOGGING;

—–

(2)의 어펜드 힌트가 직접 로딩을 유도하는 힌트다.
(1)로 로깅을 없애고,
대용량 인서트 작업을 마친 후 (3)으로 다시 로깅이 쓰여지도록 복구하면 된다.

여기서, APPEND 힌트 대신 PARALLEL 힌트를 써도 된다.
페러렐 힌트는 여러 개의 프로세스를 기동시키고, 여러 개의 프로세스가 각각 직접 로딩을 수행한다.

PARALLEL Processing 을 사용하려면
PARALLEL DML을 Enable 시켜야 한다.

(1) ALTER SESSON ENABLE PARALLEL DML;
(2) ALTER TABLE TEST NOLOGGING;
(3) INSERT /*+PARALLEL(A,4)*/ INTO TEST A
     SELECT …;
(4) ALTER TABLE TEST LOGGING;

결국 대용량 INSERT가 빠르려면 SELECT가 빨라야 한다.
SELECT가 빠르려면 인덱스를 생성하거나, PARALLEL 힌트를 사용하면 된다.
주의할 점은 PARALLEL 은 자원을 한번에 많이 사용할 가능성이 있다.

Q. 인덱스 컬럼에 함수가 적용되면 일반적으로 인덱스를 이용할 수는 없다.
이럴 때 어떤 인덱스를 이용해야 하는가?

A. Function base 인덱스

Q. VALUES 절을 이용하여 데이터를 삽입하는 경우 해당 컬럼에 ”를 삽입하면
어떤 데이터가 삽입되는가?

A. null 값

01:53 2016-12-28 수

권순용의 실전 SQL Tuning 1강 정리

권순용의 실전 SQL Tuning 1강 정리

01:03 2016-12-27 화

SQL :
데이터베이스에 저장하고 있는 테이블 등의
오브젝트에 대해 관리할 수 있는
언어를 의미한다.

SQL을 통해 데이터를 추출할 수도 있고
테이블을 생성하거나 제거하는 것도 가능하다.
DBMS에서 필요한 모든 작업은 SQL을 통해서 이루어지게 된다.

DBMS:
DBMS는 데이터베이스의 관리 시스템을 말한다.
데이터베이스의 관리 시스템은 정합성 보장, 백업과 복구, 질의 처리 및
보안 등의 데이터베이스를 관리하기 위한 요소를 제공하는 것을 의미한다.

SanDiskSecureAccessV2_win

SanDiskSecureAccessV2_win

샌디스크 USB 인식을 위한 파일입니다. 자동인식이 잘되는 PC는 설치할 필요 없고, 안되는 PC일 경우에만 깔면 됩니다.