한국의 컴퓨터 환경이라는게 한글과 영어의 다름을 해결하다보니 코드셋의 문제라는 것을 항상안고왔다고 봅니다.


 덕분에 프로그램을 개발하는 과정이나 운영하는 과정에서 이래저래 상당히 많은 불편함을 안고 운영을 하죠. 제가 일하는 사이트에서도 이런 상황이 왕왕발생합니다. 저희 사이트는 HPUX 환경에 euc-kr 콘솔환경을 운영합니다. 웃기게도!!! 데이터는 utf-8 을 쓰죠 ㅎㅎ

 어쨋든 운영을 일단 시작한뒤라보니 이런 자잘한 문제때문에 환경을 잘 바꾸질 못하죠. 이럴때 쓰면 좋은 커맨드입니다. 아마도 hpux 가 아닌 다른 곳에도 비슷한 커맨드가 분명 있을 것 같네요.

db2 -nx "select utf8_col from tabname" 
                 | iconv -s -c -f utf8 -t kore5

저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

 unix 환경에서 perl 을 이용해서 파일내의 문자열 형태의 날짜 형태를 변경할때에는 아래와 같이 사용하면 됩니다.

201003310900%PU.LMIV003C%상품.업무%신계약%심사%장기인심사_처리(단체형)%0%1%49.13%0.006%48.426%%0.697%0.076%0%0.616%
201003310900%TD.AMDP0171%판매.마케팅%영업지원%정보큰바다%우편데이터고객업데이트%0%1%31.904%%0.203%%31.7%31.7%0%0%
201003310900%PU.LMIV003R%상품.업무%신계약%심사%장기인심사_조회(단체형)%0%3%31.876%0.002%30.214%%1.659%0.04%0%1.606%
...

 위와 같은 형태의 아스키 파일에서 앞부분의 timestamp 부분을 db2 가 제공하는 기본 timestamp 포맷인 
YYYY-MM-DD-HH.MM.SS.UUUUUU 형태로 변경해야지 데이터를 통으로 넣기가 수월합니다.

2010-03-31-09.00.00.000000%PU.LMIV003C%상품.업무%신계약%심사%장기인심사_처리(단체형)%0%1%49.13%0.006%48.426%%0.697%0.076%0%0.616%
2010-03-31-09.00.00.000000%TD.AMDP0171%판매.마케팅%영업지원%정보큰바다%우편데이터고객업데이트%0%1%31.904%%0.203%%31.7%31.7%0%0%
2010-03-31-09.00.00.000000%PU.LMIV003R%상품.업무%신계약%심사%장기인심사_조회(단체형)%0%3%31.876%0.002%30.214%%1.659%0.04%0%1.606%
...

이런 형태랄까요?

 보통은 이런 작업에는 sed 를 많이 사용하는 것 같습니다. (cut 을 이용해서도 구현이 가능하지만 cut 을 사용할 경우 파이프를 타고 데이터가 전달되면서 한글 부분에서 간간히 에러를 뱉는 현상이 발생하는 것 같습니다.)

 여튼 제가 찾아본 제일 간단한 방법은 perl 을 사용하는 것입니다.

perl -pi.bak -e 's/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([*]*)/$1-$2-$3-$4.$5.00/g' <filename>

 이런식이죠~
 
 만들어진 결과 파일은 

import from <filename> of del
                modified by codepage=970 usedefaults coldel%
                insert into <tabname>

 로 간단하게 입력이 가능합니다. (import 옵션에서도 timestampformat 을 지정할 수 있는데 왠지 잘 안되더군요.;;)
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글


맥북 쓴지도 이제 반년가까이 되가는데... 시간이 지날수록 윈도우를 더 많이 쓰게되더라는... -_-;

그렇다고 내가 얼리가 아니라던지 적응력이 떨어진다던지 하는건 아닌데...
우분투 나오기 전에도 데탑에 리눅스 깔고 영화보고 TV 보고... 그랬는데 쩝;;;

(해본분은 알겠지만 우분투 전에는 저거 하나하나가 넘사벽이었다.)
리눅스야 태생이 그런줄 알았으니 이것이 나의 길이구나 하면서 갔지만...

지나고 보니 그냥 남들이 많이쓰는게 제일 좋은 것같이 느껴진다.

이번에 부트캠프 3.1이 공개됐길래 올타꾸나 하구서 Windows 7 을 지원한느 이 녀석을 설치하다가 키보드 드라이버 관련해서 뭔가가 엉킨건지 키보드 먹통되고... 어찌어찌하면서 다시 설치하고 여차저차 하면서 다시 설정하는 과정을 격다가 이렇게 글을 적는다.

이제는 감히 말한다. Xcode 가지고 아이팟 어플 개발할거 아님 맥북사지마 -_-
keynote ? 걍 우분투깔고 OpenOffice 에 opengl 플러그인 설치해서 그거써 !!!!
이건 뭐 남들 다 쓰는 윈도우를 리눅스 쓰듯해야하니...

여튼 맥쓰사를 비롯해서 여기저기에서 찾아보면 맥북의 더러운 키보드 배열 (애플은 뭐든지 업계에 통용되는 표준을 무시 :) ) 덕분에 어려움을 격는 사람들이 많이 찾는 Input Remapper / KeyTweak / MKLC 라는 프로그램이 있다.

BUT..... 이 프로그램 만큼 좋은 녀석을 아직 찾지를 못했다.

리매핑 프로그램계의 iptime 같은 녀석이랄까 ??? 한국인 특유의 섬세함이 돋보이는 "이런 기능을 쓸까?" 싶을 정도로 잡스러운 기능과 기능키 동시입력을 지원하는 강력함!!!! 간단한 설정.

거기다가 개발자가 한국인. 메일때리면 당연히 피드백 받을 수 있다. -ㅅ-;;

거기에 무료.

다운로드는 http://www.safefolder.net 여기서...

내가 사용하는 설정파일도 함께 공개해 봄.
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

 제가 일하는 곳의 서버에는 붉은성(RedCastle)이라는 커널 보안툴을 필수적으로 설치하나 봅니다. 얼마전까지만 해도 이런 보안툴의 문제점에 대해서 아무런 생각이 없었는데, 이 녀석이 일으키는 문제들이 생각보다 큰 것 같습니다.

 db2 에는 db2pd 라는 번들된 모니터링 툴이있습니다. 이 녀석은 db2 프로세스를 뒤져서 메모리상의 정보를 얻어오는 녀석인데요.

qtdev1:[/usr/local/redcastle/logs]more rclog.01
1       33554947        16777986        1262013633      1262013633      kernel  42.8.162.100    Denied setuid to root on db2pd -
d QTDEVDB -locks wait.::setuid(23):18816:18815:root(0):qtdevins(114):MSA:7:System Admins(2):db2pd -d QTDEVDB -locks wait:db2pd -
d QTDEVDB -locks wait:UXR:0:Unknown(0):18816:root(0):root(0):Deny: [LoginUser=qtdevins(114)]
1       33554945        16777986        1262013633      1262013633      kernel  42.8.162.100    Unauthorized process creation by
 qtdevins.::setresuid(126):18815:18783:qtdevins(114):qtdevins(114):MSA:7:System Admins(2):wc -l:db2pd -d QTDEVDB -locks wait:UXR
:0:Unknown(0):18816:root(0):root(0):Deny: [LoginUser=qtdevins(114)]
....
....

 웃기게도 이녀석이 아무래도 db2pd 의 메모리 액세스를 막아버리는 것 같습니다. : ) - 뒷부분의 로그를 보면 더 process creation violation error 등등의 복잡 다양한 에러를 내 뱉습니다. -

 제가 듣기로는 이 녀석이 리눅스의 SELinux / IBM 티볼리 제품군등하고 비슷한 역할을 하는 국산 제품인 것으로 알고있는데.. (아닐지도 모릅니다만) 프로그램 자체의 완성도가 나쁘다라고 생각하기보다는 아무래도 테스트가 부족한 환경에서 개발된 탓인지 이런저런 문제를 일으킬 소지가 아무래도 많은 녀석인 것 같습니다.

 그렇다고 감사라고 나오면 설치했는지 확인하기때문에 설치는 해야하는 것 같고, 설치를 하면 언제 db2가 이 녀석 때문에 내려갈지 모를 불안감을 안고 가야하는...

 정책설정에서 아무래도 예외가 가능하긴 할 것 같은데 - 설마 보안툴인데 예외 처리가 없진 않을테고.. -_- - 단지 설치 운영의 업무가 명확히 구분된 나름 규모가 있는 곳에서는 지금처럼 운영중인 환경상에 저희도 모르는 채로 설치되서 잘되던 프로그램을 안되게 만들어 버리니... 그런게 문제인 것 같습니다.
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

 사실 이게 공개해도 되는 문서인지는 모르겠기 때문에... 일단은 직접 링크는 접어서 포스팅합니다. 제가 IBM 이라면 당연히 널리 보급시키겠습니다만 IBM이 아니니까 -ㅅ-;;; 제 짧은 생각으로는 IBM은 일단 학교에서 부터 영업을 시작해야 해야하지 않을까 생각합니다. 사람들의 인식이 그렇게 빨리 변하지는 않기 때문이죠.

더보기


 IBM DB2를 시작하는 분들에게 참고가 되었으면 싶은 마음에서 - 그리고 시장 점유율이나 인식이 조금이라도 좋아졌으면 싶은 마음에서 - 이렇게 올려둡니다.
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

 '형~ 파일 이름을 출력하고, 파일 첫줄을 찍고 싶은데... 쉘 스크립트로는 어떻게 해요?'

 글쎄... 어떤 문제이던지 해결 방법은 참 많을 수 있다라고 생각한다. 하지만, 문제를 내는 사람은 알게 모르게 본인이 생각한 방향대로 문제를 해결해 주기를 원하고, 그 방향으로 생각하도록 단서를 달아서 질문을 던지기 마련인 것 같다.

 나는 이 질문을 받으면서 생각했다. 

 그래 이건 파일 리스트를 얻어와서 for 문을 이용해서 아래처럼 수행시키면 되겠구나.

for FILENAME in `ll /target`
do
  echo $FILENAME
  head -n 1 $FILENAME
done


 알려주고 곰곰히 생각해보니 왜 굳이 이렇게 쉘 스크립트 작성해야하나 싶은거다. -_-

 분명히 이보다 훨씬 더 좋은 유닉스 최강의 프로그램!!! find 가 있는데 말이다.

find /target -exec echo {} \; -exec head -n 1 {} \;


 굳이 스크립트가 왜 필요하다고 생각했을까?? 싶을 정도로 너무나도 간단한 이 한가지 구문으로 결국 문제는 클리어~ 형상이 안부 묻고 일하러 ㄱㄳ

 이번일을 격으면서 생각한건데 어떤 질문이나 문제이던지 약간 틀어진 각도에서 문제는 다시 한번 재해석하는 과정을 거쳐야할 것 같다라는 생각을 해본다. 분명히 문제를 다른 각도에서 볼 수만 있다면 정공법을 이용하는 것보다 훨씬 더 편한 방법으로 문제를 해결할 수 있을 것 같다.

ps. 인생사 꼼수없는 문제는 없는 듯 하다. 히히히 : P

저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

보호글

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력해주세요.

db2 운영 환경에서 db2pd 정보 중 tcbstats 정보를 수집하기 위한 스크립트입니다.

#!/usr/bin/perl
use Sys::Hostname;
use Getopt::Std;
use Switch;
use POSIX;

$host = hostname;

$TARGETDBNAME = "dbname";
$TARGETUSER   = "username";
$TARGETPASS   = "password";

switch ($host) {
    case "agdb1"    {   $DBNAME =   "NPAGDB"    }
    case "qudb1"    {   $DBNAME =   "NPQTDB"    }
    case "pddb1"    {   $DBNAME =   "NPPDDB"    }
    case "batdrdb"  {   $DBNAME =   "SFMIDB"    }
    case "agdevdb"  {   $DBNAME =   "AGDEVDB"   }
    case "qtdevdb"  {   $DBNAME =   "QTDEVDB"   }
    else            {   $DBNAME =   "Unknown"   }
}

sub process {
    # target loading
    switch ($_[0]) {
        case "file" {
            $filename = $_[2];
            open(MYDATA, $filename) or die ("error occured!");
            @lines = <MYDATA>;
        }

        else {
            while(<STDIN>) {
                @lines = (@lines, $_)
            }
        }
    }

    # to split line with whitespace
    # my $date = POSIX::strftime("%Y-%m-%d-%H:%M:%S", localtime(time()));
    my $input_date = POSIX::strftime("%Y-%m-%d-%H.%M.%S", localtime(time()));
    if ($_[1] ne "del") {
        print "db2 -v \"connect to $TARGETDBNAME user $TARGETUSER using $TARGETPASS\"\n";
    }

    # to find TCB Table Stats part.
    $beg_idx_stats = 0;
    $end_idx_stats = $#lines;
    foreach $stats_line (@lines) {
        if ( $stats_line =~ /TCB Table Stats/ ) {
            $beg_idx_stats++;
            last;
        } else {
            $beg_idx_stats++;
        }
    }
    @tcbstats = @lines[$beg_idx_stats+1..$end_idx_stats];

    # to find TCB Table Infomation.
    $beg_idx_info = 0;
    $end_idx_info = $beg_idx_stats-3;
    foreach $info_line (@lines) {
        if ( $info_line =~ /TCB Table Information/ ) {
            $beg_idx_info++;
            last;
        } else {
            $beg_idx_info++;
        }
    }
    @tcbinfo = @lines[$beg_idx_info+1..$end_idx_info];

    # generate data insertion statements.
    $line_no = 0;
    for $tcbstats_line (@tcbstats) {
        @stats_record = split /\s+/, $tcbstats_line;

        if ($stats_record[1] !~ /^IBM/ && $stats_record[1] !~ /^SYS/ && $stats_record[1] !~ /^TEMP/ && $stats_record[1] !~ /^INTERNAL/ && $#stats_record >= 12) {
            $table_schema = "unknown";

            for $tcbinfo_line (@tcbinfo) {
                @info_record = split /\s+/, $tcbinfo_line;
                if ($info_record[6] !~ /^IBM/ && $info_record[6] !~ /^SYS/ && $info_record[6] !~ /^TEMP/ && $info_record[6] !~ /^INTERNAL/) {
                        if ($stats_record[0] eq $info_record[0] ) {
                            $table_schema = $info_record[7];
                        }
                }
            }

            # db2pd tctstats index information
            # Address     00
            # TableName   01
            # Scans       02
            # UDI         03
            # PgReorgs    04
            # NoChgUpdts  05
            # Reads       06
            # FscrUpdates 07
            # Inserts     08
            # Updates     09
            # Deletes     10
            # OvFlReads   11
            # OvFlCrtes   12

            if ($_[1] eq "del") {
                print "\"$DBNAME\",\"$input_date\",\"$table_schema\",\"$stats_record[1]\",$stats_record[2],$stats_record[6],$stats_record[8],$stats_record[9],$stats_record[10]\n";
            } else {
                print "db2 -v \"insert into adm.tcbstats values ('$DBNAME', '$input_date', '$table_schema', '$stats_record[1]', $stats_record[2], $stats_record[6], $stats_record[8], $stats_record[9], $stats_record[10] )\"\n";
            }
        }

        if ($_[1] ne "del") {
            if ($line_no != 0 && $line_no % 100 == 0) {
                print "db2 -v \"commit work\"\n"
            }
        }
        $line_no++;
    }

    if ($_[1] ne "del") {
        print "db2 -v \"commit work\"\n";
        print "db2 -v \"terminate\"\n";
    }
   
    close MYDATA;
}

sub help {
    print "# ------------------------------------------------------------------  \n";
    print "# This shell is generated by insert_tcbstats.pl                       \n";
    print "# If you have a question, plz contact to youngchang.park@samsung.com  \n";
    print "# ------------------------------------------------------------------  \n";
   
    print "Usage : insert_tcbstats.pl -t [del|sh] -f [filename]                     \n";
    print "        insert_tcbstats.pl -t [del|sh] -s [STDIN]                        \n";
    print "        insert_tcbstats.pl -h                                            \n";
    print "        insert_tcbstats.pl -v                                            \n";
}

sub version {
    print "insert_tcbstats.pl version : 2009 / 06 / 25               \n"
}

%opts = ();
getopts("shvf:t:", \%opts);

if (defined $opts{h}) {
    help();
    exit 0;
}

if (defined $opts{v}) {
    version();
    exit 0;
}

if (defined $opts{t}) {
    if (defined $opts{s}) {
        process("stdin", $opts{t});
        exit 0;
    } else {
        if (defined $opts{f}) {
            process("file", $opts{t}, $opts{f});
            exit 0;
        }
    }
}
help();


적당히 필요한대로 수정해서 쓰시길~

- 2009.07.08
실제로 쓰는 스크립트는 기능을 좀더 추가함~
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

 HP의 OpenMCM 이라는 툴을 아시는지 모르겠지만, 이 녀석이 사용하는 DB가 바로 알티베이스입니다. 이 녀석이 어떤 프로그램인고하니 트랜잭션의 성능 측정 및 분석을 위해서 해당 정보를 저장하는 프로그램이죠. 문제는 이 녀석이 다루는 트랜잭션이라는 녀석이 엄청나게 빈번하게 발생하다보니 데이터의 변경량이 엄청나다는게 문제죠.

 아마도 그래서 Altibase 의 메모리 기반 DB를 이용하는 듯합니다.

 어찌돼었건... 이 DB는 4 대의 버전까지는 dual 테이블을 기본으로 제공하지 않기 때문에 아래와 같은 간단한 작업을 하면 오라클에서 사용하듯 dual 이라는 테이블을 이용해서 간단한 쿼리나 테스트 쿼리를 작성할 수 있습니다.

create table dual (X char(1));
insert into dual values ('x');

크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글

db2 운영중 아래의 쿼리를 이용하면 현재 lock 이 풀리기를 대기하는 어플리케이션에 대한 정보를 얻을 수있습니다.

db2pd -d <dbname> -lock wait show detail       : trans_id 확인
db2pd -d <dbname> -lock tran show detail       : agent_id 확인
db2 get snapshot for application agentid <agentid>     : 해당 appl 정보 추출



이상의 3개의 커맨드를 입력하여 얻을 수도 있는 정보이지만, 아래의 쿼리를 이용하면 좀더 간단하게 원하는 결과값을 얻을 수 있습니다.

(물론 db2pd 를 이용해서 간단한 쉘이나 프로그램을 만드는 것이 더욱 좋은 방법이라고 생각합니다. 아래의 방법보다 더 자세한 결과를 얻을 수 있기 때문이죠. 물론 snapapp_info 뷰를 이용하면 좀더 데이터를 얻을 수 있기는 합니다.)

SELECT
 L.DB_NAME,
 L.AGENT_ID,
 L.APPL_NAME,
 L.LOCK_OBJECT_TYPE,
 A.APPL_NAME,
 A.APPL_STATUS,
 A.TPMON_CLIENT_USERID,
 A.TPMON_CLIENT_WKSTN,
 A.TPMON_CLIENT_APP,
 A.TPMON_ACC_STR,
 L.AGENT_ID_HOLDING_LK,
 L.LOCK_WAIT_START_TIME,
 L.LOCK_NAME,
 L.LOCK_MODE
FROM
 SYSIBMADM.LOCKWAITS L
INNER JOIN
 SYSIBMADM.SNAPAPPL_INFO A
ON
 L.AGENT_ID = A.AGENT_ID;
SELECT
 L.DB_NAME,
 L.AGENT_ID_HOLDING_LK,
 L.APPL_NAME,
 L.LOCK_OBJECT_TYPE,
 A.APPL_NAME,
 A.APPL_STATUS,
 A.TPMON_CLIENT_USERID,
 A.TPMON_CLIENT_WKSTN,
 A.TPMON_CLIENT_APP,
 A.TPMON_ACC_STR,
 L.AGENT_ID,
 L.LOCK_WAIT_START_TIME,
 L.LOCK_NAME,
 L.LOCK_MODE
FROM
 SYSIBMADM.LOCKWAITS L
INNER JOIN
 SYSIBMADM.SNAPAPPL_INFO A
ON
 L.AGENT_ID_HOLDING_LK = A.AGENT_ID;

결국 본인이 사용하기 쉬운 방법을 이용하는게 좋을 것 같습니다.

쉘을 이용한 프로그램은 다음에~... :-) 사실은 잘 못해서... ㄷㄷ
크리에이티브 커먼즈 라이선스
Creative Commons License

설정

트랙백

댓글