2014-12-22 2 views
0

sqlplus 데이터베이스에서 데이터를 가져 오는이 perl 스크립트가 있습니다 ...이 데이터베이스는 특정 직렬에 대한 상태 값이 변경 될 때마다 새 항목을 추가합니다 번호. 이제 모든 상태 변경시 항목을 선택하고 이전 상태, 새 상태 및 다른 필드가있는 CSV 파일을 준비해야합니다. db 테이블 샘플.sqlplus를 사용하는 perl 스크립트의 효율성을 높이는 방법

SERIALNUMBER   STATE    AT      OPERATORID SUBSCRIBERID TRANSACTIONID 
51223344558899  Available   20081008T10:15:47   vsuser 
51223344558857  Available   20081008T10:15:49   vsowner 
51223344558899  Used     20081008T10:20:25   vsuser 
51223344558860  Stolen    20081008T10:15:49   vsanyone 
51223344558857  Damaged    20081008T10:50:49   vsowner 
51223344558899  Damaged    20081008T10:50:25   vsuser 
51343253335355  Available   20081008T11:15:47   vsindian 

내 스크립트를 VoucherQuery1.sql에서

#! /usr/bin/perl 

#use warnings; 
use strict; 


#my $circle = 
#my $schema = 
my $basePath = "/scripts/Voucher-State-Change"; 

#my ($sec, $min, $hr, $day, $month, $years) = localtime(time); 
#$years_+=1900;$mont_+=1; 
#my $timestamp=sprintf("%d%02d%02d",$years,$mont,$moday); 


sub getDate { 
    my $daysago=shift; 
    $daysago=0 unless ($daysago); 
    #my @months=qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time-(86400*$daysago)); 
    # YYYYMMDD, e.g. 20060126 
    return sprintf("%d%02d%02d",$year+1900,$mon+1,$mday); 
    } 

my $filedate=getDate(1); 
#my $startdate="${filedate}T__:__:__"; 
my $startdate="20081008T__:__:__"; 
print "$startdate\n"; 


##### Generating output file--- 
my $outputFile = "${basePath}/VoucherStateChangeReport.$filedate.csv"; 
open (WFH, ">", "$outputFile") or die "Can't open output file $outputFile for writing: $!\n"; 
print WFH "VoucherSerialNumber,Date,Time,OldState,NewState,UserId\n"; 



##### Generating log file--- 
my $logfile = "${basePath}/VoucherStateChange.$filedate.log"; 
open (STDOUT, ">>", "$logfile") or die "Can't open logfile $logfile for writing: $!\n"; 
open (STDERR, ">>", "$logfile") or die "Can't open logfile $logfile for writing: $!\n"; 
print "$logfile\n"; 

##### Now login to sqlplus----- 
my $SQLPLUS='/opt/oracle/product/11g/db_1/bin/sqlplus -S system/[email protected]'; 
`$SQLPLUS \@${basePath}/VoucherQuery1.sql $startdate> ${basePath}/QueryResult1.txt`; 


open (FH1, "${basePath}/QueryResult1.txt"); 

while (my $serial = <FH1>) { 
    chomp ($serial); 
    my $count = `$SQLPLUS \@${basePath}/VoucherQuery2.sql $serial $startdate`; 
    chomp ($count); 
    $count =~ s/\s+//g; 
    #print "$count\n"; 
    next if $count == 1; 

    `$SQLPLUS \@${basePath}/VoucherQuery3.sql $serial $startdate> ${basePath}/QueryResult3.txt`; 

# print "select * from sample where SERIALNUMBER = $serial----\n"; 
    open (FH3, "${basePath}/QueryResult3.txt"); 


    my ($serial_number, $state, $at, $operator_id); 
    my $count1 = 0; 
    my $old_state; 
    while (my $data = <FH3>) { 
      chomp ($data); 
        #print $data."\n"; 
      my @data = split (/\s+/, $data); 
      my ($serial_number, $state, $at, $operator_id) = @data[0..3]; 
      #my $serial_number = $data[0]; 
      #my $state = $data[1]; 
      #my $at = $data[2]; 
      #my $operator_id = $data[3]; 


      $count1++; 
      if ($count1 == 1) { 
       $old_state = $data[1]; 
       next; 
       } 

      my ($date, $time) = split (/T/, $at); 
      $date =~ s/(\d{4})(\d{2})(\d{2})/$1-$2-$3/; 

      print WFH "$serial_number,$date,$time,$old_state,$state,$operator_id\n"; 
      $old_state = $data[1]; 
      } 
     } 
close(WFH); 

쿼리 : VoucherQuery2.sql에서

select distinct SERIALNUMBER from sample where AT like '&1'; 

쿼리 : VoucherQuery2.sql에서

select count(*) from sample where SERIALNUMBER = '&1' and AT like '&2'; 

쿼리

select * from sample where SERIALNUMBER = '&1' and AT like '&2'; 

내 샘플 출력 :

VoucherSerialNumber,Date,Time,OldState,NewState,UserId 
51223344558857,2008-10-08,10:50:49,Available,Damaged,vsowner 
51223344558899,2008-10-08,10:20:25,Available,Used,vsuser 
51223344558899,2008-10-08,10:50:25,Used,Damaged,vsuser 

스크립트가 꽤 잘 작동된다. 그러나 문제는 실제 db 테이블에 특정 날짜에 대한 수백만 개의 레코드가 있다는 것입니다. 따라서 성능 문제가 제기되고 있습니다 ... & 시간의 측면에서이 스크립트의 효율성을 어떻게 향상시킬 수 있는지 조언 해주십시오. 유일한 제한은 내가 이것을 위해 DBI 모듈을 사용할 수 없다는 것입니다 ... 또한 SQL 쿼리에서 오류가 발생하면 오류 메시지가 QueryResult? .txt 파일로 전송됩니다. 로그 파일에서 이러한 오류를 처리하고 받고 싶습니다. 이것이 어떻게 성취 될 수 있는가? 덕분에

+2

데이터베이스 내에서 처리 및 결과 생성을 수행하고 결과를 파일로 직접 덤프하여 Perl에서 결과 처리를 건너 뛰는 것이 가장 효율적으로 보입니다. 저장 프로 시저를 사용하십시오. – reinierpost

+0

답장을 보내 주셔서 감사합니다.하지만 나는 초보자 저장 프로 시저입니다. 그 사이에 처음 두 개의 쿼리를 "d. *, count (*)를 (SERIALNUMBER 파티션) 이상으로 선택하십시오.) 여기서 cnt> 1; " 그것 개선을 보여주는 ... – user2611539

답변

0

나는 당신이 당신의 쿼리를 조정할 필요가 있다고 생각한다. 좋은 시작점은 오라클 데이터베이스 인 경우 EXPLAIN PLAN을 사용하는 것입니다.