ORA-00972: identifier is too long

ORA-00972: 식별자가 너무 깁니다



문제

Oracle 데이터베이스에서 이름이 30자보다 긴 열이나 테이블 같은 개체를 사용하려고 하면 다음 오류가 발생할 수 있습니다.

Oracle database error 972: ORA-00972: identifier is too long(Oracle 데이터베이스 오류 972: ORA-00972: 식별자가 너무 깁니다)

환경

  • Tableau Desktop
  • Oracle

해결 방법

Oracle 개체 이름이 30자 미만인지 확인하십시오.

원인

ORA-00972 오류는 Tableau Desktop이 아니라 Oracle 데이터베이스에서 발생합니다. 이 오류 메시지는 Oracle 데이터베이스 내의 개체가 30자를 초과한다는 것을 나타냅니다. 


블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,


동적 폼 엘리먼트 생성 및 ajax 를 이용한 전송


[동적으로 FORM 생성]


/* 화면 refresh없이 계속 submit해야하는 경우 form이 중복으로 document에 추가되기 때문에 reset하는 과정이 필요함. */

var $form = $("#myForm");
 if($form.length < 1) {
  $form = $("<form/>").attr({id:"myForm", method:'POST'});
  $(document.body).append($form);
 }
 $form.empty();

 

/* 정보 세팅 */

$("<input></input>").attr({type:"hidden", name:"aaaa", value:$.trim('aaaa')}).appendTo($form);

$("<input></input>").attr({type:"hidden", name:"bbbb", value:$.trim('bbbb')}).appendTo($form);





[Ajax 를 이용한 폼 전송]


/* ajax로 submit*/

$.ajax({

   url : '/testPjt/myPjt/test.do',

   data : $form.serialize(),

   dataType : 'json',

   success : function(json, textStatus, jqXHR){

     if(!json.result){
         alert('결과가 없습니다.');
     }else{
         alert('결과가 있습니다.');
     }

   }

});
 

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

사용중인 리눅스 종류 및 버전 확인 방법


1 방법 1: /etc/*-release

명령어
grep . /etc/*-release
cat /etc/*-release | uniq
실행예시 (Ubuntu 14.04.3)
root@zetawiki:~# grep . /etc/*-release
/etc/lsb-release:DISTRIB_ID=Ubuntu
/etc/lsb-release:DISTRIB_RELEASE=14.04
/etc/lsb-release:DISTRIB_CODENAME=trusty
/etc/lsb-release:DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"
/etc/os-release:NAME="Ubuntu"
/etc/os-release:VERSION="14.04.3 LTS, Trusty Tahr"
/etc/os-release:ID=ubuntu
/etc/os-release:ID_LIKE=debian
/etc/os-release:PRETTY_NAME="Ubuntu 14.04.3 LTS"
/etc/os-release:VERSION_ID="14.04"
/etc/os-release:HOME_URL="http://www.ubuntu.com/"
/etc/os-release:SUPPORT_URL="http://help.ubuntu.com/"
/etc/os-release:BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
실행예시 (CentOS 6.5)
[root@zetawiki ~]# grep . /etc/*-release
/etc/centos-release:CentOS release 6.5 (Final)
/etc/lsb-release:LSB_VERSION=base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
/etc/redhat-release:CentOS release 6.5 (Final)
/etc/system-release:CentOS release 6.5 (Final)
실행예시 (Fedora 11 Leonidas)
[root@zetawiki ~]# cat /etc/*-release | uniq
Fedora release 11 (Leonidas)
실행예시 (Oracle Enterprise Linux Server 5.5)
[root@zetawiki ~]# cat /etc/*-release | uniq
Enterprise Linux Enterprise Linux Server release 5.5 (Carthage)
Red Hat Enterprise Linux Server release 5.5 (Tikanga)
실행예시 (SUSE Linux Enterprise Server 11)
zetawiki:~ # cat /etc/*-release | uniq
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 1
LSB_VERSION="core-2.0-noarch:core-3.2-noarch:core-4.0-noarch:core-2.0-x86_64:core-3.2-x86_64:core-4.0-x86_64"




2 방법 2: /etc/issue*

명령어
grep . /etc/issue*
  • 배포판의 버전을 가장 쉽게 확인할 수 있는 방법이다.
  • 보안 등의 이유로 다른 내용으로 바뀌어 있는 경우도 있다.
실행예시 (Ubuntu 14.04.3)
root@zetawiki:~# grep . /etc/issue*
/etc/issue:Ubuntu 14.04.3 LTS \n \l
/etc/issue.net:Ubuntu 14.04.3 LTS
실행예시 (CentOS 6.5)
[root@zetawiki ~]# grep . /etc/issue*
/etc/issue:CentOS release 6.5 (Final)
/etc/issue:Kernel \r on an \m
/etc/issue.net:CentOS release 6.5 (Final)
/etc/issue.net:Kernel \r on an \m
실행예시 (Fedora 11)
[root@zetawiki ~]# cat /etc/issue
Fedora release 11 (Leonidas)
Kernel \r on an \m (\l)
실행예시 (Oracle Enterprise Linux 5.5)
[root@zetawiki ~]# cat /etc/issue
Enterprise Linux Enterprise Linux Server release 5.5 (Carthage)
Kernel \r on an \m
실행예시 (SUSE Linux Enterprise Server 11)
zetawiki:~ # cat /etc/issue

Welcome to SUSE Linux Enterprise Server 11 SP1  (x86_64) - Kernel \r (\l).

3 방법 3: rpm (레드햇계열)

rpm -qa *-release
실행예시 (CentOS 6.2)
[root@zetawiki ~]# rpm -qa *-release
centos-release-6-2.el6.centos.7.x86_64
실행예시 (Fedora 11 Leonidas)
[root@zetawiki ~]# rpm -qa *-release
fedora-release-11-1.noarch
실행예시 (Oracle Enterprise Linux Server 5.5)
[root@zetawiki ~]# rpm -qa *-release
enterprise-release-5-0.0.22
실행예시 (SUSE Linux Enterprise Server 11)
zetawiki:~ # rpm -qa *-release
sles-release-11.1-1.152
lsb-release-2.0-1.2.18



[제타위키내용 퍼왔습니다]

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

랜섬웨어 예방 설정방법

 

 

최근에 랜섬웨어가 유럽 및 아시아 등의 각국에서 활개치며 전 세계를 공포로 몰아


넣고 있습니다. 워너크라이(WANNACRY)란 이름으로 알려진 랜섬웨어는 윈도우 파일공유에


사용되는 SMB 원격코드의 약점을 파고 들어서 인터넷 접속만으로도 컴퓨터를 감염시키는


악성 바이러스의 일좀입니다. 이에 오늘 랜섬웨어 예방 방법에 대해서 포스팅 해보겠습니다.

 


우선 랜섬웨어 예방을 위해서 제어판에서 프로그램>Windows 기능 켜기/끄기로 이동합니다.

 


그럼 Windows 기능 창이 나타납니다. SMB 10./CIFS 파일 공유 지원을 체크 해제하신후 확인 단추를 누릅니다.

 


PC 재부팅을 물어보는 창이 나오면, 다시 시작 안함 을 선택합니다.

 

 

다시 제어판에서 시스템 및 보안>Windows방화벽> 고급설정 으로 이동을 합니다.

 


고급보안이 포함된 Windows 방화벽창에서, 인바운드 규칙  선택한후 새규칙..을 선택합니다.

 

새 인바운드 규칙 마법사 창이 뜨게 됩니다. 포트(O)를 선택하신후 다음 버튼을 선택합니다.

 

프로토콜 및 포트 탭으로 들어가시면 TCP(T)를 체크한 후 특정 로컬 포트(S)에 137-138,445 를 입력합니다.


이후 다음을 클릭합니다.

 

 

 

작업탭에서 연결 차단(K) 체크후 다음 버튼을 선택,프로필 탭에서 도메인,개인,공용 모두 체크하신후 다음

 

버튼을 클릭하십니다.

 


 

 

이름탭에 이름(N)을 입력한후 마침 버튼을 선택합니다. 이름은 임으로 아무렇게나 입력하셔도 상관은 없습니다.

 

다만 본인이 알아보기 쉽게끔 이름을 넣어주시는게 나을듯 싶습니다.

 

설정을 다 마치고 나면 랜섬웨어 예방으로해서 새로운 인바운드 규칙이 생성됩니다.

 

이미지 보시면서 차분히 해나가시면 힘드시지는 않을듯 싶습니다.

 

이상으로 랜섬웨어 예방에 대해서 포스팅 해봤습니다. 도움이 조금이나마 되셨으면 합니다.^^



출처: http://girim35822.tistory.com/?page=3 [원할머니봤쌈]

출처: http://girim35822.tistory.com/?page=3 [원할머니봤쌈]

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

윈도우10 정품인증 및 제품 키 입력 방법 쉽게 설명


오늘은 윈도우10 정품인증 및 제품키 입력 방법을 포스팅 할려고합니다.


윈도우10 정품 라이센스를 구매하시고 제품키를 인증하는 방법과 자기가


사용하고 있는 컴퓨터가 윈도우10 정품인증을 받은 것인지 확인하는 방법


이오니, 혹시라도 착오가 없으시길 바랍니다.

 

 


먼저 윈도우키 또는 시작버튼 1번을 클릭하시면 됩니다. 이후에 2번 설정버튼을


클릭하시면 바로 아래와 같은 창이 열립니다.


창안에 정품인증 이라고 쓰시면 아래쪽에 Windows가 정품 인증되었는지 확인


이라고 뜹니다. 정품인증에서 엔터를 치셔도 되고, Windows가 정품 인증되었는지 확인


부분을 클릭하셔도 됩니다.

 

 


만약 자신의 컴퓨터가 윈도우10 정품인증이 된 제품이라면 아래 이미지와 같이


Windows가 Microsoft 계정에 연결된 디지털 라이센스를 사용하여 정품 인증되었습니다.


이런 문구가 나오게 됩니다.

 

만약에 정품인증이 안된상태에서 정품인증을 하고 싶다면, 제품 키 변경 을 클릭하시면


됩니다.

 

  

 

 


정상적으로 윈도우10 정품 제품키를 입력하셨다면 확인 버튼을 눌러주시면 자동으로 

정품인증 처리가 됩니다.


다만 제품 키가 틀린경우에는


입력한 제품 키가 작동하지 않습니다. 제품 키를 확인하고 다시 시도하거나 다른 제품 키


를 사용하세요


라는 문구와 한께 오류 코드가 나오게 됩니다.

 

 

윈도우10 라이센스를 구매하신분들이라면 그렇게 크게 어려운점은 없을듯 싶습니다.




블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

 

국제유가 실시간 확인 방법

 

 

 

국제유가 실시간 확인방법을 포스팅해볼려고합니다.


아무래도 전세계적으로 국제유가 변동에는 많이 사람들이 신경을 곤두세우고 지켜보기


마련인것 같습니다. 그래서 국제유가 실시간 조회하는방법 중 가장 간단한 방법으로


포스팅해보겠습니다.

 

 

우선 네이버에 국제유가 실시간을 검색해보시거나 혹은 국제유가 실시간 포월드를

 

 

검색해보시면 됩니다

 

 


 

그리고 국제유가 실시간 포월드에 들어가셔서 상단에 보시면 브랜트유 라는 메뉴가


있습니다. 그곳을 클릭하시면 브랜트유 선물지수를 확인하실수 있습니다.

 

그리고 우측에 있는 채팅창을 이용하시면 접속해 있으신분들에게 도움을 요청하실수도 있습니다.

 

 

 

 

 

 

바로 WTI 선물 지수 차트를 확인하실수 있습니다. 여러 국제유가 실시간 사이트들이


있지만, 포월드만한곳이 없는듯 싶어서 여기 포스팅해봅니다.


참고하시면 도움이 되실듯 싶습니다



블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

 

윈도우10 업데이트 끄기 빠른해결법

 

 

 

윈도우10 업데이트 끄기 빠른해결방법에 대해서 포스팅해볼께요.
언제나 업데이트가 좋은것만은 아닌것 모두들 알고 계실겁니다.
중요한 작업중이거나 혹은 중요한 대화중일때 꼭 윈도우 업데이트를
묻는 물음이 많이 짜증나실수도 있거든요. 저또한 그렇고요.
그래서 윈도우10 업데이트 끄기 빠른해결방법에 대해서 알아보겠습니다.

 

 

 

 

우선 윈도우키를 누른 상태에서 R 키를 눌러주시면 됩니다

 

그럼 아래와 같은 실행화면이 나옵니다.

 

 

 

실행화면에 services.msc 이렇게 적으시고 확인을 누르십니다.

 

 

  

 

 

 

그럼 위와 같은 서비스 화면이 열립니다.

 

여기에서 아래쪽으로 쭉 내려오시면 Windows Update 라는 메뉴가 나오십니다.

 

이 Windows Update 라는 메뉴에서 마우스 오른쪽을 누르시면 위 그림에서처럼 메뉴가

나옵니다. 이중 속성을 클릭하시면 됩니다.

 

 

그러면 Windows Update 속성이 나오는데요, 여기에서 시작유형중에 사용 안함을 선택하시면 끝입니다.

 

 

 

그리고 확인버튼을 눌러주시면 윈도우10 업데이트 끄기 가 바로 해결 되신것니다.

많이 어렵지는 않으실겁니다. 한번 해보시고요, 도움이 되셨으면 합니다.^^

 



출처: http://girim35822.tistory.com/ [원할머니봤쌈]

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

php로 웹상의 파일 읽기(원격 리소스 읽기)

이 글은 http://www.php-mysql-tutorial.com/wikis/php-tutorial/reading-a-remote-file-using-php.aspx에 있는 글을 번역한 것입니다


php로 웹상(원격)에 있는 파일을 읽는 방법으로는 아래의 4가지 방법을 사용해서 구현이 가능하다

  1. fopen() 함수 사용
  2. file_get_contents() 함수 사용
  3. cURL 라이브러리 사용
  4. php의 소켓통신 함수들을 사용

1번과 2번 방법을 사용하기 위해서는 fopen wrapper 가 사용 가능해야한다. 이 fopen wrapper 파라미터는 php.ini에 정의되어 있으나, ini_set()을 사용해서 실행시간에 바꿀수는 없다.

이 두 방법을 쓸수 있는지의 여부는 아래 코드로 확인할수 있다

<?php
if (ini_get('allow_url_fopen') == '1') {
   // fopen() 이나 file_get_contents() 사용
} else {
   // curl 이나 함수 직접 작성
}

1. fopen() 함수 사용

fopen()을 사용하는 법은 local 파일을 읽는것 만큼 쉽다. 유일하게 다른점은 fopen()함수 내에 파일명 대신 URL을 적는다는 것이다. 아래 예제를 보자.

<?php
// 원격 파일을 사용하기 전에 성공적으로 open 되었는지 확인
if ($fp = fopen('http://www.google.com/', 'r')) {
   $content = '';
   // 전부 읽을때까지 계속 읽음
   while ($line = fread($fp, 1024)) {
      $content .= $line;
   }

   // content 사용
   // ...
} else {
   // 파일 open시 에러 발생
}

위 코드중 while 반복문의 fread() 함수는 한 루프 안에서 1024 바이트의 데이터를 읽기 위해 사용된다. 이 코드는 아래와 같이 쓸수도 있다.

<?php
// 원격 파일을 사용하기 전에 성공적으로 open 되었는지 확인
if ($fp = fopen('http://www.google.com/', 'r')) {
   $content = '';
   // 전부 읽을때까지 계속 읽음
   while ($line = fgets($fp, 1024)) {
      $content .= $line;
   }

   // content 사용
   // ...
} else {
   // 파일 open시 에러 발생
}

fread() 대신에 최대 1024바이트의 라인 한줄을 읽는 fgets()를 사용했다. 첫번째 코드가 두번째보다 좀더 선호되는 방식이다.

원격에 있는 파일이 300줄 짜리 50KB 파일이라고 생각해보면, 첫번째 코드는 루프가 15번 정도 돌테지만 두번째 코드는 300번의 루프가 실행되야 한다

만약 함수호출 비용과 시간을 고려중이라면 첫번째 방법이 확실히 나은 방법이다

2. file_get_contents() 함수 사용

가장 간단해서 내가 가장 선호하는 방법이다. 단지 파라메터를 url로 주고 함수를 호출하기만 하면 된다. 한가지 기억해야할 점은 리턴받은 값을 사용하기 전에 error가 리턴 됬는지 확인 먼저 해야한다는 것.

<?php
$content = file_get_contents('http://www.google.com/');
if ($content !== false) {
   // content 사용
} else {
   // error 발생
}

3. cURL 라이브러리 사용

위의 두 방법과는 다르게 CURL을 쓰는 방법은 딱 부러지게 설명하기 힘들다. 이 라이브러리는 (http뿐만 아니라) 다른 프로토콜 간의 연결과 통신하는 데에 매우 유용하기 쓰이긴 하지만 배우는데 시간을 좀 들여야 한다. 또 다른 문제는 모든 web host들(서버)이 이 php 라이브러리를 설치하지는 않았다는것. 따라서 이 방법을 쓰기 전에 해당 라이브러리가 설치되어 있는지 먼저 확인 해야한다

다음은 이 CURL라이브러리를 활용해서 원격 파일을 여는 간단한 예제다

<?php
// curl이 설치 되었는지 확인
if (function_exists('curl_init')) {
   // curl 리소스를 초기화
   $ch = curl_init(); 

   // url을 설정
   curl_setopt($ch, CURLOPT_URL, 'http://www.google.com'); 

   // 헤더는 제외하고 content 만 받음
   curl_setopt($ch, CURLOPT_HEADER, 0); 

   // 응답 값을 브라우저에 표시하지 말고 값을 리턴
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

   // 브라우저처럼 보이기 위해 user agent 사용
   curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0'); 

   $content = curl_exec($ch); 

   // 리소스 해제를 위해 세션 연결 닫음
   curl_close($ch);
} else {
   // curl 라이브러리가 설치 되지 않음. 다른 방법 알아볼 것
}

몇가지 경우에는 file_get_contents()나 fopen() 을 쓰는것보다 CURL이 더 빠르다. 이것은 CURL이 기본적으로 압축 프로토콜을 사용하기 때문이다 (예를들면 gzip).

크고 작은 많은 사이트에서 bandwidth를 줄이기 위해 그들 페이지에서 gzip 압축을 사용한다. 이 사이트도 gzip 압축을 사용했고, bandwidth가 절반으로 줄었다. 만약 기다리기 싫어하는 타입이라면 CURL이 가장 적당할것이다

4. php의 소켓통신 함수들을 사용

최악의 경우에는 서버의 fopen wrapper 옵션도 꺼져있고, CURL 라이브러리도 인스톨 되지 않았을수도 있다. 이 상황에서는 우리가 쓸 함수를 직접 만들어야 한다.

우리의 함수는 대상 파일의 url 파라미터 한개를 갖는 getRemoteFile() 함수로 명명했다. 대략적인 뼈대는 아래와 같다

<?php
function getRemoteFile($url)
{
   // 1. host name과 url path 값을 획득

   // 2. 원격 서버에 접속

   // 3. 파일을 얻기위해 필요한 헤더들을 전송

   // 4. 원격 서버로부터 응답 받음

   // 5. header 부분 걷어냄

   // 6. 파일 content 리턴
}

url에서 host name과 url path 를 추출하기위해서는 parse_url() 함수를 이용하면 된다. 이 함수에 넘겨진 url은 다음 항목들로 분리될 것이다

  • scheme
  • host
  • port
  • user
  • pass
  • path
  • query
  • fragment

예를들면, http://www.php-mysql-tutorial.com/somepage.php 은 아래와 같이 리턴된다

<?php
Array
(
    [scheme] => http
    [host] => www.php-mysql-tutorial.com
    [path] => /somepage.php
)

만약 http://myusername:mypassword@www.php-mysql-tutorial.com/somepage.php?q=whatsthis#ouch 라면 아래와 같이 리턴된다

<?php
Array
(
    [scheme] => http
    [host] => www.php-mysql-tutorial.com
    [user] => myusername
    [pass] => mypassword
    [path] => /somepage.php
    [query] => q=whatsthis
    [fragment] => ouch
)

우리가 관심있는것은 host, port, path, query 값 뿐이다

원격 서버와의 connection을 생성하기는 위해서 fsockopen()을 사용한다. 이 함수는 [hostname, port number, error number 포인터, error message 포인터, 시간제한] 5개의 인자를 가지고 있다

<?php
function getRemoteFile($url)
{
   // host name 과 url path 값을 획득
   $parsedUrl = parse_url($url);
   $host = $parsedUrl['host'];
   if (isset($parsedUrl['path'])) {
      $path = $parsedUrl['path'];
   } else {
      // url이 http://www.mysite.com 같은 형식이라면
      $path = '/';
   }

   if (isset($parsedUrl['query'])) {
      $path .= '?' . $parsedUrl['query'];
   } 

   if (isset($parsedUrl['port'])) {
      $port = $parsedUrl['port'];
   } else {
      // 대부분의 사이트들은 80포트를 사용
      $port = '80';
   }

   $timeout = 10;
   $response = '';
   // 원격 서버에 접속한다
   $fp = @fsockopen($host, $port, $errno, $errstr, $timeout );

   if( !$fp ) {
      echo "Cannot retrieve $url";
   } else {
      // 필요한 헤더들 전송
      fputs($fp, "GET $path HTTP/1.0\r\n" .
                 "Host: $host\r\n" .
                 "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n" .
                 "Accept: */*\r\n" .
                 "Accept-Language: en-us,en;q=0.5\r\n" .
                 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" .
                 "Keep-Alive: 300\r\n" .
                 "Connection: keep-alive\r\n" .
                 "Referer: http://$host\r\n\r\n");

      // 원격 서버로부터 response 받음
      while ( $line = fread( $fp, 4096 ) ) {
         $response .= $line;
      }

      fclose( $fp );

      // header 부분 걷어냄
      $pos      = strpos($response, "\r\n\r\n");
      $response = substr($response, $pos + 4);
   }

   // 파일의 content 리턴
   return $response;
}

위의 코드에서는 9줄의 헤더 정보를 보내지만 사실 처음 2줄만 필수사항이다. 따라서 이렇게만 보내도 된다

<?php
fputs($fp, "GET $path HTTP/1.0\r\n" . "Host: $host\r\n\r\n");

아마 대부분의 경우 잘 동작할테지만 항상 잘 동작하는것은 아니다. 열고자 하는 파일들은 원격 서버에 저장되어 있기때문에, 원격 서버가 request에 response 하는지 안하는지에 달려있다

몇몇 서버는 request 헤더에 referer 항목이 없다면 block 할것이고, 몇몇은 특정 user agent 만 받아들일 것이다. 또 어떤 것들은 cookie가 설정되어 있는 header만 받을 것이다

특정 원격 파일을 여는데에 어떤 헤더가 보내져야 하는지 알고 싶다면 파이어폭스와 live http headers plugin 툴을 사용해 보라. 작고 강한 툴이다



블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,


php 에서 MSSQL 연동하기 ( FreeTDS 이용)


URL : http://www.freeTDS.org

stable 버전을 다운받으면 된다.

구분하기 쉬우라고 다운받아서 /usr/local/src/APM 아래에 옮겨버렸다.

아 맞다 우선 설치환경부터

OS : CentOS 5.3
php : php-5.2.10
apache : httpd-2.2.11
SQL : MSSQL- ???

디비 버전을 모르겠다. 설치와는 완전 무관하기에 그냥 넘어간다.

다운받은 파일의 압축을 푼다.

cd /usr/local/src/APM/
tar xvzf freetds-stable.tgz

압축을 풀면 freetds-0.82 라는 폴더가 생긴다. 이동하자. 현재 버전이 0.82 인가 보다.

cd freetds-0.82

이제 설치하자

./configure --prefix=/usr/local/server/freetds --with-tdsver=8.0 --disable-odbc --disable-debug --enable-msdblib
make && make install

php를 재설치해야 한다.

./configure --prefix=/usr/local/server/php --with-apxs2=/usr/local/server/apache/bin/apxs --with-mysql=/usr/local/server/mysql --with-config-file-path=/usr/local/server/apache/conf --disable-debug --enable-safe-mode --enable-track-vars --enable-sockets --with-charset=utf8 --with-xml --with-language=korean --enable-calendar --enable-sysvsem=yes --enable-sysvshm=yes --enable-ftp --enable-magic-quotes --enable-gd-native-ttf --enable-url-includes --enable-inline-optimization --enable-bcmath --with-jpeg --with-png --with-zlib --with-jpeg-dir=/usr --with-png-dir=/usr/lib --with-freetype-dir=/usr --with-libxml-dir=/usr --enable-exif --with-gd --with-ttf --with-gettext --enable-sigchild --enable-mbstring --with-mssql=/usr/local/server/freetds

기존 옵션에 하나만 더 추가했다.

make && make install

아파치를 재실행한다.

/etc/init.d/httpd restart

php 정보를 확인하면 다음과 같은 mssql 이 추가된 것을 볼 수 있다.


한글이 깨지는 것을 막기 위해 php.ini 설정을 다음과 같이 수정해준다.

cd /usr/local/server/apache/conf/
vim php.ini

인코딩은 각자의 웹 환경에 맞춰서 입맛대로 바꿔주면 되겠다.

아래와 같은 코드로 테스트를 해보자.

[msdbtest.php]

<html>
<head>
    <title>mssql 접속 테스트</title>
</head>
<body>
일본어 데이터들어 분류번호와 분류명을 가져오는걸 테스트해본다.
<br><br>
<?php
$DB_IP        ="***.***.***.***:1433"; //기본 포트port 1433
$DB_USERID    ="*******";
$DB_USERPW    ="**********";
$DB_NAME      ="******";

$conn = mssql_connect($DB_IP,$DB_USERID,$DB_USERPW);
$result = mssql_select_db($DB_NAME, $conn);
$result = mssql_query("SELECT term_name, term_remark FROM terms1 WHERE LEN(term_remark)<=5");

?>
<table border=1>
<tr>
<td>번호</td>
<td>분류항목</td>
<td>분류어</td>
</tr>
<?
$i=1;
while ($row = mssql_fetch_row($result)) {
    $resultData="<tr><td>".$i++."</td><td>".$row[1]."</td><td>".$row[0]."</td></tr>";
    echo $resultData;
}

mssql_close($conn); 

?>
</table>
</body>
</html>

현재 구축되어있는 mssql 에 접속해서 읽어왔기 때문에 디비 생성이나 데이터 입력하는 부분은 빠져있다.

이 포스트를 참조하시는 분들은 본인의 환경에 맞춰서 php 코드를 수정하면 결과를 확인할 수 있을것이다.

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

MySQL에서 커버링 인덱스로 쿼리 성능을 높여보자!!


커버링 인덱스(Covering Index)라는 내용인데, 대용량 데이터 처리 시 적절하게 커버링 인덱스를 활용하여 쿼리를 작성하면 성능을 상당 부분 높일 수 있습니다.

커버링 인덱스란?

커버링 인덱스란 원하는 데이터를 인덱스에서만 추출할 수 있는 인덱스를 의미합니다. B-Tree 스캔만으로 원하는 데이터를 가져올 수 있으며, 칼럼을 읽기 위해 굳이 데이터 블록을 보지 않아도 됩니다.

인덱스는 행 전체 크기보다 훨씬 작으며, 인덱스 값에 따라 정렬이 되기 때문에 Sequential Read 접근할 수 있기 때문에, 커버링 인덱스를 사용하면 결과적으로 쿼리 성능을 비약적으로 올릴 수 있습니다.

백문이 불여일견! 아래 테스트를 보시죠.

테이블 생성

먼저 다음과 같이 테이블을 생성합니다.

create table usertest (
 userno int(11) not null auto_increment,
 userid varchar(20) not null default '',
 nickname varchar(20) not null default '',
 .. 중략 ..
 chgdate varchar(15) not null default '',
 primary key (userno),
 key chgdate (chgdate)
) engine=innodb;

약 1,000만 건 데이터를 무작위로 넣고 몇가지 테스트를 해봅니다.

커버링 인덱스(SELECT)

select chgdate , userno
from usertest
limit 100000, 100
************* 1. row *************
           id: 1
  select_type: SIMPLE
        table: usertest
         type: index
possible_keys: NULL
          key: CHGDATE
      key_len: 47
          ref: NULL
         rows: 9228802
        Extra: Using index
1 row in set (0.00 sec)

쿼리 실행 계획의 Extra 필드에 “Using Index” 결과를 볼 수 있는데, 이는 인덱스만으로 원하는 데이터 추출을 하였음을 알 수 있습니다.

이처럼 데이터 추출을 인덱스에서만 수행하는 것을 커버링 인덱스라고 합니다. 아시겠죠? ^^

그렇다면 일반 쿼리와 성능 테스트를 해볼까요?

커버링 인덱스(WHERE)

1) 일반 쿼리

select *
from usertest
where chgdate like '2010%'
limit 100000, 100

쿼리 수행 속도는 30.37초이며, 쿼리 실행 계획은 다음과 같습니다.

************* 1. row *************
           id: 1
  select_type: SIMPLE
        table: usertest
         type: range
possible_keys: CHGDATE
          key: CHGDATE
      key_len: 47
          ref: NULL
         rows: 4352950
        Extra: Using where

Extra 항목에서 “Using where” 내용은, Range 검색 이후 데이터는 직접 데이터 필드에 접근하여 추출한 것으로 보면 됩니다.

2) 커버링 인덱스 쿼리

select a.*
from (
      select userno
      from usertest
      where chgdate like '2012%'
      limit 100000, 100
) b join usertest a on b.userno = a.userno

쿼리 수행 시간은 0.16초이며 실행 계획은 다음과 같습니다.

************* 1. row *************
           id: 1
  select_type: PRIMARY
        table:
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100
        Extra:
************* 2. row *************
           id: 1
  select_type: PRIMARY
        table: a
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: b.userno
         rows: 1
        Extra:
************* 3. row *************
           id: 2
  select_type: DERIVED
        table: usertest
         type: range
possible_keys: CHGDATE
          key: CHGDATE
      key_len: 47
          ref: NULL
         rows: 4352950
        Extra: Using where; Using index

Extra 에서 “Using Index”를 확인할 수 있습니다.

그렇다면 30초 넘게 수행되는 쿼리가 0.16초로 단축됐습니다. 왜 이렇게 큰 차이가 발생했을까요?

첫 번째 쿼리는 Where에서 부분 처리된 결과 셋을 Limit 구문에서 일정 범위를 추출하고, 추출된 값을 데이터 블록에 접근하여 원하는 필드를 가져오기 때문에 수행 속도가 느립니다.

두 번째 쿼리에서도 동일하게 Where에서 부분 처리된 결과 셋이 Limit 구문에서 일정 범위 추출되나, 정작 필요한 값은 테이블의 Primary Key인 userno 값입니다. InnoDB에서 모든 인덱스 Value에는 Primary Key를 값으로 가지기 때문에, 결과적으로 인덱스 접근만으로 원하는 데이터를 가져올 수 있게 됩니다. 최종적으로 조회할 데이터 추출을 위해서 데이터 블록에 접근하는 건 수는 서브 쿼리 안에 있는 결과 갯수, 즉 100건이기 때문에 첫 번째 쿼리 대비 월등하게 좋은 성능이 나온 것입니다.

커버링 인덱스(ORDER BY)

커버링 인덱스를 잘 사용하면 Full Scan 또한 방지할 수 있습니다. 대부분 RDBMS에는 테이블에 대한 통계 정보가 있고, 통계 정보를 활용해서 쿼리 실행을 최적화 합니다.

다음 재미있는 테스트 결과를 보여드리겠습니다. 전체 테이블에서 chgdate 역순으로 400000번째 데이터부터 10 건만 가져오는 쿼리입니다.

1) 일반 쿼리

select *
from usertest
order by chgdate
limit 400000, 100
************* 1. row *************
           id: 1
  select_type: SIMPLE
        table: usertest
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 9228802
        Extra: Using filesort
1 row in set (0.00 sec)

분명 인덱스가 있음에도, Full Scan 및 File Sorting이 발생합니다. 인덱스를 태웠을 때 인덱스 블록을 읽어들이면서 발생하는 비용보다 단순 Full Scan이 더 빠르다고 통계 정보로부터 판단했기 때문이죠. 인덱스도 데이터라는 것은 항상 기억하고 있어야 합니다^^

결과 시간은 책정 불가입니다. (안끝나요~!)

2) 커버링 인덱스 쿼리

위 결과와 다르게 커버링 인덱스는 조금 더 재미있는 결과를 보여줍니다.

select a.*
from (
      select userno
      from usertest
      order by chgdate
      limit 400000, 100
) b join usertest a on b.userno = a.userno
************* 1. row *************
           id: 1
  select_type: PRIMARY
        table:
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100
        Extra:
************* 2. row *************
           id: 1
  select_type: PRIMARY
        table: a
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: b.userno
         rows: 1
        Extra:
************* 3. row *************
           id: 2
  select_type: DERIVED
        table: usertest
         type: index
possible_keys: NULL
          key: CHGDATE
      key_len: 47
          ref: NULL
         rows: 400100
        Extra: Using index

File Sorting이 발생하지 않고 커버링 인덱스가 사용되었으며, 실행 시간 또한 0.24초로 빠르게 나왔습니다.^^

Conclusion

커버링 인덱스는 InnoDB와 같이 인덱스와 데이터 모두 메모리에 올라와 있는 경우에 유용하게 쓰일 수 있습니다. 물론 커버링 인덱스가 좋기는 하지만, 커버링 인덱스를 사용하기 위해 사용하지 않는 인덱스를 주구장창 만드는 것은 최대한 피해야 하겠죠^^

잊지마세요. 인덱스도 데이터라는 사실을..

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,