블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2008.08.06 14:22

[ Perl ] Perl 에서의 ORM , DBIx::Class에 대해서... #3 - Component

  이번에는 Component 에 대해서 알아보겠습니다. 일단 예제부터 보고 시작하죠.

  Mytest/Company.pm 을 열어봅니다.

package MyTest::Company;

use strict;
use warnings;

use base 'DBIx::Class';
use AutoStoreDateTime;

__PACKAGE__->load_components("PK::Auto", "+AutoStoreDateTime", "Core");
__PACKAGE__->table("company");
__PACKAGE__->add_columns(
  "company_id",
  { data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
  "name",
  { data_type => "VARCHAR", default_value => "", is_nullable => 0, size => 255 },
  "created_on",
  { data_type => "DATETIME", default_value => "", is_nullable => 0, size => 19 },
  "updated_on",
  { data_type => "DATETIME", default_value => "", is_nullable => 0, size => 19 },
);
__PACKAGE__->set_primary_key("company_id");


# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-08-05 16:39:27                      
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:DHRIea3OvvtGG+yhaBVTvQ                        


# You can replace this text with custom content, and it will be preserved on regeneration    
1;

 이 중에서 제가 살짝 추가한 부분이 있습니다.

use AutoStoreDateTime;
__PACKAGE__->load_components("PK::Auto", "+AutoStoreDateTime", "Core");

 바로 이부분에 PK::Auto 라는 component 도 불러오라고 지정했습니다. PK::Auto 는 온라인 게임에서 자동으로 PK 를 수행하는   Primary Key Auto Increment 라고 보시면 됩니다. 즉 이 Schema Class 에서는 company_id 가 Primary Key 이니까 자동으로 Auto Increment 해준다는 거죠. (물론 SQL 에서 Auto Increment 를 지정해주면 DBMS 자체적으로 이 행위를 수행하지만, auto increment 가 지정되지 않은 경우에는 PK::Auto가 알아서 해줍니다. 이것을 확인하기 위해서 직접 Company 테이블을 변경해보시길 바랍니다)

  그리고 AutoStoreDateTime 도 있습니다. 근데 이 앞에 +라고 붙었는데.. 이것은 Custom component 입니다. PK::Auto 같은 경우는 DBIx::Class::PK::Auto 라는 모듈을 불러오는 것인데, AutoStoreDateTime 은 DBIC 정식 모듈이 아닌... 여기서 만들어서 쓰겠다라는 것이죠.
use AutoStoreDateTime;

use strict;
use warnings;
use base 'DBIx::Class';

use DateTime;

sub insert {
    my $self = shift;
   
    $self->created_on( DateTime->now( time_zone => 'Asia/Seoul' ) )
                             if $self->result_source->has_column('created_on');
                      
    $self->next::method(@_);
}

sub update {
    my $self = shift;

    $self->updated_on( DateTime->now( time_zone => 'Asia/Seoul' ) )
                           if $self->result_source->has_column('updated_on');
    $self->next::method(@_);
}

1;

  이와 같은 컴포넌트 모듈을 만들었습니다. 이것을 AutoStoreDateTime.pm 이라고 저장하고 MyTest.pm 과 같은 디렉토리에 놓습니다.
  그럼 어떤 결과를 보이는 지 확인해 볼까요?
my $company = $schema->resultset('Company');

while(<DATA>) {
    chomp;
    $company->create({
        'name'    => $_,
    });
}

__DATA__
I company
N company
D company
E company
A company
Y company

  이렇게 Company.name 을 만들도록합니다. company_id 도 지정하지 않았고, created_on 도 지정하지 않았습니다. 등록날짜도 모르면 어떻게 하려고 이럴까요?
사용자 삽입 이미지
  하지만 이렇게 created_on 은 create 한 시점의 날짜/시간을 가지고 있습니다. company_id 도 물론 지정하지 않았는데 이렇게 생겼네요(SQL에서 auto increment 가 있으면 뭐 그게 그거입니다만).

 근데 사장 마인드를 가지신 saillinux 님께서 짝수 회사번호를 가진 회사는 전부 소문자로 표기하고 싶다는 얼토당토 않은 요구를 하고 있습니다. 어쩔 수 있나요. 까라면 까야지..

my $company = $schema->resultset('Company')->search({});

while(my $row = $company->next) {
    if ($row->company_id % 2 == 0) {
        $row->name(lcfirst $row->name);
        $row->update;
    }
}

  이렇게 하면 되겠죠?
사용자 삽입 이미지
  그러면 update 된 레코드만 updated_on 이 지정되게 되죠.  어때요? 참 쉽죠?

 이렇게 DBIC 의 Component 활용에 대해서 알아보았습니다. :-) 직접 Component 를 만들어서 보다 편하게 DB 를 주물러 보심은 어떠실런지요?

  다음에는 Relation 에 대해서 살짝 알아보겠습니다. 

* 참고
 - **** Project



신고
IT/Perl 2008.04.20 12:57

[ 뒷북 && 삽질 경험기 ] RedHat 계열의 Perl Bug

 작년 중순 쯤에  RedHat 계열의 리눅스에서 Perl Package Bug가 보고되었고, 이에 따른 패치도 즉시 나왔던 적이 있습니다. 당시에는 뉴비이고 지금도 뉴비이지만, 패키지 소스의 문제까지 내다볼 능력이 없었던 저에게 사나흘의 시간은 너무 아깝더군요. 직접 당해보니까 말이죠.

 회사의 서버에서는 CentOS 4 - Perl 5.8.8 을 사용하고 있었는데요.
 아래는 어떤 스크립트를 돌렸을 때의 시간을 리포트 한 결과입니다.

사용자 삽입 이미지

Perl Patch를 때리기 전

사용자 삽입 이미지

Perl Patch 를 때리고 난 후


 대략 13분 정도 걸리는 스크립트가 10시간이 넘게 걸렸다.. 이런 얘기가 됩니다.
 그 원인이 무엇이냐고 하면...  RedHat 계열의 Perl Package에서 생기는 버그의 내용은...
 use overload 한 Package(여기서는 Perl의 package)를 bless 할 때의 CPU부하가 엄청나게 걸려서,
전체적인 처리 시간이 증가된다는 것입니다.

 실제 루프 카운트 한번에 0.25~ 0.7초라는 경이적인 속도를 보여주더군요. 총 루프횟수는 거의 50000번
정도 였구요. 이 처리를 위해서 담아둔 소스 데이터의 양은 300MB정도 됩니다. 소스 데이터의 갯수는
30개 정도 되구요. 생성되는 파일 또한 30개 정도 됩니다.

 이 처리에서 사용된 것은 DateTime 이라는 모듈인데요. 어떤 날짜를 보고 그 날짜로부터 몇 일 사이의
내용에 대해 출력하는 내용도 포함되어 있었던 것입니다. 바로 DateTime 자체가 overload 한 package를
bless 하는 것에 해당하는 것이었죠.
  혹시나 코드가 바뀌면서 버그가 있었는 가 의심해서 차츰차츰 예전의 리비젼으로 바꿔가면서 돌려봤지만
어지간히 시간은 그대로더군요. 나흘이전의 코드에서도 마찬가지로 너무 느려서 강제종료 시켜버렸습니다.

 문제는 소스가 되는 데이터도 바뀐 것이었는데... 나흘전에 다른 사람이 만들고 있던 처리에서 제가 사용하는
소스 데이터를 건드리는 게 있었거든요. 이전의 코드에서 문제가 없었던 이유는 DateTime을 사용할
조건에 부합하지 않았다는 것이었죠. 소스 데이터가 바뀌니까... 50000번 루프의 대부분이 그 조건에 부합되고
그에 따라서 처리시간은 784 -> 37419 로 바뀌어졌습니다. 생각해보면 사흘전에는 1200초 정도였군요. 조건이 부합되는 게 몇 건 밖에 없었으니까요..

 그럼 자신의 머신이 이런 문제가 있느냐 없느냐를 어떻게 간단하게 확인하냐 하면...
 
  http://blog.yappo.jp/yappo/archives/000515.html

 여기에 그 검증 코드가 있습니다. 일단 일본어 임에 주의하시구요.
 CentOS와 FreeBSD에서 검증 코드를 움직여 보면.. 그 결과의 차이에 대해서 어느 저도 파악하실 수 있습니다.
 그리고 그 차이를 절감하신다면... 패치를 하시면 됩니다. 물론 Perl 을 애용하시고, Perl 을 주로 쓰시는 분께 한해서 말이죠.
 
  물론 작년의 이슈이므로 제가 삽질한 것은 분명합니다.
  교훈은... Code의 문제 뿐 아니라.. 그 위아래의 레이어에 대해서도 알아야 되겠다는 것이죠.
  그나저나 DateTime은 없어서는 안될 좋은 모듈입니다 :-)
신고
TOTAL 462,384 TODAY 11

티스토리 툴바